How To Automate The Activation Of Windows Server 2019 Virtual Machines With PowerShell

4 min read

Introduction

A while ago, I wrote a blog post on how to automatic activate Windows Server 2016 Virtual Machines using PowerShell Direct, you can read all about it here.

In Windows Server 2016 Hyper-V, Microsoft introduced an awesome feature called PowerShell Direct. For more information about PowerShell Direct, please check the following article.

I have updated the script to support Windows Server 2019 guest virtual machines, which does not require any network configuration for the guest operation system or any type of network at all.

In this post, I will show you how to leverage PowerShell Direct and Automatic Virtual Machine Activation (AVMA) to activate Windows Server 2019 virtual machines running on top of Windows Server 2019 Standalone host or Hyper-V Cluster.

Automatic Virtual Machine Activation

Automatic Virtual Machine Activation (AVMA) is a feature that was introduced starting with Windows Server 2012 R2. AVMA binds the virtual machine activation to the licensed virtualization server and activates the virtual machine when it starts up. This eliminates the need to enter licensing information and activate each virtual machine individually.

Microsoft has update the generic AVMA Keys to support Windows Server 2019 (Datacenter/Standard/Essentials) according to the Guest OS Edition that you want to activate, for more information, please check the official documentation.

In order to get benefits of Automatic Virtual Machine Activation, AVMA requires that the host is running Windows Server 2019 Datacenter Edition and that the guest virtual machine OS is either Windows Server 2019 Datacenter, Windows Server 2019 Standard or Windows Server 2019 Essentials.

PowerShell Tool

You have deployed several Windows Server 2019 virtual machines on top of Windows Server 2019 Hyper-V (Datacenter Edition) with or without SCVMM, using Windows Admin Center, or using a deployment tool such as MDT where you can add below script during the deployment to activate all VMs.

Of course you could use the manual approach, but the easiest way is to use PowerShell, for this reason I have created a small function that takes care of the automatic activation steps for you:

Here we go:

<#
     .SYNOPSIS
    Activate Windows Server 2019 VMs.

    .DESCRIPTION
    Activate Windows Server 2019 Virtual Machines using Automatic Virtual Machine Activation (AVMA).
    Guest OSs (Windows Server 2019 Standard, Standard Core, Datacenter, Datacenter Core, or Essentials).

    .NOTES
    ===========================================================================
    File Name    : ActivateVM-WS2019.ps1
    Author       : Charbel Nemnom
    Version      : 3.0
    Date created : 08.March.2019
    Last modified: 11.March.2019
    Requires     : PowerShell Version 5.1 or above
    OS           : Windows Server 2019 Hyper-V
    Module       : Hyper-V-PowerShell
    ===========================================================================

    .LINK
    To provide feedback or for further assistance please visit:
    https://charbelnemnom.com

    .PARAMETER HyperVHost
    The Hyper-V host name or Cluster that own the virtual machine(s) to be activated.

    .PARAMETER VMName
    The name of a single virtual machine.

    .PARAMETER ALLVMS
    If this parameter is specified, then it will activate all virtual machines.
    
    .EXAMPLE
    .\ActivateVM-WS2019.ps1 -HyperVHost <Hyper-V Host> -VMName <VMName>
    This example will connect to a specified Hyper-V host or Cluster name and activate a single VM.
        
    .EXAMPLE
    .\ActivateVM-WS2019.ps1 -HyperVHost <Hyper-V Host> -ALLVMS
    This example will connect to a specified Hyper-V host or Cluster name and activate all Virtual Machines.  
       
#>

[CmdletBinding()]
param(
     [Parameter(Position=0, Mandatory=$true, HelpMessage= 'Enter Hyper-V Host or Cluster Name')]
     [ValidateNotNullOrEmpty()]
     [Alias('Hyper-V Host Name')]
     [String]$HyperVHost,

     [Parameter(Position=1, HelpMessage= 'Enter Virtual Machine Name')]
     [ValidateNotNullOrEmpty()]
     [Alias('Virtual Machine Name')]
     [String]$VMName,

     [Parameter(Position=2, HelpMessage= 'All Virtual Machines, ParameterSetName = "ALLVMS"')]
     [Alias('All Virtual Machines')]
     [Switch]$ALLVMS
      
)

# Environment Configuration
$msg = "Enter the username and password that will use to activate Windows Server 2019 VMs!"; 
$AdminCred = $Host.UI.PromptForCredential("https://charbelnemnom.com",$msg,"$env:userdomain\$env:username",$env:userdomain)

Function ActivateVM {
    param(
        [Parameter(Mandatory=$true)]
        [String]$HyperVHost,

        [Parameter(Mandatory=$true)]
        [String]$VirtualMachine,

        [Parameter(Mandatory=$true)]
        [PSCredential]$AdminCred
    )
   
Invoke-Command -ComputerName $HyperVHost -ScriptBlock {
       Wait-VM -Name $Using:VirtualMachine -For Heartbeat    
       Invoke-Command -VMName $Using:VirtualMachine -Credential $Using:AdminCred -ScriptBlock {
              param (
                   $VirtualMachine
                    )

                   # Define initial license status
                   $LicenseStatus = @("Unlicensed","Licensed","OOB Grace",
                   "OOT Grace","Non-Genuine Grace","Notification","Extended Grace")

                   # Check if the guest OS is licensed before activation
                   $WINLIC=Get-CimInstance -ClassName SoftwareLicensingProduct |`
                   Where{$_.PartialProductKey -and $_.Name -like "*Windows*"}  | Select-Object `
                   @{Expression={$_.Name};Name="WindowsName"},`
                   @{Expression={$LicenseStatus[$($_.LicenseStatus)]};Name="LicenseStatus"}

                   If ($WINLIC.LicenseStatus -ne "Licensed") {

                      If  ($WINLIC.WindowsName -like "*Standard*") {
                          # Activate VM WS2019 Standard
                          cmd.exe /c cscript //B "%windir%\system32\slmgr.vbs" /ipk TNK62-RXVTB-4P47B-2D623-4GF74 /ato
                          Write-Output "Activating virtual machine: $VirtualMachine Windows Server 2019 Standard"
                          }

                      If  ($WINLIC.WindowsName -like "*Datacenter*") {
                          # Activate VM WS2019 Datacenter
                          cmd.exe /c cscript //B "%windir%\system32\slmgr.vbs" /ipk H3RNG-8C32Q-Q8FRX-6TDXV-WMBMW /ato 
                          Write-Output "Activating virtual machine: $VirtualMachine Windows Server 2019 Datacenter"
                          }
                          
                      If  ($WINLIC.WindowsName -like "*Essentials*") {
                          # Activate VM WS2019 Essentials
                          cmd.exe /c cscript //B "%windir%\system32\slmgr.vbs" /ipk 2CTP7-NHT64-BP62M-FV6GG-HFV28 /ato 
                          Write-Output "Activating virtual machine: $VirtualMachine Windows Server 2019 Essentials"
                          }             
                   }

                   If ($WINLIC.LicenseStatus -eq "Licensed") {
                   Write-Output "Virtual Machine: $VirtualMachine is already activated!"
              }
          
         } -ArgumentList $Using:VirtualMachine
                  
   }         
}

# If ALLVMS switch is true, then activate all VMs
If ($ALLVMS) {
   $VMs = Get-ClusterGroup -Cluster $HyperVHost | ? {$_.GroupType -eq 'VirtualMachine' } | Get-VM | Select-Object VMName, ComputerName
   foreach ($VM in $VMs) { 
   ActivateVM -VirtualMachine $VM.VMName -HyperVHost $VM.ComputerName -AdminCred $Script:AdminCred
   }
}
Else {
   # Activate Single VM
   $VM = Get-ClusterGroup -Cluster $HyperVHost | ? {$_.GroupType -eq 'VirtualMachine' } | Get-VM | ? {$_.VMName -eq "$VMName"} | Select-Object VMName, ComputerName
   ActivateVM -VirtualMachine $VM.VMName -HyperVHost $VM.ComputerName -AdminCred $Script:AdminCred
}

You can run the script above from your management machine within the same domain, you need to specify first the Hyper-V host name (Standalone) or Hyper-V Cluster name, and this could be Windows Server Core or Server with Desktop Experience as well, then you have two options, either you specify a single virtual machine name or you can use the switch “-ALLVMS” to activate all virtual machines.

This script will leverage PowerShell Remoting to connect to the Hyper-V host remotely and then use PowerShell Direct to activate all VMs. Welcome to Nested PowerShell Remoting (PSRemoting + PSDirect). This script will also use a new cmdlet that was introduced in Windows Server 2016 named “Wait-VM“. This cmdlet will wait for a virtual machine to respond using (heartbeat) before activating.

The output will look something like this:

In this example, we are activating all virtual machines running on top of Storage Spaces Direct Hyper-Converged Cluster, if a VM is already activated, you will be notified, and if a new VM needs to be activated, you will be notified as well.

Roadmap

There are different ways to accomplish the same result, but nevertheless it has worked for me and I feel that it’s a much easier than having to log in and activate each VM individually.

I am planning to improve this tool in the future. This is version 3.0. If you have any feedback or changes that everyone should receive, please feel free to leave a comment below.

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

Advertisements
About Charbel Nemnom 475 Articles
Charbel Nemnom is a Cloud Architect and Microsoft Most Valuable Professional (MVP), totally fan of the latest's IT platform solutions, accomplished hands-on technical professional with over 17 years of broad IT Infrastructure experience serving on and guiding technical teams to optimize performance of mission-critical enterprise systems. Excellent communicator adept at identifying business needs and bridging the gap between functional groups and technology to foster targeted and innovative IT project development. Well respected by peers through demonstrating passion for technology and performance improvement. Extensive practical knowledge of complex systems builds, network design and virtualization.

Be the first to comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.