During a migration project with a customer, we ran into the problem where some of the clients wouldn’t be uninstalled correctly. When using the supported way of uninstalling the ConfigMgr 2012 client, the following error was shown in the ccmsetup.log file:

Installation failed with error code 1603
A Fallback Status Point has not been specified. Message with STATEID=’301′ will not be sent.
CcmSetup failed with error code 0x80070643

124_1

We tried rebooting the device that were failing, but as good of a troubleshooting tactic that might be for Windows systems, it didn’t work (who would’ve thought that anyway). When we interpreted the client.msi_uninstall.log file, that didn’t contain more than a few lines, we didn’t get that much more wiser. The only thing that we could get out of that log file was the following:

MainEngineThread is returning 1603

Well thank you very much for giving us that fatal error message all over again!

A quick search on Google pointed us in the direction where it could be related to a faulty WMI repository. We ran a few queries and for the most part it gave us an unexpected error. So we decided to try to rebuild the WMI repository on one of the devices that were experiencing problems when trying to uninstall the ConfigMgr client. At this point I realized that I’ve been wanting to write a PowerShell script that would assist in rebuilding the WMI repository, but I didn’t yet have had any time. After some digging around on the internet and a few rows of code, I ended up with the following code:

<#
.SYNOPSIS
    Maintenance script for Windows Management Instrumentation
.DESCRIPTION
    This script can perform management tasks such as rebuilding the WMI repository. On Windows 6.x and above, the default behaviour of this script
    is to salvage the WMI repository first. If that doesn't give any successful results, you'll have the option add the Reset parameter
.PARAMETER Task
    Specify a maintenance task to perform

    Valid tasks:
    - Rebuild
.PARAMETER Reset
    Enables you to reset the WMI repository instead of the default option that is to salvage (only for Windows 6.x and above)
.EXAMPLE     
     .\Start-WMIMaintenance -Task Rebuild -Verbose     
     Rebuilds the WMI repository on the local system, showing verbose output 
