<# Title: Fix-WindowsManagementInsturmentationWMI Copyright (c) Emberkom LLC Author: David Yoder Date: 2023-03-14 Intent and Notes: This script will attempt to salvage the WMI repository. If that fails, it will rebuild the repository by recompiling all MOF and MFL files and re-registering all *.dll and *.exe files that exist in the WBEM directory. This script will take ~7-10min on mid hardware, and >15min on old/slow hardware. Microsoft documentation recommends using the following command to rebuild the WMI repository: winmgmt /resetrepository However, in my experience the above command doesn't always fix the issue. #> # Exit the script if WMI does not appear to be installed at all If ( !(Test-Path "${Env:SystemRoot}\System32\wbem") ) { Write-Error "WMI components are not present on this device. Please install them manually." ; Exit 1 } $WMIService = Get-Service -Name winmgmt -ErrorAction SilentlyContinue # Exit the script if we cannot find the winmgmt service If ( !$WMIService ) { Write-Output "The winmgmt service cannot be found, WMI is likely not the problem on this endpoint, no actions will be performed by this script" }#; Exit 1 } # Exit the script if the winmgmt service is not configured for automatic startup If ( $WMIService.StartType -ne 'Automatic' ) { Write-Output "The winmgmt service is not configured to automatically start, this is not a default configuration, no actions will be performed by this script" }#; Exit 1 } # Exit the script if the winmgmt service is not running If ( $WMIService.Status -ne 'Running' ) { Write-Output "The winmgmt service is configured to start automatically but is not currently running, WMI is likely not the issue on this endpoint, no actions will be performed by this script" }#; Exit 1} # Function to test if WMI is functioning correctly Function Test-WMIFunctionality { # Track the number of failed functionality tests $WMIErrorLevel = 0 # Specify the WMI class name to query $Class = 'Win32_OperatingSystem' # Specify a property in the WMI class that we can test for a value $Property = 'LastBootUpTime' # Test that our property has a value, and that the WBEM folder exists. If ( $null -eq $(Get-CimInstance -ClassName $Class -ErrorAction SilentlyContinue | Select-Object $Property -ErrorAction SilentlyContinue).$Property ) { Write-Error "Failed to query ${Class} for the value of ${Property}" ; $WMIErrorLevel++ } # Test that the WMI repository is consistent $WMIRepoStatus = (winmgmt.exe /verifyrepository) If ( ($WMIRepoStatus -contains "inconsistent") -or ($WMIRepoStatus -contains "failed" ) ) { Write-Error "WMI repository is in an inconsistent state" ; $WMIErrorLevel++ } If ( $WMIErrorLevel -eq 0 ) { Return $true } Else { Return $false } } # Guard to exit script if no repair is necessary If ( Test-WMIFunctionality ) { Write-Output "WMI components are functioning correctly" ; Exit 0 } # Record the start time of the repair $StartTime = (Get-Date) # Attempt to salvage WMI repository and exit script if no further repair is necessary Write-Output "Attempting to salvage WMI repository" $WMIRepoSalvage = (winmgmt.exe /salvagerepository) If ( ($WMIRepoSalvage -notcontains "failed") -and (Test-WMIFunctionality) ) { Write-Output "WMI repository successfully salvaged" ; Exit 0 } Try { Write-Output "Failed to salvage WMI repository, attempting manual reinitialization of WMI" # Disable and stop the winmgmt service Write-Output "Stopping and disabling WMI service" Set-Service -Name winmgmt -StartupType Disabled Stop-Service -Name winmgmt -Force # Set the WBEM directory for manual refresh of WMI components $TargetDir = "${Env:WinDir}\System32\wbem" # Rename the Repository directory to Repo_backup If ( Test-Path "${TargetDir}\Repo_backup" ) { Remove-Item "${TargetDir}\Repo_backup" -Recurse -Force -ErrorAction SilentlyContinue } If ( Test-Path "${TargetDir}\Repository" ) { Rename-Item -Path "${TargetDir}\Repository" -NewName "${TargetDir}\Repo_backup" -Force } # Register all *.dll files Write-Output "Registering all DLL files in ""${TargetDir}""" $WMIDlls = Get-ChildItem -Path "${TargetDir}\*" -File -Include *.dll ForEach ( $dll in $WMIDlls ) { $path = $dll.FullName Write-Output " ""${path}""" Start-Process "regsvr32.exe" -ArgumentList "/s ""${path}""" -Wait } # Register all *.exe files except for: # wbemcntl.exe, wbemtest.exe, mofcomp.exe Write-Output "Registering all supported EXE files in ""${TargetDir}""" $WMIExes = Get-ChildItem -Path "${TargetDir}\*" -File -Include *.exe | Where-Object { ($_.BaseName.ToLower() -ne "wbemcntl") -and ($_.BaseName.ToLower() -ne "wbemtest") -and ($_.BaseName.ToLower() -ne "mofcomp") } ForEach ( $exe in $WMIExes ) { $path = $exe.FullName Write-Output " ""${path}""" Start-Process $path -ArgumentList "/regserver" -Wait } # Register all *.mof and *.mfl files Write-Output "Compiling all MOF and MFL files in ""${TargetDir}""" $WMIMofs = Get-ChildItem -Path "${TargetDir}\*" -File -Include *.mof,*.mfl ForEach ( $mof in $WMIMofs ) { $path = $mof.FullName Write-Output " ""${path}""" Start-Process "${TargetDir}\mofcomp.exe" -ArgumentList """${path}""" -Wait } } Catch { Write-Error $_.Exception.Message } Finally { # Start the winmgmt service Write-Output "Enabling and starting WMI service" Set-Service -Name winmgmt -StartupType Automatic Start-Service -Name winmgmt } # Final test of WMI If ( !(Test-WMIFunctionality) ) { Write-Output "WMI repair failed. Please restart this device and run this script again" ; Exit 1 } # Remove Repo_backup directory If ( Test-Path "${TargetDir}\Repo_backup" ) { Write-Output "Deleting ""${TargetDir}\Repo_backup""" Remove-Item -Path "${TargetDir}\Repo_backup" -Recurse -Force -ErrorAction SilentlyContinue } $ElapsedTime = (New-TimeSpan -Start $StartTime -End (Get-Date)).ToString("hh\:mm\:ss") Write-Output "WMI has been successfully repaired! Time elapsed: ${ElapsedTime}"