Fixing the Software Metering agent when having error 80070424 in the mtrmgr.log

I was configuring Software Metering at a costumer when reports seemed wrong. The costumer had already configured metering on Visio,exe which had been running for years, but only 60  installations was reporting usage in the past 120 days out of 540 total installations. I checked maintenance task on the site server and client settings to ensure that the server and clients was configured correct.
I looked into some of the log files on the clients and found this error:

StartPrepDriver – OpenService Failed with error 80070424

After some googling i found this Microsoft article and created a package to fix the issue, but now i was confronted by a new error i the log :

StartPrepDriver – OpenService Failed with error 2

I found another forum(can’t find the link), where it was stated that the installation had to be run as a local admin on the machine. After some testing i could confirm the statement.

The environment did’t not have configured the users to be local admin so i had to use a service account, and the only secure way of running in anther user context (that i know of) is running a task sequence.

Collecting the broken clients

First we need a collection including all the clients with the error. I choose to use a Configuration Baseline, you can import it into your own configuration using the .cab file or set it up yourself using this script as a Configuration Item:

Configuration Baseline to import:

Download: CB – Check Software Metering Agent

Script used in Configuration Item:


<#
    .SYNOPSIS


    .DESCRIPTION
    To fix https://support.microsoft.com/en-us/help/3213242/software-metering-agent-fails-with-software-metering-failed-to-start-p
    .PARAMETER

    .EXAMPLE

    .NOTES
    Author: Morten Rønborg
    Date: 13-09-2018
    Last Updated: 13-09-2018
#>

################################################
$CCMAgentLogFolder = "$env:windir\CCM\Logs"
$MeteringLog = "mtrmgr.log"
$DetectionError = "StartPrepDriver - OpenService Failed with error"


#Check if the error is present
if ((Get-Content -Path "$($CCMAgentLogFolder)\$($MeteringLog)" | Select-String $DetectionError)) {
    $Working = $False
}else {
    $Working = $True
}

#Return 
Return $Working

After the baseline has been imported we deploy it to a collection. In this example I deploy it to ‘All Desktop and Server Clients’, you can choose the schedule as preferred.

After that we create a collection based on the non-compliant clients from that deployment.

Now we have a collection which includes all the broken clients.

Deploying the fix

Now we want to prepare the package containing the script to fix the error. Copy the script to your package source share. Change the $LogLocation variable to what you prefer, currently its “$env:windir\Logs\Software”

Download: Set-PrepDriver


<#

    .SYNOPSIS


    .DESCRIPTION
    To fix https://support.microsoft.com/en-us/help/3213242/software-metering-agent-fails-with-software-metering-failed-to-start-p
    .PARAMETER

    .EXAMPLE

    .NOTES
    Author: Morten Rønborg
    Date: 12-09-2018
    Last Updated: 12-09-2018

#>

