IntuneSCCMWindows 10Windows 11

Automating WMI Issues Detection and Remediation for Network Adapters

Introduction

If you’ve ever encountered issues with WMI, you know they can be a real headache. It’s one of those things that seem to go wrong for no apparent reason, especially when you’re dealing with VPNs like GlobalProtect, SCCM, or Intune.

In this blog post, I’m going to walk you through a solution that could save you hours of troubleshooting. We’re going to automate the detection and remediation of WMI issues, focusing specifically on those related to network adapters.

Why do we focus on network adapters?

In my recent experience, many users at home suddenly lost their VPN connection due to an error message: “virtual adapter was not set up correctly…” with GlobalProtect. The root cause? A corrupt WMI, preventing connection with GlobalProtect. However, since SCCM and Intune also use WMI for different purposes, it was necessary to perform a WMI repair.

How do I detect WMI errors with Network Adapters?

Quite simply, we’re working with PowerShell, and one well-known command is:

Get-NetAdapter

In this example, the WMI classes are showing errors like “Invalid class” MSFT_NetAdapter (0x80041010),

leading to corrupted Software Center as well.

How can I solve this problem?

I have written a script that automatically checks for WMI errors related to network adapters. If any are found, it initiates a remediation process. Additionally, at the end of the script, I’ve added an SCCM Agent Health scan, which automatically resolves any WMI issues associated with the agent. The status of the health scan can then be checked in the log file located at C:\Windows\CCM\ccmeval.log. If repair is required, the progress can be found in the log file C:\Windows\CCMSetup\logs\ccmsetup-ccmeval.log.

Link to Github

<#
.SYNOPSIS
A PowerShell script designed to detect and remedy potential WMI class or namespace issues.

.DESCRIPTION
This script checks for specific errors related to the WMI class. If such errors are identified, various remediation steps are undertaken, 
including the re-registration of WBEM DLLs and EXEs, the restoration of the WMI repository, and the restarting of associated services.

.PARAMETER None required

.EXAMPLE
PS> .\WMIRemediation.ps1

.NOTES
Date Created: 2023-08-18
Author: Ditor Sahiti
#>

# Define the log file path
$logFilePath = "C:\Windows\Logs\WMIRemediation.log"

# Function to write logs
function Write-Log {
    param (
        [string]$Message
    )
    Add-Content -Path $logFilePath -Value "$(Get-Date) - $Message"
}

# Attempt to retrieve Network Adapters
$adapters = $null
$errorOccurred = $false

# Redirect error stream to variable
$adapters = Get-NetAdapter 2>&1

# Check if the error message contains the substring 'Invalid class'
if ($adapters -like "*Invalid*") {
    $errorOccurred = $true
    Write-Log "Error occurred: Invalid class in network adapters."
}

# If WMI class related error occurred
if ($errorOccurred) {
    Write-Log "WMI class appears to be missing. Attempting to fix..."

    # Attempt to stop ConfigManager service and WMI service
    Write-Log 'Stopping ConfigManager service if it exists'
    Stop-Service -Force 'ccmexec' -ErrorAction 'SilentlyContinue'

    # Temporarily disable the WMI service to perform corrective actions
    Write-Log 'Temporarily disabling Windows Management Instrumentation service'
    Set-Service -Name 'winmgmt' -StartupType 'Disabled' 

    Write-Log 'Stopping Windows Management Instrumentation service'
    Stop-Service -Force 'winmgmt' -ErrorAction 'SilentlyContinue'

    # Run the commands to re-register WMI components

    Write-Log 'Running commands to re-register WMI components'
    Set-Location "$env:windir\system32\wbem"
    cmd /c "for /f %s in ('dir /b *.dll') do regsvr32 /s %s"
    cmd /c "wmiprvse /regserver"
    cmd /c "winmgmt /regserver"
    cmd /c "for /f %s in ('dir /s /b *.mof *.mfl') do mofcomp %s"

    # Restore the WMI service to its original state and restart it
    Write-Log 'Setting Windows Management Instrumentation service back to Automatic'
    Set-Service -Name 'winmgmt' -StartupType 'Automatic'

    Write-Log 'Starting Windows Management Instrumentation service'
    Start-Service winmgmt -ErrorAction SilentlyContinue

    # Compile the provided MOF file
    Write-Log "Executed mofcomp on 'ExtendedStatus.mof'"
    mofcomp "C:\Program Files\Microsoft Policy Platform\ExtendedStatus.mof"
    
    # Run ccmeval.exe without waiting for it to finish
    Write-Log "Running ConfigMgr Evaluation"
    Start-Job -ScriptBlock {
    & "C:\Windows\ccm\ccmeval.exe"
    }
    Write-Log 'Remediation process completed'
    
    # Retry the retrieval of network adapters
    $adapters = Get-NetAdapter 2>&1
    if ($adapters -like "*Invalid*") {
        Write-Log "Error still present: Invalid class in network adapters. Running additional fix."

        Set-Location "$env:windir\system32\wbem"
        
        # Run the additional remediation steps
        cmd /c "regsvr32.exe /s /i .\NetAdapterCim.dll"
        cmd /c ".\mofcomp.exe .\NetAdapterCim.mof"
        Write-Log 'Remediation process completed'
    }
}
else {
    Write-Log "No issues detected with WMI class for network adapters."
}

