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:

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)
   {
      foreach ($depsvc in $svc.DependentServices)
      { 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...

Michael
Have keyboard. Will travel.

Comments (0)

Skip to main content