################################################
Function Write-Log
{
    param 
    (
        [Parameter(Mandatory=$true, HelpMessage="Provide a message")][string]$LogOutput,
        [Parameter(Mandatory=$true, HelpMessage="Provide the function name")][string]$FunctionName,
        [Parameter(Mandatory=$false, HelpMessage="Provide the scriptlinenumber")][string]$ScriptLine,
        [Parameter(Mandatory=$false, HelpMessage="Provide path, default is .\Logs")][string]$Path,
        [Parameter(Mandatory=$false, HelpMessage="Provide name for the logs")][string]$Name,
        [Parameter(Mandatory=$false, HelpMessage="Provide level, 1 = default, 2 = warning 3 = error")][ValidateSet(1, 2, 3)][int]$LogLevel = 1
    )

    #If the scriptline is not defined then use from the invocation
    If(!($ScriptLine)){
        $ScriptLine = $($MyInvocation.ScriptLineNumber)
    }

    if($LogOutput){

        #Date for the lognaming
        $FullLogName = ($Path + "\" + $Name + ".log")
        $FullSecodaryLogName = ($FullLogName).Replace(".log",".lo_")

        #If the log has reached over 20 mb then rename it
        if(Test-Path $FullLogName){
            if((Get-Item $FullLogName).Length -gt 5000kb){
                if(Test-Path $FullSecodaryLogName){
                    Remove-Item -Path $FullSecodaryLogName -force
                }
                Rename-Item -Path $FullLogName -NewName $FullSecodaryLogName
            }
        }

        #First check if folder/logfile excist, if not then create it
        if(!(test-path $Path)){
            New-Item -ItemType Directory -Force -Path $Path -ErrorAction SilentlyContinue
        }

        #Get current date and time to write to log
        $TimeGenerated = "$(Get-Date -Format HH:mm:ss).$((Get-Date).Millisecond)+000"

        #Construct the logline format
        $Line = '<![LOG[{0}]LOG]!><time="{1}" date="{2}" component="{3}" context="" type="{4}" thread="" file="">'

        #Define line
        $LineFormat = $logOutput, $TimeGenerated, (Get-Date -Format MM-dd-yyyy), "$($FunctionName):$($Scriptline)", $LogLevel

        #Append line
        $Line = $Line -f $LineFormat

        #Write log
        try {
            Write-Host ("[$($FunctionName):$($Scriptline)]" + $logOutput)
            $Line | Out-File -FilePath ($Path + "\" + $Name + ".log") -Append -NoClobber -Force -Encoding 'UTF8' -ErrorAction 'Stop'
        }
        catch {
            Write-Host "$_"
        }
    }
}

# logging variables
$LogLocation = "$env:windir\Logs\Software"
$LogName = "Fix-SCCMAgentSoftwareMeteringAgent"
$CCMAgentLogFolder = "$env:windir\CCM\Logs"
$MeteringLog = "mtrmgr.log"
$DetectionError = "StartPrepDriver - OpenService Failed with error"
$Elevated = (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

Write-Log -LogOutput ("*********************************************** SCRIPT START ***********************************************") -FunctionName $($MyInvocation.MyCommand)-Path $LogLocation -Name $LogName | Out-Null
Write-log -LogOutput ("Running in the context of '$($env:username)'") -FunctionName $($MyInvocation.MyCommand)-Path $LogLocation -Name $LogName | Out-Null
Write-log -LogOutput ("Running in elevated mode = $($Elevated)") -FunctionName $($MyInvocation.MyCommand)-Path $LogLocation -Name $LogName | Out-Null

#Check if the error is present
if (Get-Content -Path "$($CCMAgentLogFolder)\$($MeteringLog)" | Select-String $DetectionError) {

    #Fix the client
    Write-Log -LogOutput ("'$($DetectionError)' found in the '$($CCMAgentLogFolder)\$($MeteringLog)' log, loading the PrepDriver and restarting the SMS Agent Host..") -FunctionName $($MyInvocation.MyCommand)-Path $LogLocation -Name $LogName | Out-Null
    try {
        Start-Process -FilePath "RUNDLL32.EXE" -ArgumentList "SETUPAPI.DLL,InstallHinfSection DefaultInstall 128 C:\WINDOWS\CCM\prepdrv.inf"
        Restart-Service -Name "SMS Agent Host" -Force
    }
    catch {
        Write-Log -LogOutput ("$_") -FunctionName $($MyInvocation.MyCommand) -Path $LogLocation -Name $LogName -LogLevel 3 | Out-Null
    }

}else {
    Write-Log -LogOutput ("'$($DetectionError)' NOT found in the '$($CCMAgentLogFolder)\$($MeteringLog)' log, skipping fix.") -FunctionName $($MyInvocation.MyCommand)-Path $LogLocation -Name $LogName | Out-Null
}

Write-Log -LogOutput ("*********************************************** SCRIPT END ***********************************************") -FunctionName $($MyInvocation.MyCommand)-Path $LogLocation -Name $LogName | Out-Null

Create a simple package with no program, pointin at the location to the Set-PrepDriver location.

Create a custom Task Sequence with the ‘Run Command Line’ step running as the local admin service account.

powershell.exe -ExecutionPolicy Bypass -file .\Set-PrepDriver.ps1

Deploy that task sequence to the collection created earlier.

Specify the deployment setting as Required.

Specify the deployment setting to only rerun if failed previously.

Specify the deployment setting to not show progress.

Run a machine policy update on the client and check the logs.

The next time the Compliance Basline shedule is running the client object will be remove from the collection.

3 thoughts on “Fixing the Software Metering agent when having error 80070424 in the mtrmgr.log”

  1. Good job, but you can also fix it with a Remediation script directly in the Configuration Items. Here what I have used.

    $CurrDate = ‘{0:yyyy-MM-dd}’ -f (get-date)
    Start-Process -FilePath “C:\Windows\System32\RUNDLL32.EXE” -ArgumentList “SETUPAPI.DLL,InstallHinfSection DefaultInstall 128 C:\WINDOWS\CCM\prepdrv.inf”
    stop-service ccmexec -Force
    Start-Sleep -seconds 20
    Rename-Item -Path “C:\Windows\CCM\Logs\mtrmgr.log” -NewName “mtrmgr-$CurrDate.log”
    New-Item -Path “C:\Windows\CCM\Logs” -Name “mtrmgr.log” -ItemType “File”
    start-service ccmexec

    Reply
    • Hey Jim,

      I think the Configuration Items is running in the local system context, which will result in not fixing the issue.
      During my testing it was not working when running the script as system in 32bit (Package/Program). It resultet in a different error in the log.
      Do you have a different outcome?

      /Morten

      Reply
  2. That’s weird thought, Because I have it in deployment to 590 computers. A lot of them have been fixed.
    Nevermind! Good luck!

    Reply

Leave a comment