Skip to content

Instantly share code, notes, and snippets.

@zbalkan
Last active May 30, 2024 15:12
Show Gist options
  • Save zbalkan/4ba92656a3a8387e6b220bcf8fcd5fc6 to your computer and use it in GitHub Desktop.
Save zbalkan/4ba92656a3a8387e6b220bcf8fcd5fc6 to your computer and use it in GitHub Desktop.
It's a drop-in replacement for slmgr.vbs script
#Requires -RunAsAdministrator
#Requires -Version 5
<#
.Synopsis
Activates Windows via KMS
.DESCRIPTION
It's a drop in replacement for slmgr scripts
.EXAMPLE
Start-WindowsActivation -Verbose # Activates the local computer
.EXAMPLE
Start-WindowsActivation -Computer WS01 # Activates the computer named WS01
.EXAMPLE
Start-WindowsActivation -Computer WS01 -KMSServerFQDN server.domain.net -KMSServerPort 2500 # Activates the computer named WS01 against server.domain.net:2500
#>
function global:Start-WindowsActivation
{
[CmdletBinding(SupportsShouldProcess = $true,
PositionalBinding = $false,
ConfirmImpact = 'Medium',
DefaultParameterSetName = 'default')]
Param
(
# Type localhost or . for local computer or do not use the parameter
[Parameter(Mandatory = $false,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ValueFromRemainingArguments = $false)]
[string[]]
$Computers = @('localhost'),
[Parameter(Mandatory = $false,
Position = 1,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ValueFromRemainingArguments = $false,
ParameterSetName = 'SpecifyKMSServer')]
[ValidateLength(6, 253)]
[ValidateScript(
{
$pattern = [Regex]::new('(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)')
if ($pattern.Matches($_).Count -gt 0)
{
$true
}
else
{
throw "$_ is invalid. Please provide a valid FQDN"
}
})]
[ValidateNotNullOrEmpty()]
[string]
$KMSServerFQDN,
[Parameter(Mandatory = $false,
Position = 2,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ValueFromRemainingArguments = $false,
ParameterSetName = 'SpecifyKMSServer')]
[ValidateRange(1, 65535)]
[int]
$KMSServerPort = 1688
)
Begin
{
# Enum for a meaningful check. Reference: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/sppwmi/softwarelicensingproduct
enum LicenseStatusCode
{
Unlicensed
Licensed
OOBGrace
OOTGrace
NonGenuineGrace
Notification
ExtendedGrace
}
function getLicenseStatus
{
param(
[string]$Computer
)
if ($Computer -eq 'localhost')
{
$product = Get-CimInstance -Query 'SELECT * FROM SoftwareLicensingProduct' | Where-Object { $_.PartialProductKey }
}
else
{
$product = Get-CimInstance -Query 'SELECT * FROM SoftwareLicensingProduct' -ComputerName $Computer | Where-Object { $_.PartialProductKey }
}
$status = [LicenseStatusCode]( $product | Select-Object LicenseStatus).LicenseStatus
$activated = $status -eq [LicenseStatusCode]::Licensed
$result = [PSCustomObject]@{
LicenseStatus = $status
Activated = $activated
}
return $result
}
function sanitizeComputerName
{
param(
[string]$Computer
)
if ($Computer -eq '.' -or $Computer -eq '127.0.0.1' -or $null -eq $Computer)
{
return 'localhost'
}
else
{
return $Computer
}
}
# KMS Client License Keys - https://docs.microsoft.com/en-us/windows-server/get-started/kmsclientkeys
# Add as you wish
function getProductKey
{
param(
[string]$Computer
)
if ($Computer -eq 'localhost')
{
$OsVersion = ((Get-CimInstance -Class Win32_OperatingSystem).Caption)
}
else
{
$OsVersion = ((Get-CimInstance -Class Win32_OperatingSystem -ComputerName $Computer).Caption)
}
$productKey = switch -Wildcard ($OsVersion)
{
'Microsoft Windows Server 2022 Standard*' { 'VDYBN-27WPP-V4HQT-9VMD4-VMK7H' } # End of support: Oct 13, 2026
'Microsoft Windows Server 2022 Datacenter*' { 'WX4NM-KYWYW-QJJR4-XV3QB-6VM33' } # End of support: Oct 13, 2026
'Microsoft Windows Server 2019 Standard*' { 'N69G4-B89J2-4G8F4-WWYCC-J464C' } # End of support: Jan 9, 2024
'Microsoft Windows Server 2019 Datacenter*' { 'WMDGN-G9PQG-XVVXX-R3X43-63DFG' } # End of support: Jan 9, 2024
'Microsoft Windows Server 2019 Essentials*' { 'WVDHN-86M7X-466P6-VHXV7-YY726' } # End of support: Jan 9, 2024
# "Microsoft Windows Server 2016 Standard*" { "WC2BQ-8NRM3-FDDYY-2BFGV-KHKQY" } # End of support: Jan 11, 2022
# "Microsoft Windows Server 2016 Datacenter*" { "CB7KF-BWN84-R7R2Y-793K2-8XDDG" } # End of support: Jan 11, 2022
# "Microsoft Windows Server 2016 Essentials*" { "JCKRF-N37P4-C2D82-9YXRT-4M63B" } # End of support: Jan 11, 2022
# "Microsoft Windows Server 2012 R2 Datacenter*" { "W3GGN-FT8W3-Y4M27-J84CP-Q3VJ9" } # End of support: Oct 9, 2018
# "Microsoft Windows Server 2012 R2 Standard*" { "D2N9P-3P6X9-2R39C-7RTCD-MDVJX" } # End of support: Oct 9, 2018
# "Microsoft Windows Server 2012 Standard*" { "D2N9P-3P6X9-2R39C-7RTCD-MDVJX" } # End of support: October 9, 2018
# "Microsoft Windows Server 2008 R2 Enterprise*" { "489J6-VHDMP-X63PK-3K798-CPX3Y" } # End of support: Jan 14, 2020
'Microsoft Windows 10 Enterprise*' { 'NPPR9-FWDCX-D2C8J-H872K-2YT43' } # End of support: Oct 14, 2025
# 'Windows 10 Enterprise N*' { 'DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4' } # End of support: Oct 14, 2025
'Microsoft Windows 10 Professional*' { 'W269N-WFGWX-YVC9B-4J6C9-T83GX' } # End of support: Oct 14, 2025
# 'Windows 10 Professional N' { 'MH37W-N47XK-V7XM9-C7227-GCQG9' } # End of support: Oct 14, 2025
# "Microsoft Windows 7 Enterprise*" { "33PXH-7Y6KF-2VJC9-XBBR8-HVTHH" } # End of support: Jan 14, 2020
# "Microsoft Windows 7 Professional*" { "FJ82H-XT6CR-J8D7P-XQJJ2-GPDD4" } # End of support: Jan 14, 2020
default { 'Unknown' }
}
return $productKey
}
function activateWithDNS
{
param(
[string]$Computer,
[string]$ProductKey
)
if ($Computer -eq 'localhost')
{
$service = Get-CimInstance -Query 'SELECT * FROM SoftwareLicensingService'
}
else
{
$service = Get-CimInstance -Query 'SELECT * FROM SoftwareLicensingService' -ComputerName $Computer
}
$service.InstallProductKey($ProductKey) > $null
Start-Sleep -Seconds 10 # Installing product key takes time.
$service.RefreshLicenseStatus() > $null
Start-Sleep -Seconds 2 # It also takes time.
}
function activateWithParams
{
param(
[string]$Computer,
[string]$ProductKey,
[string]$KeyServerName,
[int]$KeyServerPort
)
if ($Computer -eq 'localhost')
{
$service = Get-CimInstance -Query 'SELECT * FROM SoftwareLicensingService'
}
else
{
$service = Get-CimInstance -Query 'SELECT * FROM SoftwareLicensingService' -ComputerName $Computer
}
$service.SetKeyManagementServiceMachine($KeyServerName)
$service.SetKeyManagementServicePort($KeyServerPort)
$service.InstallProductKey($ProductKey) > $null
Start-Sleep -Seconds 10 # Installing product key takes time.
$service.RefreshLicenseStatus() > $null
Start-Sleep -Seconds 2 # It also takes time.
}
}
Process
{
if ($pscmdlet.ShouldProcess('Computer', 'Activate license via KMS'))
{
$ErrorActionPreference = 'Stop'
Write-Verbose 'ErrorActionPreference: Stop'
Write-Verbose "Enumerating computers: $($Computers.Count) computer(s)."
foreach ($Computer in $Computers)
{
# Sanitize Computer name
$Computer = sanitizeComputerName -Computer $Computer
Write-Verbose "Computer name: $Computer"
# Check Windows Activation Status
$product = getLicenseStatus -Computer $Computer
Write-Verbose "License Status: $($product.Status)"
if ($product.Activated) { Write-Warning 'The product is already activated.'; continue; }
# Get product key
$productKey = getProductKey -Computer $Computer
Write-Verbose "Product Key (for KMS): $productKey"
# Activate Windows
if ($productKey -eq 'Unknown')
{
Write-Error 'Unknown OS.'
}
else
{
if ($PSCmdlet.ParameterSetName -eq 'SpecifyKMSServer')
{
activateWithParams -Computer $Computer -ProductKey $productKey -KeyServerName $KMSServerFQDN -KeyServerPort $KMSServerPort
}
else
{
activateWithDNS -Computer $Computer -ProductKey $productKey
}
$product = getLicenseStatus -Computer $Computer
if ($product.Activated)
{
Write-Verbose "The computer activated succesfully. Current status: $($product.LicenseStatus)"
}
else
{
Write-Error "Activation failed. Current status: $($product.LicenseStatus)"
}
}
}
}
}
}
@zbalkan
Copy link
Author

zbalkan commented Dec 16, 2023

Hi,

I improved the script to a Powershell module. It supports more than that: https://github.com/zbalkan/slmgr-ps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment