| Server IP : 121.121.20.254 / Your IP : 216.73.216.202 Web Server : Microsoft-IIS/10.0 System : Windows NT WEB-SERVER 10.0 build 20348 (Windows Server 2022) AMD64 User : IUSR ( 0) PHP Version : 8.3.28 Disable Function : NONE MySQL : ON | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /Program Files/Microsoft Office/root/Office16/ |
Upload File : |
#Requires -Version 5.1
# Copyright (c) Microsoft Corporation. All rights reserved.
#////////////////////////////////////////////////////////////////////////////////////////
#////////////////////////////////////////////////////////////////////////////////////////
# Office Software Protection Platform (OSPP) PowerShell Script
# Maintains the established OSPP commands and console output format
#////////////////////////////////////////////////////////////////////////////////////////
#////////////////////////////////////////////////////////////////////////////////////////
#region Constants
$script:wshOK = 0
$script:VALUE_ICON_WARNING = 16
$script:VALUE_ICON_INFORMATION = 64
$script:HKEY_LOCAL_MACHINE = 2147483650 # 0x80000002 as unsigned
$script:KEY_SET_VALUE = 0x0002
$script:OfficeAppId = "0ff1ce15-a989-479d-af46-f275c6370663"
$script:STR_SYS32PATH = ":\Windows\System32\"
$script:STR_OSPPREARMEXE = "\OSPPREARM.EXE"
$script:STR_OSPPREARMPATH = "\Microsoft Office\Office16\OSPPREARM.EXE"
$script:STR_OSPPREARMPATH_DEBUG = "\Microsoft Office Debug\Office16\OSPPREARM.EXE"
$script:STR_HEARTBEATPATH = "\Microsoft\Office\Heartbeat\HeartbeatCache.xml"
$script:REG_SPP = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform"
$script:REG_SCAEXP_BASE = "HKCU\SOFTWARE\Microsoft\Office\16.0\Common\ExperimentEcs\"
$script:REG_SCAEXP_END = "\Flights\ofc5juzsw45rcw0"
$script:REG_SCAEXP_OVERRIDE = "HKLM\SOFTWARE\Microsoft\Office\Common\Experiment\ofc5juzsw45rcw0"
$script:REG_SCAO15 = "HKLM\SOFTWARE\Microsoft\Office\15.0\ClickToRun\Configuration\SharedComputerLicensing"
$script:REG_SCAO16 = "HKLM\SOFTWARE\Microsoft\Office\ClickToRun\Configuration\SharedComputerLicensing"
$script:VALUE_SCAEXP_FLAVOR = "exp"
$script:VALUE_SCAEXP_OVERRIDE_FLAVOR = "expoverride"
$script:VALUE_SCAO15_FLAVOR = "o15"
$script:VALUE_SCA016_FLAVOR = "o16"
$script:VALUE_SCAREGKEY_SINGLE_TYPE = "single"
$script:VALUE_SCAREGKEY_PER_APP_TYPE = "perapp"
$script:VER_INFO = "Version Info: 2016 1.0"
#endregion
#region Messages
$script:MSG_NOREGRIGHTS = "Insufficient rights to perform operation."
$script:MSG_ISCMD_ELEVATED = "Ensure cmd.exe is elevated (right click > run as administrator)."
$script:MSG_CREDENTIALFAILURE = "Connection failed with passed credentials."
$script:MSG_FILENOTFOUND = "File not found: "
$script:MSG_SEPERATESMALL = "---------------"
$script:MSG_SEPERATE = "---------------------------------------"
$script:MSG_PROCESSING = "---Processing--------------------------"
$script:MSG_EXIT = "---Exiting-----------------------------"
$script:MSG_UNSUPPORTED = "Unsupported command passed."
$script:MSG_UNSUPPORTEDOPEROS7 = "The following command is not supported: "
$script:MSG_UNSUPPORTEDLOCAL = "The following command is supported on local machine only: "
$script:MSG_CREDENTIALERR = "Passing credentials is not supported for this command."
$script:MSG_SUCCESS = "Successfully applied setting."
$script:MSG_NOKMSLICS = "No Office KMS licenses were found on the system."
$script:MSG_ACTATTEMPT = "Installed product key detected - attempting to activate the following product:"
$script:MSG_TOKACTATTEMPT = "Installed product key detected - attempting to token activate the following product:"
$script:MSG_NOKEYSINSTALLED = "<No installed product keys detected>"
$script:MSG_UNINSTALLKEYSUCCESS = "<Product key uninstall successful>"
$script:MSG_ACTSUCCESS = "<Product activation successful>"
$script:MSG_OFFLINEACTSUCCESS = "<Offline product activation successful>"
$script:MSG_KEYINSTALLSUCCESS = "<Product key installation successful>"
$script:MSG_PARTIALKEY = "Last 5 characters of installed product key: "
$script:MSG_UNINSTALLKEY = "Uninstalling product key for: "
$script:MSG_UNRECOGFILE = "Unrecognized file. Office licenses have an .xrm-ms file extension."
$script:MSG_INSTALLLICENSE = "Installing Office license: "
$script:MSG_INSTALLLICSUCCESS = "Office license installed successfully."
$script:MSG_SEARCHEVENTSKMS = "Searching for KMS activation events on machine: "
$script:MSG_SEARCHEVENTSRET = "Searching for Internet activation failure events on machine: "
$script:MSG_NOEVENTSSKMS = "No KMS activation events found on machine: "
$script:MSG_NOEVENTSRET = "No failure events found on machine: "
$script:MSG_OSPPSVC_NOINSTALL = "Error: The Software Protection Platform service is not installed."
$script:MSG_ERRPARTIALKEY = "The last 5 characters of an installed product key are required to run this option. Run the /dstatus option to display the partial product key."
$script:MSG_KEYNOTFOUND = "<Product key not found>"
$script:MSG_CMID = "Client Machine ID (CMID): "
$script:MSG_CMID_NOTFOUND = "Not found."
$script:MSG_NOLICENSEFOUND = "<No licenses found>"
$script:MSG_AUTHERR = "Authorization Error: 0x"
$script:MSG_REMILID = "Removed Token-based Activation License with License ID (ILID): "
$script:MSG_NOTFOUNDILID = "License not found with License ID (ILID): "
$script:MSG_KMSLOOKUP = "KMS Lookup Domain: "
$script:MSG_INFO_ONLY = " (for information purposes only as the status is licensed)"
$script:MSG_ACT_ERROR_FOUND_KB = "NOTICE: A KB article has been detected for activation failure: "
$script:MSG_ACT_ERROR_KB_LINK = "FOR MORE INFORMATION PLEASE VISIT: https://support.microsoft.com/kb/2870357#Error0x"
$script:MSG_SCAEXP = "SCA Mode Experiment key "
$script:MSG_SCAEXP_OVERRIDE = "SCA Mode Experiment Override key "
$script:MSG_SCAO15 = "SCA Mode for O15 key "
$script:MSG_SCAO16 = "SCA Mode for O16 key "
$script:MSG_SCAREGKEY_ACTIVE = "found ENABLED."
$script:MSG_SCAREGKEY_INACTIVE = "found DISABLED."
#endregion
#region More Messages
$script:MSG_VLActivationType = "Activation Type Configuration: "
$script:MSG_Act_Recent = "Most recent successful activation client information: "
$script:MSG_KMS_DNS = "KMS machine name from DNS: "
$script:MSG_KMS_DNS_ERR = "DNS auto-discovery: KMS name not available"
$script:MSG_ADInfoAOName = "Activation Object name: "
$script:MSG_ADInfoAODN = "AO DN: "
$script:MSG_ADInfoExtendedPid = "AO extended PID: "
$script:MSG_ADInfoActID = "AO activation ID: "
$script:MSG_ACTIVATION_INTERVAL = "Activation Interval: "
$script:MSG_RENEWAL_INTERVAL = "Renewal Interval: "
$script:MSG_HOST_CACHING = "KMS host caching: "
$script:MSG_HOST_REG_OVERRIDE = "KMS machine registry override defined: "
$script:MSG_DEFAULT_PORT = "1688"
#endregion
#region License Status Messages
$script:MSG_PID = "PRODUCT ID: "
$script:MSG_SKUID = "SKU ID: "
$script:MSG_LICENSENAME = "LICENSE NAME: "
$script:MSG_DESCRIPTION = "LICENSE DESCRIPTION: "
$script:MSG_LICSTATUS = "LICENSE STATUS: "
$script:MSG_LICENSED = " ---LICENSED--- "
$script:MSG_UNLICENSED = " ---UNLICENSED--- "
$script:MSG_OOBGRACE = " ---OOB_GRACE--- "
$script:MSG_OOTGRACE = " ---OOT_GRACE--- "
$script:MSG_NONGENGRACE = " ---NON_GENUINE_GRACE--- "
$script:MSG_NOTIFICATION = " ---NOTIFICATIONS--- "
$script:MSG_EXTENDEDGRACE = " ---EXTENDED GRACE--- "
$script:MSG_LICUNKNOWN = " ---UNKNOWN--- "
$script:MSG_REMAINGRACE = "REMAINING GRACE: "
$script:MSG_LICEXPIRY = "BETA EXPIRATION: "
$script:MSG_ERRCODE = "ERROR CODE: "
$script:MSG_ERRDESC = "ERROR DESCRIPTION: "
$script:MSG_ERRUNKNOWN = "An unknown error occurred."
$script:MSG_ERRCODEVALUE = "An error code must start with '0x'. Example: 0xC004F009"
#endregion
#region Event Messages
$script:MSG_NOEVENTS = "No events found."
$script:MSG_HEARTBEAT_LOCALONLY = "HEARTBEATCACHE.XML SUPPORTED FOR LOCAL MACHINE ONLY."
$script:MSG_SEARCHFOR = "SEARCHING FOR INSTANCES OF "
$script:MSG_SEARCH_FORKEY = "SEARCHING FOR OFFICE PRODUCT KEYS ON MACHINE: "
$script:MSG_EVENT_1013 = "ACTIVATION SUCCESS EVENT: "
$script:MSG_EVENT_8200 = "ACTIVATION FAILURE EVENT: "
$script:MSG_EVENT_1016 = "INSTALL PRODUCT KEY SUCCESS EVENT: "
$script:MSG_EVENT_1017 = "INSTALL PRODUCT KEY FAILURE EVENT: "
$script:MSG_EVENT_2011 = "OLC-OLS EVENT: "
$script:MSG_NOKEYSINSTALLED_SUB = "<<<<< NO INSTALLED -SUBSCRIPTION- PRODUCT KEYS DETECTED >>>>>"
$script:MSG_NOKEYSINSTALLED_PERP = "<<<<< NO INSTALLED -PERPETUAL- PRODUCT KEYS DETECTED >>>>"
$script:MSG_KEYSINSTALLED_SUB = "<<<<< -SUBSCRIPTION- PRODUCT KEY DETECTED. REPORTING ON ADDITIONAL PROPERTIES >>>>>"
$script:MSG_KEYSINSTALLED_PERP = "<<<<< -PERPETUAL- PRODUCT KEY DETECTED. REPORTING ON ADDITIONAL PROPERTIES >>>>>"
$script:MSG_SCAREGKEYS = "SCA REGISTRY KEYS"
#endregion
#region Global Variables
$script:globalResource = ""
$script:globalErr = ""
$script:foundSlUi = $false
$script:strSluiPath = ""
$script:strLocal = ""
$script:strMachine = ""
$script:strUser = ""
$script:strPassword = ""
$script:objWMI1 = $null
$script:wmiErr = ""
$script:productinstances = $null
$script:strValue = ""
$script:productClass = ""
$script:tokenClass = ""
$script:intIsKms = 0
$script:kmsCounter = 0
$script:isAdActivated = $false
$script:dlicense = $false
$script:foundSubKey = $false
$script:foundPerpKey = $false
$script:strSkuId = $null
$script:getHeartBeat = $false
$script:currentDir = ""
$script:telSuccess = $false
# Activation error codes for which a KB is available
$script:errorKBs = "80070422|80070426|C004F074|80070001|80070005|8007000D|8007232B|8007251D|C004F014|C004F038|C004F039|C004F041|C004F042|C004C003|4004F040"
#endregion
#region Helper Functions
function WMIDateStringToDate {
param([string]$dtmEventDate)
# Use SWbemDateTime to preserve locale-dependent date formatting
$objWmiDate = New-Object -ComObject "WBemScripting.SWbemDateTime"
$objWmiDate.Value = $dtmEventDate
$result = $objWmiDate.GetVarDate()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($objWmiDate) | Out-Null
return $result
}
function Get-FileEncodingType {
param([string]$strFileName)
$strEncoding = "ascii"
try {
$fileStream = [System.IO.File]::OpenRead($strFileName)
try {
$bytes = New-Object byte[] 3
$null = $fileStream.Read($bytes, 0, 3)
}
finally {
$fileStream.Close()
}
# Check for little endian (x86) unicode preamble (BOM: FF FE)
if ($bytes[0] -eq 255 -and $bytes[1] -eq 254) {
$strEncoding = "unicode"
}
# Check for utf-8 preamble (BOM: EF BB BF)
elseif ($bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) {
$strEncoding = "utf-8"
}
}
catch {
# Default to ascii on error
}
return $strEncoding
}
function Read-AllTextFile {
param([string]$strFileName)
$encoding = Get-FileEncodingType $strFileName
switch ($encoding) {
"unicode" {
return [System.IO.File]::ReadAllText($strFileName, [System.Text.Encoding]::Unicode)
}
"utf-8" {
return [System.IO.File]::ReadAllText($strFileName, [System.Text.Encoding]::UTF8)
}
default {
return [System.IO.File]::ReadAllText($strFileName, [System.Text.Encoding]::ASCII)
}
}
}
function Test-FileExistsWithMessage {
param([string]$file)
if (-not (Test-Path -Path $file -PathType Leaf)) {
if ($file -eq "$script:currentDir\slerror.xml") {
Write-Host "[$script:MSG_FILENOTFOUND$file Unable to display error description.]"
}
elseif ($file -eq "$script:currentDir\ospp.htm") {
Invoke-GlobalPopFailure -strFailure "$script:MSG_FILENOTFOUND`r$file" -boolQuit $false
Invoke-QuitExit
}
else {
Invoke-GlobalPopFailure -strFailure "$script:MSG_FILENOTFOUND`r$file" -boolQuit $true
}
}
}
function Get-SluiPath {
foreach ($drive in (Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Root -match '^\w:\\$' })) {
$sluiPath = "$($drive.Root)Windows\System32\slui.exe"
if (Test-Path -Path $sluiPath -PathType Leaf) {
$script:strSluiPath = $sluiPath
$script:foundSlUi = $true
return
}
}
}
function Get-Description {
param(
[string]$strSearch,
[string]$cType
)
if ($script:foundSlUi -ne $true) {
if ($cType -ne "wmi") {
Invoke-GlobalPopFailure -strFailure "slui.exe not found." -boolQuit $true
Invoke-QuitExit
}
}
else {
$process = Start-Process -FilePath $script:strSluiPath -ArgumentList "0x2a", $strSearch -PassThru -Wait -NoNewWindow
Invoke-QuitExit
}
}
function Register-Mof {
param([string]$strFile)
$foundComp = $false
$foundMof = $false
foreach ($drive in (Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Root -match '^\w:\\$' })) {
$mofCompPath = "$($drive.Root)Windows\System32\wbem\mofcomp.exe"
if (Test-Path -Path $mofCompPath -PathType Leaf) {
$foundComp = $true
$strMofExePath = $mofCompPath
$mofPath = "$($drive.Root)Windows\System32\wbem\$strFile"
if (Test-Path -Path $mofPath -PathType Leaf) {
$foundMof = $true
$strOWmi = $mofPath
$output = & $strMofExePath $strOWmi
Write-Host $output
Invoke-QuitExit
}
}
}
if ($foundComp -ne $true) {
Invoke-GlobalPopFailure -strFailure "$script:MSG_FILENOTFOUND$($script:STR_SYS32PATH.Replace(':', ''))wbem\mofcomp.exe" -boolQuit $true
}
else {
if ($foundMof -ne $true) {
Invoke-GlobalPopFailure -strFailure "$script:MSG_FILENOTFOUND$($script:STR_SYS32PATH.Replace(':', ''))wbem\osppwmi.mof" -boolQuit $true
}
}
}
function Show-Processing {
Write-Host $script:MSG_PROCESSING
Write-Host $script:MSG_SEPERATE
}
function Get-ScriptEngine {
$hostName = $Host.Name
# PowerShell does not have the same cscript/wscript distinction
# but we should ensure we are running in a console host
if ($hostName -ne "ConsoleHost") {
$wshShell = New-Object -ComObject WScript.Shell
$wshShell.Popup("Unable to perform operation. $($MyInvocation.ScriptName) requires a console host.`rRun from PowerShell console.", 0, $PSCommandPath, $script:VALUE_ICON_WARNING)
exit
}
}
function Show-IePopUp {
param([string]$strPath)
try {
$objExplorer = New-Object -ComObject InternetExplorer.Application
$objExplorer.Navigate($strPath)
$objExplorer.ToolBar = 0
$objExplorer.StatusBar = 0
$objExplorer.Width = 1000
$objExplorer.Height = 593
$objExplorer.Left = 1
$objExplorer.Top = 1
$objExplorer.Visible = 1
}
catch {
# Silently ignore COM startup failures and continue
}
}
function Invoke-QuitExit {
Write-Host $script:MSG_SEPERATE
Write-Host $script:MSG_EXIT
exit
}
function Invoke-GlobalPopSuccess {
param(
[string]$strSuccess,
[bool]$boolQuit
)
$wshShell = New-Object -ComObject WScript.Shell
if ($boolQuit -eq $true) {
$null = $wshShell.Popup($strSuccess, 0, $PSCommandPath, $script:wshOK + $script:VALUE_ICON_INFORMATION)
Invoke-QuitExit
}
else {
$null = $wshShell.Popup($strSuccess, 0, $PSCommandPath, $script:wshOK + $script:VALUE_ICON_INFORMATION)
}
}
function Invoke-GlobalPopFailure {
param(
[string]$strFailure,
[bool]$boolQuit
)
$wshShell = New-Object -ComObject WScript.Shell
if ($boolQuit -eq $true) {
$null = $wshShell.Popup($strFailure, 0, $PSCommandPath, $script:wshOK + $script:VALUE_ICON_WARNING)
Invoke-QuitExit
}
else {
$null = $wshShell.Popup($strFailure, 0, $PSCommandPath, $script:wshOK + $script:VALUE_ICON_WARNING)
}
}
#endregion
#region Error Handling Functions
function Get-ResourceFromXml {
param([string]$resource)
# Save current error state - this function should not affect $Error
$savedErrorCount = $Error.Count
try {
[xml]$xmlDoc = Get-Content -Path "$script:currentDir\slerror.xml" -ErrorAction SilentlyContinue
if ($xmlDoc) {
$node = $xmlDoc.SelectSingleNode("//$resource")
if ($node) {
$script:globalResource = $node.InnerText
}
}
}
catch {
# Ignore errors from XML lookup
}
# Remove any errors added by this function to preserve original error state
while ($Error.Count -gt $savedErrorCount) {
$Error.RemoveAt(0)
}
}
function Invoke-SppErrHandle {
param([string]$strCommand)
$lastErr = $Error[0]
$errNumber = 0
if ($lastErr) {
# Prefer InnerException.HResult as it contains the actual WMI/COM error code
# The outer Exception.HResult is often a generic CLR exception wrapper
if ($lastErr.Exception.InnerException -and $lastErr.Exception.InnerException.HResult) {
$errNumber = $lastErr.Exception.InnerException.HResult
}
elseif ($lastErr.Exception.HResult) {
$errNumber = $lastErr.Exception.HResult
}
}
$script:globalErr = "{0:X}" -f $errNumber
if ($errNumber -eq 0) {
switch ($strCommand) {
{ $_ -in "/act", "/tokact", "/actsub", "/actp" } {
Write-Host $script:MSG_ACTSUCCESS
}
"/inpkey" {
Write-Host $script:MSG_KEYINSTALLSUCCESS
Invoke-QuitExit
}
"/inslic" {
Write-Host $script:MSG_INSTALLLICSUCCESS
Invoke-QuitExit
}
{ $_ -in "/ckms-domain", "/skms-domain", "/actype", "/sethst", "/setprt", "/remhst", "/stokflag", "/ctokflag", "/cachst" } {
Write-Host $script:MSG_SUCCESS
Invoke-QuitExit
}
"/rtokil" {
Write-Host "$script:MSG_REMILID$($script:strValue.ToUpper())"
Invoke-QuitExit
}
"/unpkey" {
Write-Host $script:MSG_UNINSTALLKEYSUCCESS
Invoke-QuitExit
}
}
}
else {
Test-FileExistsWithMessage "$script:currentDir\slerror.xml"
Get-ResourceFromXml "err0x$script:globalErr"
if ($script:globalResource -eq "") {
if ($script:globalErr.Length -ne 8) {
Write-Host "$script:MSG_ERRDESC$script:MSG_ERRUNKNOWN (0x$script:globalErr)"
}
else {
if ($script:foundSlUi -eq $true) {
Write-Host "${script:MSG_ERRCODE}0x$script:globalErr"
Write-Host "${script:MSG_ERRDESC}Run the following: powershell ospp.ps1 /ddescr:0x$script:globalErr"
}
else {
Write-Host "${script:MSG_ERRCODE}0x$script:globalErr"
}
}
if ($strCommand -ne "/act" -and $strCommand -ne "/actsub" -and $strCommand -ne "/actp") {
Invoke-QuitExit
}
}
else {
Write-Host "${script:MSG_ERRCODE}0x$script:globalErr"
Write-Host "${script:MSG_ERRDESC}$script:globalResource"
}
if ($strCommand -eq "/dtokcerts" -or $strCommand -eq "/ignore") {
Invoke-QuitExit
}
}
if ($script:globalErr -eq "C004F074") {
Write-Host "To view the activation event history run: powershell $($MyInvocation.ScriptName) /dhistorykms"
}
if ($strCommand -eq "/act" -and $script:globalErr -ne "0") {
# If a KB article is found, show the KB link
Find-KBArticle $script:globalErr
}
$script:globalResource = ""
$script:globalErr = ""
$Error.Clear()
}
function Invoke-WmiErrHandle {
$lastErr = $Error[0]
$errNumber = 0
if ($lastErr) {
if ($lastErr.Exception.HResult) {
$errNumber = $lastErr.Exception.HResult
}
}
if ($errNumber -ne 0) {
switch ($errNumber) {
424 {
Invoke-GlobalPopFailure -strFailure "$script:MSG_ERRCODE$errNumber`r$script:MSG_ERRDESC$script:MSG_CREDENTIALFAILURE" -boolQuit $true
}
default {
if ($lastErr.Exception.Message -ne "") {
Invoke-GlobalPopFailure -strFailure "$script:MSG_ERRCODE$errNumber`r$script:MSG_ERRDESC$($lastErr.Exception.Message)" -boolQuit $true
}
else {
Invoke-GlobalPopFailure -strFailure "An error occurred while making the connection.`r$script:MSG_ERRCODE$errNumber" -boolQuit $true
}
}
}
}
}
#endregion
#region WMI Functions
function Connect-WMI {
param(
[string]$strMachine,
[string]$strUser,
[string]$strPassword,
[string]$ctype
)
$Error.Clear()
# Store connection parameters globally for later WMI queries
$script:strMachine = $strMachine
$script:strUser = $strUser
$script:strPassword = $strPassword
if ($ctype -eq "") {
if ([string]::IsNullOrEmpty($strMachine) -or $strMachine.ToLower() -eq $script:strLocal.ToLower()) {
# Local machine - just verify WMI is accessible
$null = Get-WmiObject -Class __PROVIDER -Namespace "root\cimv2" -ErrorAction SilentlyContinue
$script:strMachine = ""
}
else {
if ([string]::IsNullOrEmpty($strUser) -and [string]::IsNullOrEmpty($strPassword)) {
$null = Get-WmiObject -Class __PROVIDER -ComputerName $strMachine -Namespace "root\cimv2" -ErrorAction SilentlyContinue
}
else {
try {
$secPassword = ConvertTo-SecureString $strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($strUser, $secPassword)
$null = Get-WmiObject -Class __PROVIDER -ComputerName $strMachine -Credential $credential -Namespace "root\cimv2" -ErrorAction Stop
}
catch {
$script:wmiErr = "{0:X}" -f $_.Exception.HResult
if ($script:wmiErr.Length -eq 8) {
Get-Description "0x$script:wmiErr" "wmi"
}
}
}
}
}
else {
if (![string]::IsNullOrEmpty($strUser)) {
Invoke-GlobalPopFailure -strFailure $script:MSG_CREDENTIALERR -boolQuit $true
}
if ([string]::IsNullOrEmpty($strMachine) -or $strMachine.ToLower() -eq $script:strLocal.ToLower()) {
$script:objWMI1 = [wmiclass]"\\.\root\default:StdRegProv"
$script:strMachine = ""
}
else {
$script:objWMI1 = [wmiclass]"\\$strMachine\root\default:StdRegProv"
}
}
Invoke-WmiErrHandle
Set-WinOS
}
function Set-WinOS {
$wmiParams = @{
Class = "Win32_OperatingSystem"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$os = Get-WmiObject @wmiParams
if ($null -eq $os) {
Invoke-GlobalPopFailure -strFailure "Unable to determine OS version via WMI." -boolQuit $true
}
$ver = $os.Version.Split('.')
# Win8/Server2012 (for compatibility checks)
if ($ver[0] -eq "6" -and $ver[1] -eq "2") {
}
Set-WmiClasses
}
function Set-WmiClasses {
# Win8+ only - use SoftwareLicensingProduct
$script:productClass = "SoftwareLicensingProduct"
$script:tokenClass = "SoftwareLicensingTokenActivationLicense"
}
function Invoke-ExecuteQuery {
param(
[string]$strSelect,
[string]$strWhere,
[string]$strClass
)
$Error.Clear()
$wmiParams = @{
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
if ([string]::IsNullOrEmpty($strWhere)) {
$wmiParams['Query'] = "SELECT $strSelect FROM $strClass"
}
else {
$wmiParams['Query'] = "SELECT $strSelect FROM $strClass WHERE $strWhere"
}
$script:productinstances = Get-WmiObject @wmiParams
Invoke-SppErrHandle ""
}
#endregion
#region Token Activation Functions
function Get-TkaSigner {
$Error.Clear()
try {
# Win8+ only - use SPPWMI
$signer = New-Object -ComObject "SPPWMI.SppWmiTokenActivationSigner"
return $signer
}
catch {
$errHex = "{0:X}" -f $_.Exception.HResult
if ($errHex -eq "80020009") {
Invoke-GlobalPopFailure -strFailure "${script:MSG_ERRCODE}0x${errHex}`r${script:MSG_ERRDESC}$($_.Exception.Message)" -boolQuit $true
}
}
}
function Write-TkaCertificate {
param([string]$strThumbprint)
$arrParams = $strThumbprint.Split('|')
# Guard array access when the thumbprint payload is incomplete
if ($arrParams.Count -ge 5) {
Write-Host "Thumbprint: $($arrParams[0])"
Write-Host "Subject: $($arrParams[1])"
Write-Host "Issuer: $($arrParams[2])"
$dtParsed = $null
if ([DateTime]::TryParse($arrParams[3], [ref]$dtParsed)) {
Write-Host "Valid From: $($dtParsed.ToString('d'))"
} else {
Write-Host "Valid From: $($arrParams[3])"
}
if ([DateTime]::TryParse($arrParams[4], [ref]$dtParsed)) {
Write-Host "Valid To: $($dtParsed.ToString('d'))"
} else {
Write-Host "Valid To: $($arrParams[4])"
}
Write-Host $script:MSG_SEPERATE
}
}
#endregion
#region Registry Functions
function Test-RegRights {
param(
[object]$wmiObject,
[string]$strKeyPath
)
$result = $wmiObject.CheckAccess($script:HKEY_LOCAL_MACHINE, $strKeyPath, $script:KEY_SET_VALUE)
if ($result.bGranted -ne $true) {
Invoke-GlobalPopFailure -strFailure "$script:MSG_NOREGRIGHTS`r$script:MSG_ISCMD_ELEVATED" -boolQuit $true
}
}
function Set-RegValue {
param(
[object]$wmiObject,
[int]$opsValue,
[string]$strValueName
)
$Error.Clear()
# Win8+ uses REG_SPP
$strKeyPath = $script:REG_SPP
switch ($strValueName) {
"UserOperations" {
$null = $wmiObject.CreateKey($script:HKEY_LOCAL_MACHINE, $strKeyPath)
$null = $wmiObject.SetDWORDValue($script:HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $opsValue)
}
}
Invoke-WmiErrHandle
Write-Host $script:MSG_SUCCESS
Invoke-QuitExit
}
function Invoke-PerformRegAction {
param([string]$strCommand)
$Error.Clear()
# Win8+ only - check registry rights for SPP
Test-RegRights $script:objWMI1 $script:REG_SPP
switch ($strCommand) {
"/puserops" {
Set-RegValue $script:objWMI1 1 "UserOperations"
}
"/duserops" {
Set-RegValue $script:objWMI1 0 "UserOperations"
}
}
}
#endregion
#region Service Functions
function Invoke-PerformServiceAction {
param([string]$strCommand)
$Error.Clear()
# Build WMI params with optional remote computer and credentials
$svcWmiParams = @{
Class = "Win32_Service"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$svcWmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$svcWmiParams['Credential'] = $credential
}
}
$services = Get-WmiObject @svcWmiParams
$installed = $false
foreach ($service in $services) {
if ($service.Name -eq "osppsvc") {
$installed = $true
break
}
}
if ($installed -ne $true) {
Invoke-GlobalPopFailure -strFailure $script:MSG_OSPPSVC_NOINSTALL -boolQuit $true
}
if ($strCommand -eq "/osppsvcauto") {
$services = Get-WmiObject @svcWmiParams -Filter "StartMode = 'Manual' or StartMode = 'Disabled'"
$foundOsppNonAuto = $false
foreach ($service in $services) {
if ($service.Name.ToLower() -eq "osppsvc") {
$foundOsppNonAuto = $true
$null = $service.Change($null, $null, $null, $null, "Automatic")
Start-Sleep -Seconds 15
break
}
}
if ($foundOsppNonAuto -ne $true) {
Write-Host "Service startup type already set to automatic: Office Software Protection Platform"
Invoke-QuitExit
}
$services = Get-WmiObject @svcWmiParams -Filter "StartMode = 'Auto'"
$foundOsppAuto = $false
foreach ($service in $services) {
if ($service.Name.ToLower() -eq "osppsvc") {
$foundOsppAuto = $true
Write-Host "Successfully set service startup to automatic:$($service.DisplayName)"
Invoke-QuitExit
}
}
if ($foundOsppAuto -ne $true) {
Write-Host "Unsuccessful setting service startup to automatic. $script:MSG_ISCMD_ELEVATED"
Invoke-QuitExit
}
}
else {
$services = Get-WmiObject @svcWmiParams
foreach ($service in $services) {
if ($service.Name.ToLower() -eq "osppsvc") {
switch ($service.State.ToLower()) {
"running" {
$null = $service.StopService()
Start-Sleep -Seconds 15
$null = $service.StartService()
Start-Sleep -Seconds 15
}
default {
$null = $service.StartService()
Start-Sleep -Seconds 15
}
}
break
}
}
$services = Get-WmiObject @svcWmiParams
foreach ($service in $services) {
if ($service.Name.ToLower() -eq "osppsvc") {
if ($service.State.ToLower() -eq "running") {
Write-Host "Successfully restarted: $($service.DisplayName)"
Invoke-QuitExit
}
else {
Write-Host "Unsuccessful restart: $($service.DisplayName). Status: $($service.State). $script:MSG_ISCMD_ELEVATED"
Invoke-QuitExit
}
break
}
}
}
}
function Invoke-ReARM {
param([string]$skuid)
$progFiles = $env:ProgramFiles
$rearmPath = ""
if (Test-Path -Path "$progFiles$script:STR_OSPPREARMPATH" -PathType Leaf) {
$rearmPath = "$progFiles$script:STR_OSPPREARMPATH"
}
elseif (Test-Path -Path "$progFiles$script:STR_OSPPREARMPATH_DEBUG" -PathType Leaf) {
$rearmPath = "$progFiles$script:STR_OSPPREARMPATH_DEBUG"
}
else {
$progFilesX86 = ${env:ProgramFiles(x86)}
if (Test-Path -Path "$progFilesX86$script:STR_OSPPREARMPATH" -PathType Leaf) {
$rearmPath = "$progFilesX86$script:STR_OSPPREARMPATH"
}
elseif (Test-Path -Path "$progFilesX86$script:STR_OSPPREARMPATH_DEBUG" -PathType Leaf) {
$rearmPath = "$progFilesX86$script:STR_OSPPREARMPATH_DEBUG"
}
else {
# Check the script directory
$scriptDirectory = Split-Path -Parent $PSCommandPath
if (Test-Path -Path "$scriptDirectory$script:STR_OSPPREARMEXE" -PathType Leaf) {
$rearmPath = "$scriptDirectory$script:STR_OSPPREARMEXE"
}
else {
Write-Host "$script:MSG_FILENOTFOUND`OSPPREARM.EXE"
Invoke-QuitExit
}
}
}
if ([string]::IsNullOrEmpty($skuid)) {
$output = & $rearmPath
}
else {
$output = & $rearmPath $skuid
}
Write-Host $output
}
#endregion
#region Event Functions
function Get-Events {
param(
[string]$strMessage,
[string]$strLog,
[string]$strEventCode,
[string]$strSource,
[string]$strMachine
)
Write-Host "$script:MSG_SEARCHFOR$strMessage<<<<< Log: $strLog Source: $strSource Event: $strEventCode >>>>>"
Write-Host $script:MSG_SEPERATE
$wmiParams = @{
Query = "Select * from Win32_NTLogEvent Where Logfile = '$strLog' and EventCode = '$strEventCode' and SourceName = '$strSource'"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$events = Get-WmiObject @wmiParams
if ($events -and @($events).Count -gt 0) {
Write-Host $script:MSG_SEPERATESMALL
foreach ($event in $events) {
$strTimeWritten = WMIDateStringToDate $event.TimeWritten
Write-Host "Coordinated Universal Time Written: $strTimeWritten"
Write-Host $event.Message
Write-Host $script:MSG_SEPERATESMALL
}
Write-Host $script:MSG_SEPERATE
}
else {
Write-Host $script:MSG_NOEVENTS
Write-Host $script:MSG_SEPERATE
}
}
function Get-MachineId {
param([string]$strMachine)
$wmiParams = @{
Class = "Win32_ComputerSystemProduct"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$instances = Get-WmiObject @wmiParams
foreach ($instance in $instances) {
Write-Host "MachineID: $($instance.uuid)"
Write-Host $script:MSG_SEPERATE
}
}
function Get-HeartbeatXml {
param([string]$strMachine)
$Error.Clear()
if (![string]::IsNullOrEmpty($strMachine)) {
Write-Host $script:MSG_HEARTBEAT_LOCALONLY
}
else {
try {
$shell = New-Object -ComObject Shell.Application
$appDataPath = $shell.Namespace(0x23).Self.Path
$heartbeatPath = "$appDataPath$script:STR_HEARTBEATPATH"
$fHeartBeat = $false
if (Test-Path -Path $heartbeatPath -PathType Leaf) {
$fHeartBeat = $true
[xml]$xmlDoc = Get-Content -Path $heartbeatPath
Write-Host "HeartbeatCache.xml found: $heartbeatPath"
Write-Host "Contents:"
Write-Host $script:MSG_SEPERATESMALL
$nodes = $xmlDoc.SelectNodes("//*")
foreach ($node in $nodes) {
if ($node.LocalName.ToLower() -ne "heartbeatcache") {
# lastchk & skuid are attribs of License node
if ($node.LocalName.ToLower() -eq "license") {
$hLastChk = $node.GetAttribute("lastCheckTime")
Write-Host "lastCheckTime: $hLastChk"
$hSkuId = $node.GetAttribute("skuId")
Write-Host "skuId: $hSkuId"
}
else {
Write-Host "$($node.LocalName): $($node.InnerText)"
}
}
}
}
if ($fHeartBeat -ne $true) {
Write-Host "$script:MSG_FILENOTFOUND`HeartbeatCache.xml"
}
}
catch {
Write-Host "$script:MSG_FILENOTFOUND`HeartbeatCache.xml"
}
}
Write-Host $script:MSG_SEPERATE
}
function Find-KBArticle {
param([string]$errorCode)
if ($script:errorKBs.Contains($errorCode)) {
Write-Host "${script:MSG_ACT_ERROR_FOUND_KB}0x$errorCode"
Write-Host "$script:MSG_ACT_ERROR_KB_LINK$errorCode"
}
}
#endregion
#region SCA Status Functions
function Test-ScaStatus {
Write-Host "$script:MSG_SEARCHFOR$script:MSG_SCAREGKEYS"
Write-Host $script:MSG_SEPERATE
$flavorsList = @(
$script:VALUE_SCAEXP_FLAVOR,
$script:VALUE_SCAEXP_OVERRIDE_FLAVOR,
$script:VALUE_SCAO15_FLAVOR,
$script:VALUE_SCA016_FLAVOR
)
$result = $false
foreach ($flavor in $flavorsList) {
$result = $result -or (Test-ScaStatusForFlavor $flavor)
}
if ($result -eq $true) {
Write-Host "Machine in SCA mode."
}
else {
Write-Host "Machine NOT in SCA mode."
}
}
function Test-ScaStatusForFlavor {
param([string]$flavor)
$Error.Clear()
$key = ""
$message = ""
$keyType = ""
switch ($flavor) {
$script:VALUE_SCAEXP_FLAVOR {
$key = $script:REG_SCAEXP_BASE
$message = $script:MSG_SCAEXP
$keyType = $script:VALUE_SCAREGKEY_PER_APP_TYPE
}
$script:VALUE_SCAEXP_OVERRIDE_FLAVOR {
$key = $script:REG_SCAEXP_OVERRIDE
$message = $script:MSG_SCAEXP_OVERRIDE
$keyType = $script:VALUE_SCAREGKEY_SINGLE_TYPE
}
$script:VALUE_SCAO15_FLAVOR {
$key = $script:REG_SCAO15
$message = $script:MSG_SCAO15
$keyType = $script:VALUE_SCAREGKEY_SINGLE_TYPE
}
$script:VALUE_SCA016_FLAVOR {
$key = $script:REG_SCAO16
$message = $script:MSG_SCAO16
$keyType = $script:VALUE_SCAREGKEY_SINGLE_TYPE
}
}
$result = $false
if ($keyType -eq $script:VALUE_SCAREGKEY_SINGLE_TYPE) {
$result = Read-AndReportScaKey $key $message
}
elseif ($keyType -eq $script:VALUE_SCAREGKEY_PER_APP_TYPE) {
$appsList = @(
"word",
"excel",
"powerpoint",
"visio",
"project",
"onenote",
"outlook",
"access",
"publisher",
"lync"
)
foreach ($app in $appsList) {
$keyPerApp = "$key$app$script:REG_SCAEXP_END"
$result = $result -or (Read-AndReportScaKey $keyPerApp $message)
}
}
return $result
}
function Read-AndReportScaKey {
param(
[string]$key,
[string]$message
)
$Error.Clear()
$result = $false
try {
$wshShell = New-Object -ComObject WScript.Shell
$keyValue = $wshShell.RegRead($key)
if ($keyValue -eq 1) {
Write-Host "$message$script:MSG_SCAREGKEY_ACTIVE"
$result = $true
}
else {
Write-Host "$message$script:MSG_SCAREGKEY_INACTIVE"
$result = $false
}
Write-Host $key
Write-Host $script:MSG_SEPERATESMALL
}
catch {
$result = $false
}
$Error.Clear()
return $result
}
#endregion
#region Licensing Action Functions
function Invoke-PerformLicAction {
param(
[string]$strCommand,
[string]$strValue,
[string]$strMachine
)
$Error.Clear()
# Store strValue globally for use by Invoke-SppErrHandle
$script:strValue = $strValue
if ($strCommand -eq "/dhistorykms" -or $strCommand -eq "/dhistoryacterr") {
Test-FileExistsWithMessage "$script:currentDir\slerror.xml"
if ($strCommand -eq "/dhistorykms") {
# 12288 = KMS Activation event id
$eventCode = "12288"
$strSrcEvents = $script:MSG_SEARCHEVENTSKMS
$strNoEvents = $script:MSG_NOEVENTSSKMS
}
else {
# 8200 = Internet Activation event id
$eventCode = "8200"
$strSrcEvents = $script:MSG_SEARCHEVENTSRET
$strNoEvents = $script:MSG_NOEVENTSRET
}
if (![string]::IsNullOrEmpty($strMachine)) {
Write-Host "$strSrcEvents$strMachine"
}
else {
Write-Host "$strSrcEvents$script:strLocal"
}
Write-Host "Event ID: $eventCode"
Write-Host ""
$wmiParams = @{
Query = "Select * from Win32_NTLogEvent Where Logfile = 'Application' and EventCode = '$eventCode'"
Namespace = "root\cimv2"
}
# Add the remote computer and optional credentials when provided
if (![string]::IsNullOrEmpty($strMachine)) {
$wmiParams['ComputerName'] = $strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$events = Get-WmiObject @wmiParams
if ($events -and @($events).Count -gt 0) {
foreach ($event in $events) {
if ($strCommand -eq "/dhistoryacterr") {
$strTimeWritten = WMIDateStringToDate $event.TimeWritten
Write-Host "Coordinated Universal Time Written: $strTimeWritten"
$strReplCrs = $event.Message.Replace("`r`n", "")
Write-Host "MESSAGE: $strReplCrs"
# Use the full message when it is shorter than the expected suffix length
if ($strReplCrs.Length -ge 10) {
$strhr10 = $strReplCrs.Substring($strReplCrs.Length - 10)
} else {
$strhr10 = $strReplCrs
}
Get-ResourceFromXml "err$strhr10"
if ($script:globalResource -eq "") {
if ($script:foundSlUi -eq $true) {
Write-Host "$script:MSG_ERRDESC`Run the following: powershell ospp.ps1 /ddescr:$strhr10"
}
else {
Write-Host "$script:MSG_ERRDESC`Not available."
}
}
else {
Write-Host "$script:MSG_ERRDESC$script:globalResource"
}
Write-Host $script:MSG_SEPERATE
}
else {
# Skip malformed messages that are too short for the expected slice
if ($event.Message.Length -ge 99) {
$strhr10 = $event.Message.Substring(89, 10)
} else {
continue
}
$strReplCrs = $event.Message.Replace("`r`n", "")
if ($strReplCrs.EndsWith(" 5")) {
$strReplStrs = $strReplCrs.Replace("The client has sent an activation request to the key management service machine.Info:", "")
$strTimeWritten = WMIDateStringToDate $event.TimeWritten
Write-Host "Coordinated Universal Time Written: $strTimeWritten"
$intColon = $strReplStrs.IndexOf(":")
# Clamp negative colon positions so Substring starts at the beginning
if ($intColon -lt 0) { $intColon = 0 }
$strErrHost = $strReplStrs.Substring(0, $intColon)
$strErrHost = $strErrHost.Trim()
$strErrHost = $strErrHost.Replace(":", "")
Write-Host "ERROR/HOST: $strErrHost"
switch ($strhr10) {
"0x00000000" {
Write-Host "$script:MSG_ERRDESC`N/A"
}
default {
Get-ResourceFromXml "err$strhr10"
if ($script:globalResource -eq "") {
if ($script:foundSlUi -eq $true) {
Write-Host "$script:MSG_ERRDESC`Run the following: powershell ospp.ps1 /ddescr:$strhr10"
# If a KB article is found, show the KB link
Find-KBArticle $strhr10.Substring($strhr10.Length - 8)
}
else {
Write-Host "$script:MSG_ERRDESC`Not available."
}
}
else {
Write-Host "$script:MSG_ERRDESC$script:globalResource"
# If a KB article is found, show the KB link
Find-KBArticle $strhr10.Substring($strhr10.Length - 8)
}
}
}
Write-Host $script:MSG_SEPERATE
}
}
}
}
else {
Write-Host $script:MSG_SEPERATE
if (![string]::IsNullOrEmpty($strMachine)) {
Write-Host "$strNoEvents$strMachine"
}
else {
Write-Host "$strNoEvents$script:strLocal"
}
Write-Host $script:MSG_SEPERATE
}
Invoke-QuitExit
}
# Get service object for certain operations (Win8+ only - SoftwareLicensingService)
$objOspp = $null
switch ($strCommand) {
{ $_ -in "/inpkey", "/dcmid", "/inslic", "/cachst", "/dstatus", "/dstatusall", "/dpid", "/dstatussub", "/pstatus" } {
$wmiParams = @{
Class = "SoftwareLicensingService"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$instances = Get-WmiObject @wmiParams
foreach ($service in $instances) {
$objOspp = $service
break
}
}
}
Invoke-SppErrHandle ""
if ($strCommand -eq "/inpkey") {
$Error.Clear()
try {
$null = $objOspp.InstallProductKey($strValue)
}
catch {
# Error will be captured in $Error and handled by Invoke-SppErrHandle
}
Invoke-SppErrHandle $strCommand
}
elseif ($strCommand -eq "/cachst") {
if ($strValue -eq "true") {
$null = $objOspp.DisableKeyManagementServiceHostCaching($false)
Invoke-SppErrHandle $strCommand
}
elseif ($strValue -eq "false") {
$null = $objOspp.DisableKeyManagementServiceHostCaching($true)
Invoke-SppErrHandle $strCommand
}
else {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTED A TRUE or FALSE value is required for: $strCommand" -boolQuit $true
}
}
elseif ($strCommand -eq "/dcmid") {
# Check if KMS key installed. If yes retrieve the SKUID value.
Invoke-ExecuteQuery "ID, ApplicationId, Description, Name" "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL" $script:productClass
foreach ($instance in $script:productinstances) {
Invoke-SppErrHandle ""
$script:intIsKms = if ($null -ne $instance.Description) { $instance.Description.ToUpper().IndexOf("KMS") } else { -1 }
if ($script:intIsKms -ne -1) {
$script:strSkuId = $instance.ID
break
}
}
if ($null -eq $script:strSkuId) {
Write-Host "$script:MSG_CMID$script:MSG_CMID_NOTFOUND"
Invoke-QuitExit
}
# Return the last Office KMS event containing the SKUID value for the installed KMS key.
# & retrieve the CMID value from the event.
$oKmsEventCounter = 0
$eventCode = "12288"
$wmiParams = @{
Query = "Select * from Win32_NTLogEvent Where Logfile = 'Application' and EventCode = '$eventCode'"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$events = Get-WmiObject @wmiParams
if ($events -and @($events).Count -gt 0) {
foreach ($event in $events) {
$oKmsEvent = $event.Message.IndexOf($script:strSkuId)
if ($oKmsEvent -ne -1) {
$oKmsEventCounter++
$parseEvntMsg1 = $event.Message.IndexOf(", ")
if ($parseEvntMsg1 -eq -1) { continue }
$parseEvntMsg2 = $event.Message.IndexOf(", ", $parseEvntMsg1 + 2)
if ($parseEvntMsg2 -eq -1) { continue }
$parseEvntMsg3 = $event.Message.IndexOf(", ", $parseEvntMsg2 + 2)
if ($parseEvntMsg3 -eq -1) { continue }
$parseEvntMsg4 = $event.Message.IndexOf(", ", $parseEvntMsg3 + 2)
if ($parseEvntMsg4 -eq -1) { continue }
$cmidValue = $event.Message.Substring($parseEvntMsg3 + 2, $parseEvntMsg4 - ($parseEvntMsg3 + 2))
Write-Host "$script:MSG_CMID$cmidValue"
break
}
}
}
if ($oKmsEventCounter -eq 0) {
Write-Host "$script:MSG_CMID$script:MSG_CMID_NOTFOUND"
}
Invoke-QuitExit
}
elseif ($strCommand -eq "/inslic") {
if ($strValue.EndsWith(".xrm-ms", [StringComparison]::OrdinalIgnoreCase)) {
Test-FileExistsWithMessage $strValue
Write-Host "$script:MSG_INSTALLLICENSE$strValue"
}
else {
Invoke-GlobalPopFailure -strFailure $script:MSG_UNRECOGFILE -boolQuit $true
}
$LicenseData = Read-AllTextFile $strValue
$null = $objOspp.InstallLicense($LicenseData)
Invoke-SppErrHandle $strCommand
}
elseif ($strCommand -eq "/stokflag") {
# Not supported
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTEDOPEROS7`r$strCommand" -boolQuit $true
}
elseif ($strCommand -eq "/ctokflag") {
# Not supported
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTEDOPEROS7`r$strCommand" -boolQuit $true
}
elseif ($strCommand -eq "/dtokils") {
$Error.Clear()
$objWmiDate = New-Object -ComObject "WBemScripting.SWbemDateTime"
$wmiParams = @{
Query = "SELECT ILID, ILVID, AuthorizationStatus, ExpirationDate, Description, AdditionalInfo FROM $script:tokenClass"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$tokenInstances = Get-WmiObject @wmiParams
$i = 0
foreach ($instance in $tokenInstances) {
Invoke-SppErrHandle ""
$i++
Write-Host "License ID (ILID): $($instance.ILID)"
Write-Host "Version ID (ILvID): $($instance.ILVID)"
if ($null -ne $instance.ExpirationDate) {
$objWmiDate.Value = $instance.ExpirationDate
if ($objWmiDate.GetFileTime($false) -ne 0) {
Write-Host "Expiry Date: $($objWmiDate.GetVarDate())"
}
}
if ($null -ne $instance.AdditionalInfo) {
Write-Host "Additional Info: $($instance.AdditionalInfo)"
}
if ($null -ne $instance.AuthorizationStatus -and $instance.AuthorizationStatus -ne 0) {
$script:globalErr = "{0:X}" -f $instance.AuthorizationStatus
Write-Host "$script:MSG_AUTHERR$script:globalErr"
Invoke-QuitExit
}
else {
Write-Host "Description: $($instance.Description)"
}
Write-Host $script:MSG_SEPERATE
}
if ($i -eq 0) {
Write-Host $script:MSG_NOLICENSEFOUND
}
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($objWmiDate) | Out-Null
Invoke-QuitExit
}
elseif ($strCommand -eq "/rtokil") {
$Error.Clear()
$wmiParams = @{
Query = "SELECT ILID, ID FROM $script:tokenClass"
Namespace = "root\cimv2"
}
if (![string]::IsNullOrEmpty($script:strMachine)) {
$wmiParams['ComputerName'] = $script:strMachine
if (![string]::IsNullOrEmpty($script:strUser) -and ![string]::IsNullOrEmpty($script:strPassword)) {
$secPassword = ConvertTo-SecureString $script:strPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($script:strUser, $secPassword)
$wmiParams['Credential'] = $credential
}
}
$tokenInstances = Get-WmiObject @wmiParams
$i = 0
foreach ($instance in $tokenInstances) {
Invoke-SppErrHandle ""
$i++
if ($strValue.ToLower() -eq $instance.ILID.ToLower()) {
$null = $instance.Uninstall()
Invoke-SppErrHandle $strCommand
}
else {
Write-Host "$script:MSG_NOTFOUNDILID$strValue Run /dtokils to display the ILID for installed licenses."
}
}
if ($i -eq 0) {
Write-Host $script:MSG_NOLICENSEFOUND
}
Invoke-QuitExit
}
elseif ($strCommand -eq "/dtokcerts") {
$Error.Clear()
$objSigner = Get-TkaSigner
Invoke-SppErrHandle $strCommand
Invoke-ExecuteQuery "ID, Name, ApplicationId, PartialProductKey, Description, LicenseIsAddon" "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL AND LicenseIsAddon = FALSE" $script:productClass
foreach ($instance in $script:productinstances) {
Invoke-SppErrHandle ""
$arrGrants = $null
try {
$null = $instance.GetTokenActivationGrants([ref]$arrGrants)
}
catch {
# Handle error below
}
if ($Error.Count -eq 0) {
try {
$arrThumbprints = $objSigner.GetCertificateThumbprints($arrGrants)
}
catch {
# Handle error below
}
if ($Error.Count -eq 0) {
foreach ($strThumbprint in $arrThumbprints) {
Write-TkaCertificate $strThumbprint
}
}
else {
Invoke-SppErrHandle ""
}
}
else {
Invoke-SppErrHandle ""
}
Write-Host $script:MSG_SEPERATE
$Error.Clear()
}
Invoke-QuitExit
}
elseif ($strCommand -eq "/tokact") {
$Error.Clear()
$objSigner = Get-TkaSigner
Invoke-SppErrHandle "/ignore"
# Parse thumbprint and pin from strValue
$pos1 = $strValue.IndexOf(":")
if ($pos1 -eq -1) {
$strThumbprint = $strValue
$strPin = ""
}
else {
$strThumbprint = $strValue.Substring(0, $pos1)
$strPin = $strValue.Substring($pos1 + 1)
}
Invoke-ExecuteQuery "ID, Name, ApplicationId, PartialProductKey, Description, LicenseIsAddon" "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL AND LicenseIsAddon = FALSE" $script:productClass
foreach ($instance in $script:productinstances) {
Invoke-SppErrHandle ""
Write-Host $script:MSG_TOKACTATTEMPT
Write-Host "$script:MSG_SKUID$($instance.ID)"
Write-Host "$script:MSG_LICENSENAME$($instance.Name)"
Write-Host "$script:MSG_DESCRIPTION$($instance.Description)"
Write-Host "$script:MSG_PARTIALKEY$($instance.PartialProductKey)"
$strChallenge = $null
try {
$null = $instance.GenerateTokenActivationChallenge([ref]$strChallenge)
}
catch {
# Handle error below
}
if ($Error.Count -eq 0) {
$strAuthInfo2 = $null
try {
$strAuthInfo1 = $objSigner.Sign($strChallenge, $strThumbprint, $strPin, [ref]$strAuthInfo2)
}
catch {
# Handle error below
}
if ($Error.Count -eq 0) {
try {
$null = $instance.DepositTokenActivationResponse($strChallenge, $strAuthInfo1, $strAuthInfo2)
}
catch {
# Handle error below
}
Invoke-SppErrHandle $strCommand
}
else {
Invoke-SppErrHandle ""
}
}
else {
Invoke-SppErrHandle ""
}
Write-Host $script:MSG_SEPERATE
}
Invoke-QuitExit
}
else {
$Error.Clear()
# Process commands that iterate over product instances
# Determine the appropriate query based on command
$strOptions = ""
if ($strCommand -eq "/dstatus") {
# Win8+ query with KMS-related fields
$strOptions = "ID, ApplicationId, EvaluationEndDate, PartialProductKey, Description, Name, LicenseStatus, LicenseStatusReason, ProductKeyID, ProductKeyID2, GracePeriodRemaining, KeyManagementServiceLookupDomain, VLActivationType, VLActivationTypeEnabled, ADActivationObjectName, ADActivationObjectDN, ADActivationCsvlkPid, ADActivationCsvlkSkuId, DiscoveredKeyManagementServiceMachineName, DiscoveredKeyManagementServiceMachinePort, VLActivationInterval, VLRenewalInterval, KeyManagementServiceMachine, KeyManagementServicePort"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
elseif ($strCommand -eq "/dstatusall") {
$strOptions = "ID, ApplicationId, EvaluationEndDate, PartialProductKey, Description, Name, LicenseStatus, LicenseStatusReason, ProductKeyID, ProductKeyID2, GracePeriodRemaining, KeyManagementServiceLookupDomain, VLActivationType, VLActivationTypeEnabled, ADActivationObjectName, ADActivationObjectDN, ADActivationCsvlkPid, ADActivationCsvlkSkuId, DiscoveredKeyManagementServiceMachineName, DiscoveredKeyManagementServiceMachinePort, VLActivationInterval, VLRenewalInterval, KeyManagementServiceMachine, KeyManagementServicePort"
$strWhere = "ApplicationId = '$script:OfficeAppId'"
}
elseif ($strCommand -eq "/dpid") {
$strOptions = "ID, ApplicationId, PartialProductKey, Description, Name, ProductKeyID, ProductKeyID2"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
elseif ($strCommand -eq "/dstatussub" -or $strCommand -eq "/pstatus") {
$strOptions = "ID, ApplicationId, EvaluationEndDate, PartialProductKey, Description, Name, ProductKeyID, ProductKeyID2, LicenseStatus, LicenseStatusReason, GracePeriodRemaining"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
elseif ($strCommand -eq "/dinstid") {
$strOptions = "ID, ApplicationId, PartialProductKey, Description, Name, OfflineInstallationId"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
elseif ($strCommand -eq "/unpkey") {
$strOptions = "ID, ApplicationId, Description, PartialProductKey, Name, ProductKeyID"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
elseif ($strCommand -in "/actype", "/skms-domain", "/ckms-domain") {
$strOptions = "ID, Description, PartialProductKey, ApplicationId"
$strWhere = "ApplicationId = '$script:OfficeAppId'"
}
elseif ($strCommand -in "/sethst", "/setprt", "/remhst") {
$strOptions = "ID, Description, PartialProductKey, ApplicationId"
$strWhere = "ApplicationId = '$script:OfficeAppId'"
}
elseif ($strCommand -in "/act", "/actsub", "/actp") {
$strOptions = "ID, ApplicationId, PartialProductKey, Description, Name"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
else {
# Default query for commands that work on products with a partial product key
$strOptions = "ID, ApplicationId, PartialProductKey, Description, Name, LicenseStatus"
$strWhere = "ApplicationId = '$script:OfficeAppId' AND PartialProductKey <> NULL"
}
Invoke-ExecuteQuery $strOptions $strWhere $script:productClass
$instanceCount = 0
$i = 0 # Counter for instances with installed keys
$y = 0 # Counter for unpkey matches
$strDisplayLicName = ""
$strDisplayLicDesc = ""
$script:foundCssKey = $false
foreach ($instance in $script:productinstances) {
Invoke-SppErrHandle ""
$instanceCount++
# Count only instances that have an installed partial product key
if (![string]::IsNullOrEmpty($instance.PartialProductKey)) {
$i++
}
$intIsKms = if ($null -ne $instance.Description) { $instance.Description.ToUpper().IndexOf("KMS") } else { -1 }
if ($intIsKms -ne -1) {
$script:kmsCounter++
}
$strDisplayLicName = $instance.Name
$strDisplayLicDesc = $instance.Description
if ($strCommand -eq "/dstatus" -or $strCommand -eq "/dstatusall") {
$getInstalled = $false
Test-FileExistsWithMessage "$script:currentDir\slerror.xml"
$licSr = "{0:X}" -f $instance.LicenseStatusReason
if ($strCommand -eq "/dstatusall") {
$getInstalled = $true
Write-Host "$script:MSG_SKUID$($instance.ID)"
Write-Host "$script:MSG_LICENSENAME$strDisplayLicName"
Write-Host "$script:MSG_DESCRIPTION$strDisplayLicDesc"
}
else {
# /dstatus - only show products with installed keys
if ($null -ne $instance.ProductKeyID -and $instance.ProductKeyID.Length -gt 0) {
$getInstalled = $true
Write-Host "$script:MSG_PID$($instance.ProductKeyID2)"
Write-Host "$script:MSG_SKUID$($instance.ID)"
Write-Host "$script:MSG_LICENSENAME$strDisplayLicName"
Write-Host "$script:MSG_DESCRIPTION$strDisplayLicDesc"
# Display EvaluationEndDate if present and not the default "no expiry" date
if (![string]::IsNullOrEmpty($instance.EvaluationEndDate)) {
$objDate = New-Object -ComObject "WBemScripting.SWbemDateTime"
$objDate.Value = $instance.EvaluationEndDate
if ($objDate.GetVarDate() -ne [DateTime]::new(1601, 1, 1)) {
Write-Host "$script:MSG_LICEXPIRY$($objDate.GetVarDate())"
}
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($objDate) | Out-Null
}
}
}
if ($getInstalled) {
switch ($instance.LicenseStatus) {
0 { Write-Host "$script:MSG_LICSTATUS$script:MSG_UNLICENSED" }
1 { Write-Host "$script:MSG_LICSTATUS$script:MSG_LICENSED" }
2 { Write-Host "$script:MSG_LICSTATUS$script:MSG_OOBGRACE" }
3 { Write-Host "$script:MSG_LICSTATUS$script:MSG_OOTGRACE" }
4 { Write-Host "$script:MSG_LICSTATUS$script:MSG_NONGENGRACE" }
5 { Write-Host "$script:MSG_LICSTATUS$script:MSG_NOTIFICATION" }
6 { Write-Host "$script:MSG_LICSTATUS$script:MSG_EXTENDEDGRACE" }
default { Write-Host "$script:MSG_LICSTATUS$script:MSG_LICUNKNOWN" }
}
if ($licSr -ne "0") {
if ($instance.LicenseStatus -ne 1) {
Write-Host "${script:MSG_ERRCODE}0x$licSr"
}
else {
Write-Host "${script:MSG_ERRCODE}0x${licSr}$script:MSG_INFO_ONLY"
}
Get-ResourceFromXml "err0x$licSr"
if ([string]::IsNullOrEmpty($script:globalResource)) {
if ($script:foundSlUi -ne $true) {
Write-Host "$script:MSG_ERRDESC`Not available."
}
else {
Write-Host "$script:MSG_ERRDESC`Run the following: powershell ospp.ps1 /ddescr:0x$licSr"
}
}
else {
Write-Host "$script:MSG_ERRDESC$script:globalResource"
}
}
if ($instance.GracePeriodRemaining -ne 0) {
$dGrace = $instance.GracePeriodRemaining / 60 / 24
$rndDown = [Math]::Floor($dGrace)
Write-Host "$script:MSG_REMAINGRACE$rndDown days ($($instance.GracePeriodRemaining) minute(s) before expiring)"
}
if ($null -ne $instance.PartialProductKey -and $instance.PartialProductKey.Length -gt 0) {
Write-Host "$script:MSG_PARTIALKEY$($instance.PartialProductKey)"
# Display additional volume info for KMS licenses
if ($intIsKms -ne -1) {
switch ($instance.VLActivationTypeEnabled) {
1 { Write-Host "$script:MSG_VLActivationType`AD" }
2 { Write-Host "$script:MSG_VLActivationType`KMS" }
3 { Write-Host "$script:MSG_VLActivationType`Token" }
default { Write-Host "$script:MSG_VLActivationType`ALL" }
}
# Check to see if last activated via AD - display object info
if ($instance.VLActivationType -eq 1) {
$script:isAdActivated = $true
Write-Host "${script:MSG_Act_Recent}AD"
Write-Host "`t$script:MSG_ADInfoAOName$($instance.ADActivationObjectName)"
Write-Host "`t$script:MSG_ADInfoAODN$($instance.ADActivationObjectDN)"
Write-Host "`t$script:MSG_ADInfoExtendedPid$($instance.ADActivationCsvlkPid)"
Write-Host "`t$script:MSG_ADInfoActID$($instance.ADActivationCsvlkSkuId)"
}
if ($script:isAdActivated -eq $false) {
$strKms = $instance.DiscoveredKeyManagementServiceMachineName
$strPort = $instance.DiscoveredKeyManagementServiceMachinePort
if ([string]::IsNullOrEmpty($strKms) -or $strPort -eq 0) {
Write-Host "`t$script:MSG_KMS_DNS_ERR"
}
else {
Write-Host "`t${script:MSG_KMS_DNS}${strKms}:${strPort}"
}
# Check to see if registry override is defined
$strKms = $instance.KeyManagementServiceMachine
if (![string]::IsNullOrEmpty($strKms)) {
$strPort = $instance.KeyManagementServicePort
if ($strPort -eq 0) {
$strPort = $script:MSG_DEFAULT_PORT
}
Write-Host "`t${script:MSG_HOST_REG_OVERRIDE}${strKms}:${strPort}"
}
Write-Host "`t$script:MSG_ACTIVATION_INTERVAL$($instance.VLActivationInterval) minutes"
Write-Host "`t$script:MSG_RENEWAL_INTERVAL$($instance.VLRenewalInterval) minutes"
if ($null -ne $objOspp -and $objOspp.KeyManagementServiceHostCaching -eq $true) {
Write-Host "`t${script:MSG_HOST_CACHING}Enabled"
}
else {
Write-Host "`t${script:MSG_HOST_CACHING}Disabled"
}
if (![string]::IsNullOrEmpty($instance.KeyManagementServiceLookupDomain)) {
Write-Host "`t$script:MSG_KMSLOOKUP$($instance.KeyManagementServiceLookupDomain)"
}
}
}
}
Write-Host $script:MSG_SEPERATE
}
}
elseif ($strCommand -eq "/dpid") {
# Show PID details only for subscription or perpetual keys with ProductKeyID
if ($null -ne $instance.ProductKeyID -and $instance.ProductKeyID.Length -gt 0) {
$intOccurSub = $instance.Name.ToLower().IndexOf("_sub")
$intOccurPerp = ($instance.Name.ToLower().IndexOf("_retail") -ne -1) -or ($instance.Name.ToLower().IndexOf("_perp") -ne -1)
if ($intOccurSub -ne -1 -or $intOccurPerp) {
Write-Host $script:MSG_SEPERATE
if ($intOccurSub -ne -1) {
$script:foundSubKey = $true
Write-Host $script:MSG_KEYSINSTALLED_SUB
}
if ($intOccurPerp) {
$script:foundPerpKey = $true
Write-Host $script:MSG_KEYSINSTALLED_PERP
}
Write-Host $script:MSG_SEPERATE
Write-Host "$script:MSG_SKUID$($instance.ID.ToUpper())"
Write-Host "$script:MSG_LICENSENAME$($instance.Name)"
Write-Host "$script:MSG_PARTIALKEY$($instance.PartialProductKey)"
Write-Host "$script:MSG_PID$($instance.ProductKeyID2)"
# Determine machinekey from PID (guard matches /dstatussub path)
if (![string]::IsNullOrEmpty($instance.ProductKeyID2)) {
$strPid2 = $instance.ProductKeyID2.Replace("-", "")
if ($strPid2.Length -ge 19) {
$strPid2 = $strPid2.Substring($strPid2.Length - 19)
$strGid = $strPid2.Substring(0, 5)
$strSerial1 = $strPid2.Substring(5, 3)
$strSerial2 = $strPid2.Substring(8, 6)
Write-Host "Machine Key: $strGid-$strSerial1-$strSerial2"
}
}
}
}
}
elseif ($strCommand -eq "/act") {
Write-Host $script:MSG_ACTATTEMPT
Write-Host "$script:MSG_SKUID$($instance.ID)"
Write-Host "$script:MSG_LICENSENAME$strDisplayLicName"
Write-Host "$script:MSG_DESCRIPTION$strDisplayLicDesc"
Write-Host "$script:MSG_PARTIALKEY$($instance.PartialProductKey)"
try {
$null = $instance.Activate()
} catch {
# Exception is expected on activation failure - error handling below will process it
}
Invoke-SppErrHandle $strCommand
Write-Host $script:MSG_SEPERATE
}
elseif ($strCommand -eq "/unpkey") {
if ($strValue.Length -ne 5) {
Invoke-GlobalPopFailure -strFailure $script:MSG_ERRPARTIALKEY -boolQuit $true
}
if ($null -ne $instance.PartialProductKey -and $instance.PartialProductKey.Length -gt 0) {
if ($strValue.ToUpper() -eq $instance.PartialProductKey.ToUpper()) {
$y++
Write-Host "$script:MSG_UNINSTALLKEY$strDisplayLicName"
# This WMI method operates on the current instance and takes no parameters.
$null = $instance.UninstallProductKey()
Invoke-SppErrHandle $strCommand
}
}
}
elseif ($strCommand -eq "/dinstid") {
if ($null -ne $instance.PartialProductKey -and $instance.PartialProductKey.Length -gt 0) {
Write-Host "Installation ID for: $($instance.Name): $($instance.OfflineInstallationId)"
Write-Host $script:MSG_SEPERATE
}
}
elseif ($strCommand -eq "/actcid") {
if ($null -ne $instance.PartialProductKey -and $instance.PartialProductKey.Length -gt 0) {
# Apply the confirmation ID before showing the result
$Error.Clear()
try {
$null = $instance.DepositOfflineConfirmationId($instance.OfflineInstallationId, $strValue)
}
catch {
# Error captured for handling below
}
if ($Error.Count -eq 0) {
if ($script:telSuccess -ne $true) {
Write-Host "$script:MSG_LICENSENAME$($instance.Name)"
Write-Host $script:MSG_OFFLINEACTSUCCESS
$script:telSuccess = $true
}
}
else {
Write-Host "$script:MSG_LICENSENAME$($instance.Name)"
Invoke-SppErrHandle ""
}
Write-Host $script:MSG_SEPERATE
}
}
elseif ($strCommand -eq "/actype") {
switch ($strValue) {
{ $_ -in "0", "1", "2", "3" } {
# Valid value
}
default {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTED A value of`r0 (for all)`r1 (for AD)`r2 (for KMS`r3 (for Token)`rIs required for: $strCommand" -boolQuit $true
}
}
# Only apply to KMS licenses
if ($intIsKms -ne -1) {
if ($strValue -ne "0") {
$null = $instance.SetVLActivationTypeEnabled($strValue)
}
else {
$null = $instance.ClearVLActivationTypeEnabled()
}
}
Invoke-SppErrHandle ""
}
elseif ($strCommand -eq "/skms-domain") {
# Only apply to KMS licenses
if ($intIsKms -ne -1) {
$null = $instance.SetKeyManagementServiceLookupDomain($strValue)
}
Invoke-SppErrHandle ""
}
elseif ($strCommand -eq "/ckms-domain") {
# Only apply to KMS licenses
if ($intIsKms -ne -1) {
$null = $instance.ClearKeyManagementServiceLookupDomain()
}
Invoke-SppErrHandle ""
}
elseif ($strCommand -eq "/sethst") {
# Only apply to KMS licenses
if ($intIsKms -ne -1) {
$null = $instance.SetKeyManagementServiceMachine($strValue)
}
Invoke-SppErrHandle ""
}
elseif ($strCommand -eq "/setprt") {
# Only apply to KMS licenses
if ($intIsKms -ne -1) {
$null = $instance.SetKeyManagementServicePort([int]$strValue)
}
Invoke-SppErrHandle ""
}
elseif ($strCommand -eq "/remhst") {
# Only apply to KMS licenses
if ($intIsKms -ne -1) {
$null = $instance.ClearKeyManagementServiceMachine()
Invoke-SppErrHandle ""
$null = $instance.ClearKeyManagementServicePort()
}
Invoke-SppErrHandle ""
}
elseif ($strCommand -eq "/actsub" -or $strCommand -eq "/actp") {
$intOccurSub = 0
$intOccurPerp = 0
$intOccurProduct = 0
$lowerName = $instance.Name.ToLower()
if ($strCommand -eq "/actsub") {
$intOccurSub = $lowerName.IndexOf("_sub")
if ($intOccurSub -lt 0) { $intOccurSub = 0 } else { $intOccurSub = $intOccurSub + 1 }
}
else {
# /actp
$intOccurSub = $lowerName.IndexOf("_sub")
if ($intOccurSub -lt 0) { $intOccurSub = 0 } else { $intOccurSub = $intOccurSub + 1 }
$retailIdx = $lowerName.IndexOf("_retail")
$perpIdx = $lowerName.IndexOf("_perp")
if ($retailIdx -ge 0 -or $perpIdx -ge 0) {
$intOccurPerp = 1
}
if ($intOccurSub -ne 0 -or $intOccurPerp -ne 0) {
$productIdx = $lowerName.IndexOf($strValue.ToLower())
if ($productIdx -ge 0) {
$intOccurProduct = $productIdx + 1
}
}
}
# Process subscription activation when a matching subscription or product entry is present
if (($strCommand -eq "/actsub" -and $intOccurSub -ne 0) -or $intOccurProduct -ne 0) {
$script:foundCssKey = $true
Write-Host $script:MSG_ACTATTEMPT
Write-Host "$script:MSG_SKUID$($instance.ID)"
Write-Host "$script:MSG_LICENSENAME$($instance.Name)"
Write-Host "$script:MSG_DESCRIPTION$($instance.Description)"
Write-Host "$script:MSG_PARTIALKEY$($instance.PartialProductKey)"
try {
$null = $instance.Activate()
} catch {
# Exception is expected on activation failure - error handling below will process it
}
Invoke-SppErrHandle $strCommand
Write-Host $script:MSG_SEPERATE
}
}
elseif ($strCommand -eq "/dstatussub" -or $strCommand -eq "/pstatus") {
$intOccurSub = 0
$intOccurPerp = 0
$intOccurProduct = 0
$script:dlicense = $true
Test-FileExistsWithMessage "$script:currentDir\slerror.xml"
$licSr = "{0:X}" -f $instance.LicenseStatusReason
if (![string]::IsNullOrEmpty($instance.ProductKeyID)) {
$lowerName = $instance.Name.ToLower()
if ($strCommand -eq "/dstatussub") {
$subIdx = $lowerName.IndexOf("_sub")
if ($subIdx -ge 0) { $intOccurSub = $subIdx + 1 }
}
else {
# /pstatus
$subIdx = $lowerName.IndexOf("_sub")
if ($subIdx -ge 0) { $intOccurSub = $subIdx + 1 }
$retailIdx = $lowerName.IndexOf("_retail")
$perpIdx = $lowerName.IndexOf("_perp")
if ($retailIdx -ge 0 -or $perpIdx -ge 0) {
$intOccurPerp = 1
}
if ($intOccurSub -ne 0 -or $intOccurPerp -ne 0) {
$productIdx = $lowerName.IndexOf($strValue.ToLower())
if ($productIdx -ge 0) {
$intOccurProduct = $productIdx + 1
if ($intOccurSub -ne 0) {
$script:getHeartBeat = $true
}
}
}
}
# Process subscription status when a matching subscription or product entry is present
if (($strCommand -eq "/dstatussub" -and $intOccurSub -ne 0) -or $intOccurProduct -ne 0) {
$script:foundCssKey = $true
Write-Host "$script:MSG_PID$($instance.ProductKeyID2)"
Write-Host "$script:MSG_SKUID$($instance.ID)"
Write-Host "$script:MSG_LICENSENAME$($instance.Name)"
Write-Host "$script:MSG_DESCRIPTION$($instance.Description)"
# EvaluationEndDate - avoid displaying 1/1/1601
if (![string]::IsNullOrEmpty($instance.EvaluationEndDate)) {
$evalDate = WMIDateStringToDate $instance.EvaluationEndDate
if ($evalDate -ne [DateTime]::new(1601, 1, 1)) {
Write-Host "$script:MSG_LICEXPIRY$evalDate"
}
}
switch ($instance.LicenseStatus) {
0 { Write-Host "$script:MSG_LICSTATUS$script:MSG_UNLICENSED" }
1 { Write-Host "$script:MSG_LICSTATUS$script:MSG_LICENSED" }
2 { Write-Host "$script:MSG_LICSTATUS$script:MSG_OOBGRACE" }
3 { Write-Host "$script:MSG_LICSTATUS$script:MSG_OOTGRACE" }
4 { Write-Host "$script:MSG_LICSTATUS$script:MSG_NONGENGRACE" }
5 { Write-Host "$script:MSG_LICSTATUS$script:MSG_NOTIFICATION" }
6 { Write-Host "$script:MSG_LICSTATUS$script:MSG_EXTENDEDGRACE" }
default { Write-Host "$script:MSG_LICSTATUS$script:MSG_LICUNKNOWN" }
}
if ($licSr -ne "0") {
if ($instance.LicenseStatus -ne 1) {
Write-Host "${script:MSG_ERRCODE}0x$licSr"
}
else {
Write-Host "${script:MSG_ERRCODE}0x$licSr$script:MSG_INFO_ONLY"
}
Get-ResourceFromXml "err0x$licSr"
if ([string]::IsNullOrEmpty($script:globalResource)) {
if ($script:foundSlUi -ne $true) {
Write-Host "${script:MSG_ERRDESC}Not available."
}
else {
Write-Host "${script:MSG_ERRDESC}Run the following: powershell ospp.ps1 /ddescr:0x$licSr"
}
}
else {
Write-Host "$script:MSG_ERRDESC$script:globalResource"
}
}
if ($instance.GracePeriodRemaining -ne 0) {
$dGrace = $instance.GracePeriodRemaining / 60 / 24
$rndDown = [math]::Floor($dGrace)
Write-Host "$script:MSG_REMAINGRACE$rndDown days ($($instance.GracePeriodRemaining) minute(s) before expiring)"
}
if (![string]::IsNullOrEmpty($instance.PartialProductKey)) {
Write-Host "$script:MSG_PARTIALKEY$($instance.PartialProductKey)"
}
if (![string]::IsNullOrEmpty($instance.ProductKeyID2)) {
$strPid2 = $instance.ProductKeyID2.Replace("-", "")
if ($strPid2.Length -ge 19) {
$strPid2 = $strPid2.Substring($strPid2.Length - 19)
$strGid = $strPid2.Substring(0, 5)
$strSerial1 = $strPid2.Substring(5, 3)
$strSerial2 = $strPid2.Substring(8, 6)
Write-Host "MACHINE KEY: $strGid-$strSerial1-$strSerial2"
}
}
Write-Host $script:MSG_SEPERATE
}
}
}
}
# Handle commands with no matching instances found
if ($strCommand -eq "/unpkey") {
if ($y -eq 0) {
Write-Host $script:MSG_KEYNOTFOUND
Invoke-QuitExit
}
}
elseif ($strCommand -eq "/dpid") {
# For /dpid, show "no keys" messages for sub and perp separately
if ($script:foundSubKey -ne $true) {
Write-Host $script:MSG_SEPERATE
Write-Host $script:MSG_NOKEYSINSTALLED_SUB
Write-Host $script:MSG_SEPERATE
}
if ($script:foundPerpKey -ne $true) {
Write-Host $script:MSG_SEPERATE
Write-Host $script:MSG_NOKEYSINSTALLED_PERP
Write-Host $script:MSG_SEPERATE
}
}
elseif ($strCommand -in "/ckms-domain", "/skms-domain", "/actype", "/sethst", "/setprt", "/remhst") {
# KMS-related commands require at least one KMS license
if ($script:kmsCounter -eq 0) {
Write-Host $script:MSG_NOKMSLICS
Invoke-QuitExit
}
else {
Invoke-SppErrHandle $strCommand
}
}
elseif ($strCommand -eq "/actsub" -or $strCommand -eq "/dstatussub" -or $strCommand -eq "/actp" -or $strCommand -eq "/pstatus") {
if ($script:foundCssKey -ne $true) {
Write-Host $script:MSG_NOKEYSINSTALLED
Write-Host $script:MSG_SEPERATE
}
}
else {
# For other commands, use the installed key count
if ($i -eq 0) {
if ($strCommand -eq "/dstatus" -or $strCommand -eq "/dstatusall") {
Write-Host $script:MSG_NOKEYSINSTALLED
Write-Host $script:MSG_SEPERATE
}
elseif ($strCommand -eq "/act") {
Write-Host $script:MSG_NOKEYSINSTALLED
Write-Host $script:MSG_SEPERATE
}
elseif ($strCommand -eq "/dinstid") {
Write-Host $script:MSG_NOKEYSINSTALLED
}
elseif ($strCommand -eq "/actcid") {
Write-Host $script:MSG_NOKEYSINSTALLED
}
}
}
if ($script:dlicense -eq $false) {
Invoke-QuitExit
}
}
}
#endregion
#region Main Function
function Invoke-Main {
param (
[string]$strCommand,
[string]$strMachine,
[string]$strUser,
[string]$strPassword,
[string]$strValue
)
$strCommand = $strCommand.ToLower()
# Handle commands that don't need WMI first
switch ($strCommand) {
{ $_ -in "/act", "/dstatus", "/dstatusall", "/dinstid", "/dtokils", "/remhst", "/stokflag", "/ctokflag", "/dcmid", "/dtokcerts", "/ckms-domain", "/dpid", "/actsub", "/dstatussub" } {
Connect-WMI $strMachine $strUser $strPassword ""
Invoke-PerformLicAction $strCommand "" $strMachine
if ($strCommand -eq "/dstatussub") {
Get-HeartbeatXml $strMachine
Invoke-QuitExit
}
}
"/dlicenseinfo" {
if (![string]::IsNullOrEmpty($strMachine)) {
Write-Host "$script:MSG_SEARCH_FORKEY$strMachine"
}
else {
Write-Host "$script:MSG_SEARCH_FORKEY$script:strLocal"
}
Write-Host $script:MSG_SEPERATE
$script:dlicense = $true
Connect-WMI $strMachine $strUser $strPassword ""
Invoke-PerformLicAction "/dstatusall" "" ""
Invoke-PerformLicAction "/dpid" "" $strMachine
Write-Host $script:MSG_SEPERATE
Get-MachineId $strMachine
Get-HeartbeatXml $strMachine
Get-Events $script:MSG_EVENT_2011 "Application" "2011" "Microsoft Office 15" $strMachine
# Display SPP related events (Win8+ only since we don't support Win7)
Get-Events $script:MSG_EVENT_1016 "Application" "1016" "Microsoft-Windows-Security-SPP" $strMachine
Get-Events $script:MSG_EVENT_1017 "Application" "1017" "Microsoft-Windows-Security-SPP" $strMachine
Get-Events $script:MSG_EVENT_1013 "Application" "1013" "Microsoft-Windows-Security-SPP" $strMachine
Get-Events $script:MSG_EVENT_8200 "Application" "1014" "Microsoft-Windows-Security-SPP" $strMachine
Write-Host $script:MSG_SEPERATE
Test-ScaStatus
Invoke-QuitExit
}
{ $_ -in "/dhistoryacterr", "/dhistorykms" } {
Connect-WMI $strMachine $strUser $strPassword ""
Invoke-PerformLicAction $strCommand "" $strMachine
}
{ $_ -in "/puserops", "/duserops" } {
Connect-WMI $strMachine $strUser $strPassword "reg"
Invoke-PerformRegAction $strCommand
}
{ $_ -in "/osppsvcrestart", "/osppsvcauto" } {
Connect-WMI $strMachine $strUser $strPassword ""
Invoke-PerformServiceAction $strCommand
}
{ $_ -in "/help", "help", "?", "/?" } {
$helpPath = Join-Path $script:currentDir "ospp.htm"
Test-FileExistsWithMessage $helpPath
Show-IePopUp $helpPath
Invoke-QuitExit
}
"/regmof" {
Register-Mof "osppwmi.mof"
}
"/rearm" {
if ([string]::IsNullOrEmpty($strMachine)) {
Invoke-ReARM ""
}
else {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTEDLOCAL`r$strCommand" -boolQuit $true
}
Invoke-QuitExit
}
"/version" {
Invoke-GlobalPopSuccess $script:VER_INFO $true
}
default {
# Handle commands with colon values like /inpkey:value, /unpkey:value, etc.
if (![string]::IsNullOrEmpty($strValue)) {
switch ($strCommand) {
{ $_ -in "/skms-domain", "/actype", "/inpkey", "/unpkey", "/inslic", "/actcid", "/sethst", "/setprt", "/ddescr", "/rtokil", "/tokact", "/cachst", "/rearm", "/pstatus", "/actp" } {
if ($strCommand -eq "/ddescr") {
if ($strValue.StartsWith("0x")) {
Get-Description $strValue ""
}
else {
Write-Host $script:MSG_ERRCODEVALUE
Invoke-QuitExit
}
}
elseif ($strCommand -eq "/rearm") {
if ([string]::IsNullOrEmpty($strMachine)) {
Invoke-ReARM $strValue
}
else {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTEDLOCAL`r$strCommand" -boolQuit $true
}
Invoke-QuitExit
}
else {
Connect-WMI $strMachine $strUser $strPassword ""
Invoke-PerformLicAction $strCommand $strValue ""
if ($strCommand -eq "/pstatus" -and $script:getHeartBeat -eq $true) {
Get-HeartbeatXml $strMachine
}
Invoke-QuitExit
}
}
default {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTED" -boolQuit $true
}
}
}
else {
# Check if command requires a value (has colon but empty value)
if ($strCommand -in "/skms-domain", "/actype", "/inpkey", "/unpkey", "/inslic", "/actcid", "/sethst", "/setprt", "/ddescr", "/rtokil", "/tokact", "/cachst", "/rearm", "/pstatus", "/actp") {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTED A value is required for: $strCommand" -boolQuit $true
}
else {
Invoke-GlobalPopFailure -strFailure "$script:MSG_UNSUPPORTED" -boolQuit $true
}
}
}
}
}
#endregion
#region Script Entry Point
# Record the script directory without changing the process working directory
$script:currentDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$strArg = ""
$strMachine = ""
$strUser = ""
$strPassword = ""
# Parse command line arguments: command, machine, user, password
if ($args.Count -ge 1) {
$strArg = $args[0]
}
if ($args.Count -ge 2) {
$strMachine = $args[1]
}
if ($args.Count -ge 3) {
$strUser = $args[2]
}
if ($args.Count -ge 4) {
$strPassword = $args[3]
}
if ($strArg.Length -lt 1) {
# No command specified; show the help file
$helpPath = Join-Path $script:currentDir "ospp.htm"
Test-FileExistsWithMessage $helpPath
Show-IePopUp $helpPath
exit
}
# Ensure the script is running in a console host
Get-ScriptEngine
# Display the processing header
Show-Processing
# Initialize the SLUI path lookup
Get-SluiPath | Out-Null
$script:strLocal = $env:COMPUTERNAME
# Handle commands with embedded values (e.g., /inpkey:XXXXX-XXXXX-XXXXX-XXXXX-XXXXX)
$strValue = ""
if ($strArg.Contains(":")) {
$colonPos = $strArg.IndexOf(":")
$strCommand = $strArg.Substring(0, $colonPos)
$strValue = $strArg.Substring($colonPos + 1)
$strArg = $strCommand
}
Invoke-Main $strArg $strMachine $strUser $strPassword $strValue
#endregion
# SIG # Begin signature block
# MIIngAYJKoZIhvcNAQcCoIIncTCCJ20CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBgbtVgGTe21r44
# eRMp0adQiFf2kpjsUkAKP2lPWUVBG6CCDMkwggYEMIID7KADAgECAhMzAAACHPrN
# xZvoL37EAAAAAAIcMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD
# b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQxWhcNMjcwNDE1MTg1
# OTQxWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD
# VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDVsZfgOKmM31HPfoWOoNEiw0SlCiIxUMC0I9NMWbucKOw/e9lP
# oAoehQVu6SG65V4EPzrYsnBnFPNoi4/HoOdjhz1qkrEt4I6tEcxXU6oOeY9zGveC
# /3iBeuhLYxM3M/PkcUoebF+Nednm8OkdSPoDu8imViHPQq/8CQUu0WRR4rE+dMRf
# rpVqfmNi2qWCX94T4MsepijGVkwE//tJg0ryAiYdHT34LSnlG/RSBZmQRGWZ5g8j
# qnKjRParSqMft1gvjuUTVgtWNZfgcLFSK5Wa0myrq8OPcgTGGsRgun+tnSS+IxDT
# xVsAPH1OzvPjwomguByhUe/OcvUN0D5Wmp7xAgMBAAGjggGqMIIBpjAOBgNVHQ8B
# Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O
# BBYEFNoH7a2YDjOSwpkp6DHcmUS7J+0yMFQGA1UdEQRNMEukSTBHMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxFjAUBgNVBAUT
# DTIzMDAxMis1MDc1NjkwHwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEw
# YAYDVR0fBFkwVzBVoFOgUYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9jcmwvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy
# bDBtBggrBgEFBQcBAQRhMF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmcl
# MjBQQ0ElMjAyMDI0LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IC
# AQAUnEqhaRXe0T3hIJjvdQErEkrA/7bByjn6t5IArODkkRjzkYwtKMc2yYj2quaN
# rLutWw2YZcngKPy1b71YyDJQTy4NDRwaSh9Tw5thrk3NmcPrAHia5vtcBJ1CgtKK
# 7mQbIcQ22d/N3813ayCDDFewu1+jsZmX+r/aTEqaOM4TVxVtRSkuCy8nAXKuChOK
# Li/zA4XuH8iEYqIsj2YoNaeSxVmeGiERXpKdo3dDmYi0kO5w2D8VS4c3+9h6gElY
# BaAAg/dYErBg27qT3vv0zRDJhJufvCNylA8S7/+8H5E/PV5cng6na9VV/w9OV3qu
# uND6zdGa2EX38Glp50F9AIQk3p2xXmcvorDeM4XJ7UlWYBi6g80J1SSOQnInCYFE
# msfUNn3+1AaTJKSJL83quKArTac2pKhu0Yzzzrzo6HrsRiQKzpnRBb1/dMa6P3hz
# 75XbMRBctNsFhZC07WCmjExdLg2eHW5uV0TY8D5+6wozJf7vF3+WHkYPO85Z+BC6
# U4FkNbYNycZ9cE4j1tXRdyDCfml6c0HWPHjNVDObrv9lKt3qUqFpX38VCqVCyNOO
# 1UcXfQiVjJw32U2WUKZjt/neJKHEBsm9kFsLuWzkQ53+qcaSaytmsCnk2gOglrlD
# 5d3kKyvvAw+rzm0lT8K38P6PLxfZQHhu4W8dV7Av8N2ZmDCCBr0wggSloAMCAQIC
# EzMAAAA5O7Y3Gb8GHWcAAAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS
# b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoX
# DTM2MDMyMjIyMTMwNFowVzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ
# Q0EgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeq
# lRYHNa265v4IY9fH8TKhemHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo
# 0dtS/EW6I/yEL/bLSY8hKpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATv
# QVL4tcf03aTycsz8QeCdM0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a
# 1uv1zerOYMnsneRRwCbpyW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1
# FyQfK0fVkaya8SmVHQ/tOf23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfO
# GSWHIIV4YrTJTT6PNty5REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7
# ttOu1bVnXfHaqPYl2rPs20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJ
# uz2MXMCt7iw7lFPG9LXKGjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxS
# CwyoGIq0PhaA7Y+VPct5pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOm
# VQop36wUVUYklUy++vDWeEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3
# SkE/xIkgpfl22MM1itkZ35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8E
# BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPX
# LQaUEggxMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMB
# Af8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBP
# oE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
# TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAw
# TgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMv
# TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOC
# AgEAFJQfOChP7onn6fLIMKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D
# 5W4wMwYeLystcEqfkjz4NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBY
# nbu0+THSuVHTe0VTTPVhily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSI
# vgn0JksVBVMYVI5QFu/qhnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6
# aR9y34aiM1qmxaxBi6OUnyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4w
# PKC5OmHm1DQIt/MNokbbH3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7
# RTX8AdBPo0I6OEojf39zuFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK
# /fg8B2qjW88MT/WF5V5uvZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSK
# YBv0VisCzfxgeU+dquXW9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkw
# YTu/9dLeH2pDqeJZAABVDWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVT
# Ql0v4q8J/AUmQN5W4n101cY2L4A7GTQG1h32HHAvfQESWP0xghoNMIIaCQIBATBu
# MFcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# KDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIc
# +s3Fm+gvfsQAAAAAAhwwDQYJYIZIAWUDBAIBBQCggcAwGQYJKoZIhvcNAQkDMQwG
# CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI
# hvcNAQkEMSIEIIMHHQ5sLgGf+zKJELM1+Nj4AIna0iGxBHlD5bTaMhQvMFQGCisG
# AQQBgjcCAQwxRjBEoCKAIABNAGkAYwByAG8AcwBvAGYAdAAgAE8AZgBmAGkAYwBl
# oR6AHGh0dHA6Ly9vZmZpY2UubWljcm9zb2Z0LmNvbSAwDQYJKoZIhvcNAQEBBQAE
# ggEAZxX2nBpmVk2dTnqFGo1rxfGjtcphTr70BD6Ah6oF1EjoNr9vnO3qM4XF5R0j
# rkqwc+v69UM+DzPNC1j+L5GczDDb/n5eGL7Tbobie8w7YLlhp4hsnv++ORwVnMeh
# ONSw8Cno0Ari1eRxuCEmx8EP1YBh/3UAo7sAFxbSUWOmcwr99m7QzPtUPDKMJRml
# W6CSIxi6TB/Yc7Pi+cGiJxfJlUo6gM0aCXXt6Qd4nBVzuV7T3l5LZxjcKhCmcQL6
# wruI0ClMpK5sxr6oqS1Vn+zdjaQIaf3MsL4MIZeD2F1/c9bnkvPzhRbCTaSPyz5E
# hhFbDSgdgp6XFBkEt3VxKBAZk6GCF60wghepBgorBgEEAYI3AwMBMYIXmTCCF5UG
# CSqGSIb3DQEHAqCCF4YwgheCAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsqhkiG
# 9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQC
# AQUABCC8nWzBEw7Di3IJqGhJhVIX7pqElze5wxtJUeXo2bWTvQIGaeyDzrPnGBMy
# MDI2MDQzMDA3MTUzNC4zNTFaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFu
# ZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo2
# RjFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
# dmljZaCCEfswggcoMIIFEKADAgECAhMzAAACHAlVFdfDWQfRAAEAAAIcMA0GCSqG
# SIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDgx
# NDE4NDgzMVoXDTI2MTExMzE4NDgzMVowgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjZGMUEtMDVF
# MC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIC
# IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAow0xEAUaFIyyLIXeFzeI8IKy
# BON2u0Dr02ISE5p9G5CUXfnFu2S0E1gWCMvDWpopX6lRxjmgnqaL3BtnWlBVTo8x
# UNRZu23ie4YBMAJB7Ut6mnqnHVwvDJxGO4TD3SnrCd+yg35B9QFejq3o4+OByvXj
# ynaypZyukcQaLsKQvoxE8ElHH7zcOXEJWmU3rnXzaW/S4SH3OPhoUbTTcy6nUgKx
# 5pRWiQ24UEPLYzcxGJjqjkz+GiCWGPFHDMdW86laWvmCslouQPsN2eBk8dxJcEZm
# W4l6p4TthoXcfexEA9YdYaMz10aMhZNpdsNaDtDQUMDEC3k1D1My69MXSPlUmD9x
# FyDlkXiVa7BCEp3XcVtqTgzHGwr28JD6oE7zEPYeuZOiuCBXTZSo/wk3tbDlsESb
# IPV6inYqrzxiMYqlxfCdzC3Cimh9/NT/Lk9/aU+Iyyc9b3OaT0dZ8wgLaVDCGELR
# MrqyImdFHv0MudctzW/kPsV3Ja9ufpKWujEiN3CW//X8hFa9j5ImNeQzcMit3MoS
# aoGwnbiZJX1IyibIphlqccXFk4oTTSOQBsAUw8U0gwOnM5UJD8mBUBd65Np6NBkx
# 2cviJ4I34GyXFCWyy5Ft1QsBYyVfAG3KOhCfPHQf8lQzJvLr57YW0bD/xVs4Ag4g
# TS6KZNyFEfX9jFdRlr0CAwEAAaOCAUkwggFFMB0GA1UdDgQWBBRa3mOCzB8u7zpv
# Dh8MGKVYLCk7ZDAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNV
# HR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Ny
# bC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYI
# KwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAy
# MDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI
# MA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAklb6w/deaid3BujQ
# CtWFBe0n9pkyRy+yyWEg70iDwoJ5u0e0O+4GerNzdZb1zTPsHJ8EGMyo1K7ytL21
# +pmdFMTl19PC8OJ5Y2p+XKUQy2dD+hggRMmJgDQsgbOCxHYeO+jg4t+vg61wUrov
# zzLkH3z0PJXXvoNuBj9Lda9CiNMd60451Kube99ArSf6ZMj3t0p4rFbgSazDs+8T
# J+8KA5GVaYjPHj9rlMuI3WjohEc9apnQ6hMjMck3jlHZIwluVYeUQE0qjmApfMtT
# AEzbMUdY8sLTunL1GkbDSeKn9O7llBGnNtyM1uM9Mdv1VyWh0z/IriQKIjntqqGy
# oF0HvDHOFZCyUDBPLflyiu7Y1zQ/sPounsb96aBfQdq3h3LOn6t+m9EnNz/G6Mzz
# WvpJk6YgTHTIqeQN/F/XpiPvbfek3nq/PYbL3au+kBfRUHiCFXSvt6lor0HC626v
# Umz9ZNPOxwEWLuccomxsy3JwWH79vsM/7ARqoG5h6d6NahfaOuRP4XI9xtdH3Pa/
# NCLyQjxKXyLxzwQzjddkX2EpTJnlypuhPmEdea59Uz2E303LxyXSnKBvGsAnyWYA
# fnejr3YAiL9YrN2l2dn198RpA4DCm9QtZYiwC0q2fuUvui34PfPIUZByf7wHuuWu
# 50hY9WLx1kOMI8xyo7AI6TaNrnIwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZ
# AAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
# ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVa
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1
# V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9
# alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmv
# Haus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928
# jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3t
# pK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEe
# HT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26o
# ElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4C
# vEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ug
# poMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXps
# xREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0C
# AwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYE
# FCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtT
# NRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNo
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5o
# dG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBD
# AEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZW
# y4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5t
# aWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAt
# MDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0y
# My5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pc
# FLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpT
# Td2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0j
# VOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3
# +SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmR
# sqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSw
# ethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5b
# RAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmx
# aQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsX
# HRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0
# W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0
# HVUzWLOhcGbyoYIDVjCCAj4CAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFu
# ZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo2
# RjFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
# dmljZaIjCgEBMAcGBSsOAwIaAxUAWmTiA01u5mxq/nVxiRJLMOskVGeggYMwgYCk
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIF
# AO2c8LwwIhgPMjAyNjA0MjkyMTAzNTZaGA8yMDI2MDQzMDIxMDM1NlowdDA6Bgor
# BgEEAYRZCgQBMSwwKjAKAgUA7ZzwvAIBADAHAgEAAgImCDAHAgEAAgISQTAKAgUA
# 7Z5CPAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAID
# B6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQDDt6fOs69O0gqJDbmO
# O98e42L1zek0VsR50iefHkehBcMghToqy5y7A/susCfpofv/MRkRPn6JV9m0UAWU
# aenKUiPcTgRDERL21G8saCqWocSQhzrRfUA5AYtl0knDqASQ/CfJLxYe4ZXtR08y
# ThuWLWZYDst/fYxDwJFwODnPGmWHo5HrL4vZXkuib/rZFx821ijdM7Uu/CZMfa2m
# tTlp2CMdnVdCS9wHi41o2/dyy/atRCAGWfe2/NTfZ9L3EvMUsDjf9mxqkfLWlDZa
# +ctrrDpfce7r9/BqQPMhIC2AosN6uTGtAHApZUaoLRsD4YlGv2ZFkvoU1VXXSijm
# HmzcMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAC
# EzMAAAIcCVUV18NZB9EAAQAAAhwwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3
# DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgmML8vKQxMkjgaFoz
# 9pFbMVBX5iEIUuAh5OguZHDCIwswgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9
# BCCgIGkmNhdo7+KE7dWhI+E2Ctx2RLWoYvvJodCIciHHaDCBmDCBgKR+MHwxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACHAlVFdfDWQfRAAEAAAIcMCIE
# IGQlmkSQcNFDNjDW+aEbjW+qEGbHuKLvUKJCXX5ydRlQMA0GCSqGSIb3DQEBCwUA
# BIICACSLTvWs7sjfBXjjiN1Wm6+UE8XOMVaIkSWBd0HXDDRHFwNB3vjr0Z4Oz7nt
# rmVihrrJt9jNzR0Yd88vv3iHC2B2EvuyVE6f8ZhbLYjW9fz6PJve6hWMoYUYIR8L
# s6J7DtG0RL1bpaxkXkFUpxGtb9J49WCKALurq1mVHWx0PkcCY1Zeg93amP0U67S9
# AYtc2gYJ9mtNiTcxnCN1tS4Yrkmp6OhDGPJ3vU+4oa3hOGUEMlNPyA+sqFtkPDkH
# 8Fs3ZwcAyzJeHuu29aSnDakH3tNNrVi4H8FtUPCVUs3mpSvptkY48o392klc8AUl
# tvInOhxCuPJ8WEFgC2WuCjrbJIdHNxk/pyi5atEE61C8zE3JOH5wijCjRA/1pWnX
# mRO2XOGh6cKAiJfrvWk6m7THAZxNYKj9XNFcrI2WZxDmgIPjpjRMIAO2watkYPNB
# UwHVcOUOf37g7KRyhEbhc4umELbgTBRh68sfnCEO7VIDRL17N9i1wO0WvHzniYkb
# Qy60s3s9ghkxbUUfp93YLKe9p2WxGJbS/t5J4wXsGQD6q4KMRv62ZX7xkZTqb2BA
# MbdTR+q+sPIbeqepTHVCnzl8wTTKi4O7pqsgGMRtcnKKpojWnf6qBj68cEjmCcA1
# A3LzP2Np3zPqodPL+tgMajAh0Bt7+i8CGAG/rU81oyMTcWUL
# SIG # End signature block