<# .SYNOPSIS Installs a Windows product key (for example an Enterprise MAK) and activates it, logging each step. .DESCRIPTION Uses the Software Licensing WMI classes, the same ones slmgr.vbs calls, to install a product key, activate Windows online, and confirm the result. If the key belongs to a different edition that supports a key-based upgrade (Pro or Education to Enterprise, for instance), Windows switches edition; a restart finishes the job. The key is taken as a SecureString and never written to the log. Run it elevated. Supports -WhatIf. .PARAMETER ProductKey The product key, as a SecureString. Prompted for if you leave it off. .PARAMETER ExpectedEdition The EditionID you expect afterwards, for example Enterprise. Used for the check at the end. .PARAMETER LogPath Where to write the log. Default: C:\Windows\Temp\Update-WindowsEdition.log .PARAMETER Restart Restart the computer when everything succeeded. Off by default. .EXAMPLE .\Update-WindowsEdition.ps1 -ExpectedEdition Enterprise -WhatIf .EXAMPLE .\Update-WindowsEdition.ps1 -ProductKey (Read-Host -AsSecureString 'Product key') -ExpectedEdition Enterprise -Restart #> #Requires -RunAsAdministrator [CmdletBinding(SupportsShouldProcess)] param( [securestring]$ProductKey, [ValidateNotNullOrEmpty()][string]$ExpectedEdition = 'Enterprise', [string]$LogPath = (Join-Path $env:SystemRoot 'Temp\Update-WindowsEdition.log'), [switch]$Restart ) $ErrorActionPreference = 'Stop' $windowsAppId = '55c92734-d682-4d71-983e-d6ec3f16059f' # ApplicationID for Windows itself in SoftwareLicensingProduct function Write-Log { param([string]$Message) $line = '{0:yyyy-MM-dd HH:mm:ss} {1}' -f (Get-Date), $Message Write-Verbose $line Add-Content -Path $LogPath -Value $line -WhatIf:$false } function Get-WindowsLicense { Get-CimInstance -ClassName SoftwareLicensingProduct -Filter "ApplicationID='$windowsAppId' AND PartialProductKey IS NOT NULL" | Select-Object -First 1 } $editionKey = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' $before = (Get-ItemProperty -Path $editionKey).EditionID Write-Log "Starting. Current edition: $before" if (-not $ProductKey) { $ProductKey = Read-Host -AsSecureString 'Product key' } $plainKey = [System.Net.NetworkCredential]::new('', $ProductKey).Password.Trim().ToUpper() if ($plainKey -notmatch '^([A-Z0-9]{5}-){4}[A-Z0-9]{5}$') { throw 'That doesn''t look like a product key (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX).' } $lastFive = $plainKey.Substring(24) $result = [ordered]@{ ComputerName = $env:COMPUTERNAME; EditionBefore = $before; EditionAfter = $null; KeyEndsWith = $lastFive; Activated = $false; RestartNeeded = $false } if (-not $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Install product key ending $lastFive and activate")) { return [pscustomobject]$result } try { $service = Get-CimInstance -ClassName SoftwareLicensingService Write-Log "Installing product key ending $lastFive" Invoke-CimMethod -InputObject $service -MethodName InstallProductKey -Arguments @{ ProductKey = $plainKey } | Out-Null Invoke-CimMethod -InputObject $service -MethodName RefreshLicenseStatus | Out-Null $license = Get-WindowsLicense Write-Log "Activating $($license.Name)" Invoke-CimMethod -InputObject $license -MethodName Activate | Out-Null $license = Get-WindowsLicense $result.Activated = ($license.LicenseStatus -eq 1) Write-Log "License status: $($license.LicenseStatus) (1 = licensed). Channel: $($license.ProductKeyChannel)" } catch { Write-Log "FAILED: $($_.Exception.Message)" throw } finally { $plainKey = $null } $after = (Get-ItemProperty -Path $editionKey).EditionID $result.EditionAfter = $after $result.RestartNeeded = ($after -ne $before) Write-Log "Edition now reports: $after" if ($after -ne $ExpectedEdition) { Write-Warning "Edition is '$after', expected '$ExpectedEdition'. Some changes only show after a restart." $result.RestartNeeded = $true } [pscustomobject]$result if ($Restart -and $result.Activated -and $PSCmdlet.ShouldProcess($env:COMPUTERNAME, 'Restart')) { Write-Log 'Restarting' Restart-Computer -Force }