Last active
September 29, 2024 08:44
-
-
Save zbalkan/4ba92656a3a8387e6b220bcf8fcd5fc6 to your computer and use it in GitHub Desktop.
It's a drop-in replacement for slmgr.vbs script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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)" | |
} | |
} | |
} | |
} | |
} | |
} |
Added capability to define the KMS server name (FQDN) and port based on feedback of r/Zulgrib.
I have a script which activates a windows installation using a fake keyserver
@echo off
:: https://stackoverflow.com/a/8486061/9731176
title Activate Windows 11 (ALL versions) for FREE &cls&echo =====================================================================================&echo #Project: Activating Microsoft software products for FREE without additional software&echo =====================================================================================&echo.&echo #Supported products:&echo - Windows 11 Home&echo - Windows 11 Professional&echo - Windows 11 Education&echo - Windows 11 Enterprise&echo.&echo.&echo ============================================================================&echo Activating your Windows...&cscript //nologo slmgr.vbs /ckms >nul&cscript //nologo slmgr.vbs /upk >nul&cscript //nologo slmgr.vbs /cpky >nul&set i=1&wmic os | findstr /I "enterprise" >nul
if %errorlevel% EQU 0 (cscript //nologo slmgr.vbs /ipk NPPR9-FWDCX-D2C8J-H872K-2YT43 >nul||cscript //nologo slmgr.vbs /ipk DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4 >nul||cscript //nologo slmgr.vbs /ipk YYVX9-NTFWV-6MDM3-9PT4T-4M68B >nul||cscript //nologo slmgr.vbs /ipk 44RPN-FTY23-9VTTB-MP9BX-T84FV >nul||cscript //nologo slmgr.vbs /ipk WNMTR-4C88C-JK8YV-HQ7T2-76DF9 >nul||cscript //nologo slmgr.vbs /ipk 2F77B-TNFGY-69QQF-B8YKP-D69TJ >nul||cscript //nologo slmgr.vbs /ipk DCPHK-NFMTC-H88MJ-PFHPY-QJ4BJ >nul||cscript //nologo slmgr.vbs /ipk QFFDN-GRT3P-VKWWX-X7T3R-8B639 >nul||cscript //nologo slmgr.vbs /ipk M7XTQ-FN8P6-TTKYV-9D4CC-J462D >nul||cscript //nologo slmgr.vbs /ipk 92NFX-8DJQP-P6BBQ-THF9C-7CG2H >nul&goto skms) else wmic os | findstr /I "home" >nul
if %errorlevel% EQU 0 (cscript //nologo slmgr.vbs /ipk TX9XD-98N7V-6WMQ6-BX7FG-H8Q99 >nul||cscript //nologo slmgr.vbs /ipk 3KHY7-WNT83-DGQKR-F7HPR-844BM >nul||cscript //nologo slmgr.vbs /ipk 7HNRX-D7KGG-3K4RQ-4WPJ4-YTDFH >nul||cscript //nologo slmgr.vbs /ipk PVMJN-6DFY6-9CCP6-7BKTT-D3WVR >nul&goto skms) else wmic os | findstr /I "education" >nul
if %errorlevel% EQU 0 (cscript //nologo slmgr.vbs /ipk NW6C2-QMPVW-D7KKK-3GKT6-VCFB2 >nul||cscript //nologo slmgr.vbs /ipk 2WH4N-8QGBV-H22JP-CT43Q-MDWWJ >nul&goto skms) else wmic os | findstr /I "11 pro" >nul
if %errorlevel% EQU 0 (cscript //nologo slmgr.vbs /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX >nul||cscript //nologo slmgr.vbs /ipk MH37W-N47XK-V7XM9-C7227-GCQG9 >nul||cscript //nologo slmgr.vbs /ipk NRG8B-VKK3Q-CXVCJ-9G2XF-6Q84J >nul||cscript //nologo slmgr.vbs /ipk 9FNHH-K3HBT-3W4TD-6383H-6XYWF >nul||cscript //nologo slmgr.vbs /ipk 6TP4R-GNPTD-KYYHQ-7B7DP-J447Y >nul||cscript //nologo slmgr.vbs /ipk YVWGF-BXNMC-HTQYQ-CPQ99-66QFC >nul&goto skms) else (goto notsupported)
:skms
if %i% GTR 10 goto busy
if %i% EQU 1 set KMS=kms7.MSGuides.com
if %i% EQU 2 set KMS=s8.now.im
if %i% EQU 3 set KMS=s9.now.im
if %i% GTR 3 goto ato
cscript //nologo slmgr.vbs /skms %KMS%:1688 >nul
:ato
echo ============================================================================&echo.&echo.&cscript //nologo slmgr.vbs /ato | find /i "successfully" && (echo.&echo ============================================================================&echo.&echo #My official blog: devsjournal.com&echo.&echo #How it works: bit.ly/kms-server&echo.&echo #Please feel free to contact me at msguides.com@gmail.com if you have any questions or concerns.&echo.&echo #Please consider supporting this project: donate.msguides.com&echo #Your support is helping me keep my servers running 24/7!&echo.&echo ============================================================================&choice /n /c YN /m "Would you like to visit my blog [Y,N]?" & if errorlevel 2 exit) || (echo The connection to my KMS server failed! Trying to connect to another one... & echo Please wait... & echo. & echo. & set /a i+=1 & goto skms)
explorer "http://MSGuides.com"&goto halt
:notsupported
echo ============================================================================&echo.&echo Sorry, your version is not supported.&echo.&goto halt
:busy
echo ============================================================================&echo.&echo Sorry, the server is busy and can't respond to your request. Please try again.&echo.
:halt
pause >nul
which I'd really like to convert to PowerShell. It seems to me like your script does or at least can do the same, but do you think you can confirm, @zbalkan?
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
Major refactor: