Resetting WMI repository - dos and dont's
Today's topic:
Resetting WMI Repository
dos and dont's
Some people like Windows Management Instrumentation (WMI) because of its power - some just hate it. The ones who hate it often claim that the WMI repository is not really reliable and often gets corrupt / unusable.
Even though this may happen - it's not a usual scenario. Anyhow - if you face a corrupt WMI repository - you need to repair it.
The basic steps would be
- set WinMgmt service state to Disabled
- stop WinMgmt service
- walk through all dlls in %windir%\system32\wbem and re-register those
- call /regserver method on WMI private server executable (wmiprvse.exe)
- call /resetrepository method on WinMgmt service executable to reset the WMI repository to the initial state and restore MOF files that contain the #pragma autorecover statement
- set WinMgmt service state to Auto
- start WinMgmt service
- walk through all relevant Windows Management Object Files (.mof) in %windir%\system32\wbem and all Windows Management Language Files (.mfl) in language subfolders of %windir%\system32\wbem and re-register them by mofcomp.exe calls.
- restart machine
There are various articles out there that describe how to do it - some even provide automation code. Unfortunately most of these disregard the fact that the purpose of some MOF files is to uninstall the WMI namespace / class defined in the MOF - they just run through all MOF files and register those.
Saying - if you mofcomp all MOF files found in the wbem folder - you may end up with an even more unusable WMI repository - just because you uninstalled necessary WMI data ...
How you detect MOFs / MFLs that are intended to uninstall WMI namespaces / classes:
Some MOFs / MFLs are very kind to the admins and have 'uninstall' or 'remove' as part of their name - but this does not detect all classes that uninstall WMI data. To reliably identify the MOFs / MFLs to be registered by mofcomp -> do the following:
- skip MOFs / MFLs that have 'autorecover' as part of their name
- skip MOFs / MFLs that have 'uninstall' or 'remove' as part of their name
- skip MOFs / MFLs that contain the #pragma autorecover statement (already handled by winmgmt /resetrepository)
- skip MOFs / MFLs that do not contain the #pragma autorecover statement but either #pragma deleteinstance or #pragma deleteclass statement(s)
To bring this all together in some PoSh code:
[code lang="powershell"]
function DisableService([System.ServiceProcess.ServiceController]$svc)
{ Set-Service -Name $svc.Name -StartupType Disabled }
function EnableServiceAuto([System.ServiceProcess.ServiceController]$svc)
{ Set-Service -Name $svc.Name -StartupType Automatic }
function StopService([System.ServiceProcess.ServiceController]$svc)
{
[string]$dep = ([string]::Empty)
foreach ($depsvc in $svc.DependentServices)
{ $dep += $depsvc.DisplayName + ", " }
Write-Host "Stopping $($svc.DisplayName) and its dependent services ($dep)"
$svc.Stop()
$svc.WaitForStatus([System.ServiceProcess.ServiceControllerStatus]::Stopped)
Write-Host "Stopped $($svc.DisplayName)"
}
function StartService([System.ServiceProcess.ServiceController]$svc, [bool]$handleDependentServices)
{
if ($handleDependentServices)
{ Write-Host "Starting $($svc.DisplayName) and its dependent services" }
else
{ Write-Host "Starting $($svc.DisplayName)" }
if (!$svc.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Running)
{
try
{
$svc.Start()
$svc.WaitForStatus([System.ServiceProcess.ServiceControllerStatus]::Running)
}
catch { }
}
Write-Host "Started $($svc.DisplayName)"
if ($handleDependentServices)
{
[System.ServiceProcess.ServiceController]$depsvc = $null;
foreach ($depsvc in $svc.DependentServices)
{
if ($depsvc.StartType -eq [System.ServiceProcess.ServiceStartMode]::Automatic)
{ StartService $depsvc $handleDependentServices }
}
}
}
function RegSvr32([string]$path)
{
Write-Host "Registering $path"
regsvr32.exe $path /s
}
function RegisterMof([System.IO.FileSystemInfo]$item)
{
[bool]$register = $true
Write-Host "Inspecting: $($item.FullName)"
if ($item.Name.ToLowerInvariant().Contains('uninstall'))
{
$register = $false
Write-Host "Skipping - uninstall file: $($item.FullName)"
}
elseif ($item.Name.ToLowerInvariant().Contains('remove'))
{
$register = $false
Write-Host "Skipping - remove file: $($item.FullName)"
}
else
{
$txt = Get-Content $item.FullName
if ($txt.Contains('#pragma autorecover'))
{
$register = $false
Write-Host "Skipping - autorecover: $($item.FullName)"
}
elseif ($txt.Contains('#pragma deleteinstance'))
{
$register = $false
Write-Host "Skipping - deleteinstance: $($item.FullName)"
}
elseif ($txt.Contains('#pragma deleteclass'))
{
$register = $false
Write-Host "Skipping - deleteclass: $($item.FullName)"
}
}
if ($register)
{
Write-Host "Registering $($item.FullName)"
mofcomp $item.FullName
}
}
function HandleFSO([System.IO.FileSystemInfo]$item, [string]$targetExt)
{
if ($item.Extension -ne [string]::Empty)
{
if ($targetExt -eq 'dll')
{
if ($item.Extension.ToLowerInvariant() -eq '.dll')
{ RegSvr32 $item.FullName }
}
elseif ($targetExt -eq 'mof')
{
if (($item.Extension.ToLowerInvariant() -eq '.mof') -or ($item.Extension.ToLowerInvariant() -eq '.mfl'))
{ RegisterMof $item }
}
}
}
# get Winmgmt service
[System.ServiceProcess.ServiceController]$wmisvc = Get-Service 'winmgmt'
# disable winmgmt service
DisableService $wmisvc
# stop winmgmt service
StopService $wmisvc
# get wbem folder
[string]$wbempath = [Environment]::ExpandEnvironmentVariables("%windir%\system32\wbem")
[System.IO.FileSystemInfo[]]$itemlist = Get-ChildItem $wbempath -Recurse | Where-Object { $_.FullName.Contains('AutoRecover') -ne $true}
[System.IO.FileSystemInfo]$item = $null
# walk dlls
foreach ($item in $itemlist)
{ HandleFSO $item 'dll' }
# call /regserver method on WMI private server executable
wmiprvse /regserver
# call /resetrepository method on WinMgmt service executable
winmgmt /resetrepository
# enable winmgmt service
EnableServiceAuto $wmisvc
# start winmgmt service
StartService $wmisvc $true
# walk MOF / MFLs
foreach ($item in $itemlist)
{ HandleFSO $item 'mof' }
Kudos to my dear colleague Constantin - one of the WMI haters :- )
Have fun resetting...
4/6/2019: Updated PoSh code to only start dependent services if start mode of those is set to 'Automatic'
Michael
Have keyboard. Will travel.
Comments
- Anonymous
April 02, 2019
So. First off, Beautiful code! Thanks for building this! Secondly, I have a problem. When I run this, it seems to hang on "Starting Network Connectivity ASsistant and it's dependent services." Any ideas??- Anonymous
April 05, 2019
I'm guessing it should be relatively safe to modify this section...# start winmgmt serviceStartService $wmisvc $trueto# start winmgmt serviceStartService $wmisvc $falseIt appears it attempts to ensure all dependent services of WMI are running before proceeding. However, Network Connectivity Assistant doesn't stay running. It's a manual process that will stop itself if it doesn't have anything to do. So the script appears to be waiting on a service to stay in a running state that never will.- Anonymous
April 06, 2019
Hi guys,thx for error feedback - very welcome.Changed code above to only start dependency services if start mode of the service is set to 'Automatic': foreach ($depsvc in $svc.DependentServices) { if ($depsvc.StartType -eq [System.ServiceProcess.ServiceStartMode]::Automatic) { StartService $depsvc $handleDependentServices } }
- Anonymous
- Anonymous
- Anonymous
May 25, 2019
The comment has been removed