.NOTES     
     Script name: Start-WMIMaintenance.ps1     
     Version:     1.0     
     Author:      Nickolaj Andersen     
     Contact:     @NickolajA     
     DateCreated: 2015-02-11 
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [parameter(Mandatory=$true)]
    [ValidateSet("Rebuild")]
    [string]$Task,
    [parameter(Mandatory=$false)]
    [switch]$Reset
)
Begin {
    # Stop Windows Management Instrumentation dependent services
    $RunningServicesArrayList = New-Object -TypeName System.Collections.ArrayList
    foreach ($Service in (Get-Service -Name Winmgmt).DependentServices) {
        if ($Service.Status -like "Running") {
            $RunningServicesArrayList.Add($Service.Name) | Out-Null
            Write-Verbose -Message "Stopping Winmgmt dependent service '$($Service.Name)'"
            Stop-Service -Name $Service.Name -Force -ErrorAction Stop
        }
    }
    try {
    # Stop Windows Management Instrumentation service
        Write-Verbose -Message "Stopping Windows Management Instrumentation service"
        Stop-Service -Name "Winmgmt" -Force -ErrorAction Stop
    }
    catch {
        Throw "Unable to stop 'Winmgmt' service"
    }

    # Contruct an array of locations to the WMI repository
    $WMIPaths = @((Join-Path -Path $env:SystemRoot -ChildPath "System32\wbem"),(Join-Path -Path $env:SystemRoot -ChildPath "SysWOW64\wbem"))
}
Process {
    if ($PSBoundParameters.Values -contains "Rebuild") {
        # Re-register WMI executables
        foreach ($WMIPath in $WMIPaths) {
            if (Test-Path -Path $WMIPath -PathType Container) {
                $WMIExecutables = @("unsecapp.exe","wmiadap.exe","wmiapsrv.exe","wmiprvse.exe","scrcons.exe")
                foreach ($WMIExecutable in $WMIExecutables) {
                    $CurrentExecutablePath = (Join-Path -Path $WMIPath -ChildPath $WMIExecutable)
                    if (Test-Path -Path $CurrentExecutablePath -PathType Leaf) {
                        Write-Verbose -Message "Registering: $($CurrentExecutablePath)"
                        Start-Process -FilePath $CurrentExecutablePath -ArgumentList "/RegServer" -Wait
                    }
                }
            }
            else {
                Write-Warning -Message "Unable to locate path '$($WMIPath)'"
            }
        }

        # Reset WMI repository
        if ([System.Environment]::OSVersion.Version.Major -ge 6) {
            $WinMgmtPath = Join-Path -Path $env:SystemRoot -ChildPath "\System32\wbem\winmgmt.exe"
            if ($PSBoundParameters["Reset"]) {
                Write-Verbose -Message "Resetting WMI repository"
                Start-Process -FilePath $WinMgmtPath -ArgumentList "/resetrepository" -Wait
            }
            else {
                Write-Verbose -Message "Salvaging WMI repository"
                Start-Process -FilePath $WinMgmtPath -ArgumentList "/salvagerepository" -Wait
            }
        }
        else {
            foreach ($WMIPath in $WMIPaths) {
                if (Test-Path -Path $WMIPath -PathType Container) {
                    $MOFFiles = Get-ChildItem $WMIPath -Include "*.mof","*.mfl" -Recurse
                    foreach ($MOFFile in $MOFFiles) {
                        $CurrentMOFFilePath = (Join-Path -Path $WMIPath -ChildPath $MOFFile)
                        Write-Verbose -Message "Compiling MOF: $($CurrentMOFFilePath)"
                        Start-Process -FilePath (Join-Path -Path $env:SystemRoot -ChildPath "\System32\wbem\mofcomp.exe") -ArgumentList $CurrentMOFFilePath -Wait
                    }
                }
                else {
                    Write-Warning -Message "Unable to locate path '$($WMIPath)'"
                }
            }
            if ([System.Environment]::OSVersion.Version.Minor -eq 1) {
                Start-Process -FilePath (Join-Path -Path $env:SystemRoot -ChildPath "\System32\rundll32.exe") -ArgumentList wbemupgd,UpgradeRepository
            }
            else {
                Start-Process -FilePath (Join-Path -Path $env:SystemRoot -ChildPath "\System32\rundll32.exe") -ArgumentList wbemupgd,RepairWMISetup
            }
        }
    }
}
End {
    # Start Windows Management Instrumentation service
    Write-Verbose -Message "Starting Windows Management Instrumentation service"
    Start-Service -Name "Winmgmt"

    # Start previously running services that was stopped by this script
    foreach ($Service in $RunningServicesArrayList) {
        Write-Verbose -Message "Starting service '$($Service)'"
        Start-Service -Name $Service -ErrorAction SilentlyContinue
    }
}

In order to run the script, save the script above as Start-WMIMaintenance.ps1 in e.g. C:\Scripts.

1. Open an elevated PowerShell console.
2. Browse to the C:\Scripts.
3. Run the following command:

.\Start-WMIMaintenance.ps1 -Task Rebuild -Verbose

After that we had run the script on the device that we decided to rebuild the WMI repository on, we were successful in uninstalling the ConfigMgr client.

Here’s the output from the script, to give you a better idea of what it does:

124_2

Nickolaj Andersen
Principal Consultant and Enterprise Mobility MVP. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows deployments and Automation. In 2015 Nickolaj was awarded as PowerShell Hero by the community for his script and tools contributions. Author of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService and a frequent speaker at user groups.

(973)

comments
  • Kevin Johnston
    Posted at 22:29 February 11, 2015
    Kevin Johnston
    Reply
    Author

    Nice post Nickolaj. I’m curious though, what is the reasoning for performing a salvage after a reset? I was under the impression that a salvage should be attempted first, and if that didn’t work, a reset. Once the reset occurs, I didn’t think there would be anything left to salvage. Thanks!

    • Nickolaj
      Posted at 10:41 February 12, 2015
      Nickolaj
      Reply
      Author

      Hi Kevin,

      Upon further searching on the topic, I believe that you’re correct in your statement. In fact, it should be enough with just a reset of the repository. Perhaps I should include such a switch that could give you the option to first salvage the repository and if it doesn’t work, perform a reset? What do you think?

      Learning every day 🙂

      Regards,
      Nickolaj

  • RobinH
    Posted at 12:19 October 14, 2015
    RobinH
    Reply
    Author

    This worked a treat for me, many thanks!

  • Leave a Reply