Public/Repair-WindowsLicense.ps1
|
#Requires -Version 5 <# .SYNOPSIS Reinstalls known-good Windows system license files. .DESCRIPTION Finds .xrm-ms files below the local Windows OEM and SPP token directories and reinstalls them through SoftwareLicensingService. This operation is local-only because the files must come from the target system's own Windows installation. .INPUTS None. .OUTPUTS slmgr-ps.LicensingOperationResult. Emits one result for localhost when the operation is attempted. Throws one aggregate error after attempting every discovered license file when one or more files fail. .EXAMPLE Repair-WindowsLicense -Verbose .LINK https://github.com/zbalkan/slmgr-ps #> function Repair-WindowsLicense { [OutputType([PSCustomObject])] [CmdletBinding(SupportsShouldProcess = $true, PositionalBinding = $false, ConfirmImpact = 'High')] param() $licenseFiles = @(Get-SystemLicenseFile -ErrorAction Stop) if (-not $PSCmdlet.ShouldProcess( 'localhost', "Reinstall $($licenseFiles.Count) Windows system license file(s)")) { return } $repairFailures = [System.Collections.Generic.List[System.Management.Automation.ErrorRecord]]::new() $fileFailures = [System.Collections.Generic.List[System.Management.Automation.ErrorRecord]]::new() $session = $null try { $session = Get-Session -Computer 'localhost' -Credentials $null -ErrorAction Stop $service = Get-CimInstance -CimSession $session -ClassName SoftwareLicensingService -ErrorAction Stop $installedAny = $false foreach ($file in $licenseFiles) { try { $license = @(Get-LicenseFileContent -Path $file.FullName -ErrorAction Stop)[0] $service | Invoke-SppCimMethod -MethodName InstallLicense -Arguments @{ License = $license.Content } $installedAny = $true } catch { $message = "Failed to reinstall system license file '$($file.FullName)': $($_.Exception.Message)" $exception = [System.InvalidOperationException]::new($message, $_.Exception) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'WindowsSystemLicenseRepairFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, $file.FullName) $fileFailures.Add($errorRecord) } } if ($installedAny) { try { $service | Invoke-SppCimMethod -MethodName RefreshLicenseStatus } catch { $message = "System licenses were reinstalled, but licensing status could not be refreshed: $($_.Exception.Message)" $exception = [System.InvalidOperationException]::new($message, $_.Exception) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'WindowsSystemLicenseRefreshFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, 'localhost') $fileFailures.Add($errorRecord) } } } catch { $message = "System license repair could not start: $($_.Exception.Message)" $exception = [System.InvalidOperationException]::new($message, $_.Exception) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'WindowsSystemLicenseRepairStartFailed', [System.Management.Automation.ErrorCategory]::ConnectionError, 'localhost') $fileFailures.Add($errorRecord) } finally { if ($null -ne $session) { Remove-CimSession -CimSession $session -ErrorAction Ignore | Out-Null } } if ($fileFailures.Count -eq 0) { New-LicensingOperationResult ` -ComputerName localhost ` -Operation RepairSystemLicenses ` -Success $true ` -VerificationState ProviderAccepted } else { $innerExceptions = [System.Collections.Generic.List[System.Exception]]::new() foreach ($failure in $fileFailures) { $innerExceptions.Add($failure.Exception) } $targetException = [System.AggregateException]::new( "$($fileFailures.Count) system license repair failure(s). First failure: $($fileFailures[0].Exception.Message)", $innerExceptions.ToArray()) $targetException.Data['Failures'] = $fileFailures.ToArray() $targetError = [System.Management.Automation.ErrorRecord]::new( $targetException, 'WindowsSystemLicenseRepairFailed', [System.Management.Automation.ErrorCategory]::InvalidOperation, 'localhost') $structured = New-LicensingOperationError ` -ErrorRecord $targetError ` -ComputerName localhost ` -Operation RepairSystemLicenses $repairFailures.Add($structured.ErrorRecord) Write-Output $structured.Result } Complete-LicensingOperationBatch -Failures $repairFailures } |