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”
<#
.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.
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
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
That’s weird thought, Because I have it in deployment to 590 computers. A lot of them have been fixed.
Nevermind! Good luck!