DSCResources/cWindowsLicense/cWindowsLicense.psm1
DATA Const{ ConvertFrom-StringData -stringdata @' ServiceClass = SoftwareLicensingService ProductClass = SoftwareLicensingProduct WindowsAppId = 55c92734-d682-4d71-983e-d6ec3f16059f '@ } # //////////////////////////////////////////////////////////////////////////////////////// # //////////////////////////////////////////////////////////////////////////////////////// #https://technet.microsoft.com/en-US/library/dn502536(v=ws.11).aspx Enum WinLicenseStatus { Unlicensed = 0 Licensed = 1 OOBGrace = 2 OOTGrace = 3 NonGenuineGrace = 4 Notification = 5 ExtendedGrace = 6 } # //////////////////////////////////////////////////////////////////////////////////////// # //////////////////////////////////////////////////////////////////////////////////////// function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [ValidateSet("Present", "Absent")] [string] $Ensure = 'Present', [parameter(Mandatory = $true)] [string] $ProductKey, [parameter()] [bool] $Activate = $true, [parameter()] [bool] $Force = $false # [parameter()] # [bool] # $IsKmsClient = $false, # [parameter()] # [string] # $KmsServer ) $GetRes = @{ Ensure = $Ensure ProductKey = '' Activate = $false #IsKmsClient = $false #KmsServer = $KmsServer PartialProductKey = '' LicenseStatus = '' OS = '' } # Check the Product key was installed or not $Product = Get-PrimaryWindowsSKU -ea SilentlyContinue if (-not $Product) { #Write-Verbose ('Product key is not installed on this machine.') $GetRes.Ensure = 'Absent' } else { $GetRes.Ensure = 'Present' $GetRes.OS = $Product.Name #Check activation status $GetRes.LicenseStatus = [string]([WinLicenseStatus]$Product.LicenseStatus) if ($Product.LicenseStatus -ne [WinLicenseStatus]::Licensed) { #Write-Verbose ('Windows is NOT Licensed. (License status: "{0}")' -f [WinLicenseStatus]$Product.LicenseStatus) $GetRes.Activate = $false } else { #Write-Verbose 'Windows is Licensed.' $GetRes.Activate = $true } #Get partial product key (Last 5 chars) $GetRes.PartialProductKey = $Product.PartialProductKey } $GetRes } # end of Get-TargetResource # //////////////////////////////////////////////////////////////////////////////////////// # //////////////////////////////////////////////////////////////////////////////////////// function Set-TargetResource { [CmdletBinding()] param ( [ValidateSet("Present", "Absent")] [string] $Ensure = 'Present', [parameter(Mandatory = $true)] [string] $ProductKey, [parameter()] [bool] $Activate = $true, [parameter()] [bool] $Force = $false ) # $ErrorActionPreference = 'Stop' # Test the product key format (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX) if ($ProductKey) { if ($ProductKey -notmatch '^[0-9A-Z]{5}(-[0-9A-Z]{5}){4}$') { Write-Error ('The product key is invalid') return } } $Slmgr = 'C:\Windows\System32\slmgr.vbs' $Cscript = 'C:\Windows\System32\cscript.exe' @($Slmgr, $Cscript).ForEach( { if (-not (Test-Path $_)) { Write-Error ('"{0}" not found' -f $_) } }) $cState = (Get-TargetResource @PSBoundParameters) if ($Ensure -eq 'Absent') { # Remove Product Key $ExitCode = (Start-Command -FilePath $Cscript -ArgumentList ($Slmgr, '-upk')).ExitCode if ($ExitCode -ne 0) {Write-Error ('Error happend when removing the product key')} else {Write-Verbose ('Remove the product key succeeded')} # Remove Product Key from registry $ExitCode = (Start-Command -FilePath $Cscript -ArgumentList ($Slmgr, '-cpky')).ExitCode if ($ExitCode -ne 0) {Write-Error ('Error happend when removing the product key from registry')} else {Write-Verbose ('Remove the product key from registry succeeded')} } else { $isKeyChenged = $false $local:tmpPPKey = $ProductKey.Substring($ProductKey.Length - 5, 5) # Last 5 chars if (($cState.Ensure -eq 'Absent') -or ($cState.PartialProductKey -ne $tmpPPKey) -or $Force) { # Install Product Key $ExitCode = (Start-Command -FilePath $Cscript -ArgumentList ($Slmgr, '-ipk', $ProductKey)).ExitCode if ($ExitCode -ne 0) {Write-Error ('Error happend when installing the product key')} else {Write-Verbose ('Install the product key succeeded')} $isKeyChenged = $true } if ($Activate) { if ($isKeyChenged -or (!$cState.Activate)) { #Activation $ExitCode = (Start-Command -FilePath $Cscript -ArgumentList ($Slmgr, '-ato')).ExitCode if ($ExitCode -ne 0) {Write-Error ('Error happend when try to activation')} else {Write-Verbose ('Activation succeeded')} } } } } # end of Set-TargetResource # //////////////////////////////////////////////////////////////////////////////////////// # //////////////////////////////////////////////////////////////////////////////////////// function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [ValidateSet("Present", "Absent")] [string] $Ensure = 'Present', [parameter(Mandatory = $true)] [string] $ProductKey, [parameter()] [bool] $Activate = $true, [parameter()] [bool] $Force = $false ) # Test the product key format (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX) if ($ProductKey) { if ($ProductKey -notmatch '^[0-9A-Z]{5}(-[0-9A-Z]{5}){4}$') { Write-Error ('The product key is invalid') return $true } } $cState = (Get-TargetResource @PSBoundParameters) if ($Ensure -eq 'Absent') { if ($cState.Ensure -eq 'Absent') { Write-Verbose ('Product key is not installed on this machine. It is your desired state.') return $true } else { Write-Verbose ('Product key is installed. It is NOT your desired state.') return $false } } elseif ($Ensure -eq 'Present') { if ($Force) { Write-Verbose ("Specified 'Force' switch. Skip test and return False.") return $false } if ($cState.Ensure -eq 'Absent') { Write-Verbose ('Product key is not installed on this machine. It is NOT your desired state.') return $false } $local:tmpPPKey = $ProductKey.Substring($ProductKey.Length - 5, 5) # Last 5 chars if ($cState.PartialProductKey -ne $tmpPPKey) { Write-Verbose ('Partial product key is not matched. (current:"{0}" / desired: "{1}")' -f $cState.PartialProductKey, $tmpPPKey) return $false } if ($Activate) { if (!$cState.Activate) { Write-Verbose ('Windows is NOT Licensed. (License status: "{0}")' -f [WinLicenseStatus]$cState.LicenseStatus) return $false } else { Write-Verbose 'Windows is Licensed.' } } } return $true } # end of Test-TargetResource # //////////////////////////////////////////////////////////////////////////////////////// # //////////////////////////////////////////////////////////////////////////////////////// function Get-PrimaryWindowsSKU { [CmdletBinding()] Param() # This logic is ported from slmgr.vbs $QueryStr = ('SELECT * FROM {0} WHERE PartialProductKey IS NOT NULL' -f $Const.ProductClass) $object = Get-WmiObject -Query $QueryStr -ErrorAction SilentlyContinue | where {($_.ApplicationId -eq $Const.WindowsAppId) -and (!$_.LicenseIsAddon)} if (@($object).Count -ne 1) { return $null } else { return $object } } # //////////////////////////////////////////////////////////////////////////////////////// # //////////////////////////////////////////////////////////////////////////////////////// function Start-Command { [CmdletBinding()] Param( [Parameter(Mandatory = $true, Position = 0)] [string] $FilePath, [Parameter(Mandatory = $false, Position = 1)] [string[]]$ArgumentList, [int]$Timeout = [int]::MaxValue ) $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo $ProcessInfo.FileName = $FilePath $ProcessInfo.UseShellExecute = $false $ProcessInfo.Arguments = [string]$ArgumentList $Process = New-Object System.Diagnostics.Process $Process.StartInfo = $ProcessInfo $Process.Start() | Out-Null if (!$Process.WaitForExit($Timeout)) { $Process.Kill() Write-Error ('Process timeout. Terminated. (Timeout:{0}s, Process:{1})' -f ($Timeout * 0.001), $FilePath) } $Process } Export-ModuleMember -Function *-TargetResource |