How can I automate this?

You can either create a scheduled task via GPO or package, if the WMI is not yet corrupted, that executes the script at startup. This ensures that if there are any WMI issues present, the problem will be automatically resolved. In my example I created a scheduled task, exported it, and then created a package via PSADT.

Here are the steps I have taken:

1. Open Task Scheduler and create a new task using “Create Task…”

2. Enter the name of the scheduled task, run the task as SYSTEM, enable Run with highest privileges.

3. Create a new trigger and select “Run at system startup.”

4. Assuming the script is located at C:\Company\Scripts, create new actions as follows:

Program/Script: Powershell.exe
Add arguments: -ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -File “C:\Company\Scripts\WMINetAdapterCheck\WMIRemediation.ps1”


5. Export the XML file or use the example below and create your PSADT package.

XML File:

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2023-11-07T18:00:59.9736386</Date>
    <Author>SYSTEM</Author>
    <URI>\WMINetadapterCheck</URI>
  </RegistrationInfo>
  <Triggers>
    <BootTrigger>
      <Enabled>true</Enabled>
    </BootTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>true</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
    <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>Powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -File "C:\Company\Scripts\WMINetAdapterCheck\WMIRemediation.ps1"</Arguments>
    </Exec>
  </Actions>
</Task>

Install:

        #Check if the folder exists, and if not, create it at the following path:
        $path = "C:\Company\Scripts\WMINetAdapterCheck"
            if (-not (Test-Path -Path $path)) {
                New-Item -Path $path -ItemType Directory
        }

        #Copy the WMIRemediation.ps1 from $dirScript to the specified path:
        Copy-Item -Path "$dirFiles\WMIRemediation.ps1" -Destination $path -Force
        
         
        #Silently import the Scheduled Task named "ConfigMgr Client Health.xml" located in $dirScript
        $taskName = "WMINetadapterCheck"
        $taskPath = "$dirFiles\WMINetadapterCheck.xml"

        # Check if the task exists
        if (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue) {
            # If it exists, unregister/delete it
            Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
        }

        # Import the task (this will create a new task if it doesn't exist, or overwrite if it does)
        if (Test-Path -Path $taskPath) {
            Register-ScheduledTask -Xml (Get-Content $taskPath | Out-String) -TaskName $taskName
        } else {
            Write-Host "Scheduled Task not found!"
        }

Uninstall:

        # Path to the WMINetadapterCheck folder
        $path = "C:\Company\Scripts\WMINetadapterCheck"

        # Name of the scheduled task
        $taskName = "WMINetadapterCheck"
        
        # Check if the scheduled task exists and delete it if found
        if (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue) {
            Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
            Write-Host "Scheduled Task '$taskName' has been deleted."
        } else {
            Write-Host "Scheduled Task '$taskName' not found."
        }
        
        # Check if the folder exists and delete it if found
        if (Test-Path -Path $path) {
            Remove-Item -Path $path -Recurse -Force
            Write-Host "Folder '$path' has been deleted."
        } else {
            Write-Host "Folder '$path' not found."
        }

Conclusion

In summary, we’ve learned to detect and automatically fix WMI errors related to network adapters. Understanding the root cause of these errors can be tricky, but having automation in place is highly beneficial, especially in today’s remote work environment. This saves users the inconvenience of bringing their notebooks into the office unnecessarily.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *