I was recently tasked with changing the license key and activating a significant number (read: more than 10) Virtual Machines and Hypervisor hosts, in order to facilitate the use of Automatic Virtual Machine Activation. AVMA is a Windows Sever 2012 R2 feature, whereby Windows Server 2012 R2 guests can activate via their Hypervisor host, if it is running Windows Server 2012 R2 Datacenter, leveraging your Virtual Guest Entitlement rights in a very practical way!
I thought this was a prime opportunity for the Invoke-Command PowerShell cmdlet, calling SLMGR vbs. Turns out I was wrong, with remote host & guest activation universally failing, irrespective of how I called the script, be it via CMD.exe, as an escalated process or satanic ritual. It appears there was no way of sufficiently elevating the command whilst operating remotely!
My work around for this was rather old-school, and in some ways neater (read: less nested braces in the PowerShell code) than using Invoke-Command. Using the SCHTASKS.exe, it is possible to schedule one-shot tasks that run as Local System. Combining this command with PowerShell pipelines to gather our target machines provided the desired result:
We configure SCHTASKS.exe with the following uncommon parameters:
- The /ru switch is used to specify that the configured task will run as Local System
- The /sc switch is used to specify that the configured task will only run once
- The /z switch is used to configured the task to delete itself after execution
- The /st switch is used to configure the task to execute at the time contained in the calculated variable $TaskTime
- The /V1 switch is used to force SCHTASKS.exe to operate in legacy compatibility mode, suppressing this error
We have chosen to target the hosts via the Windows Failover Clustering PowerShell module and the Virtual Machines via the VMM PowerShell module. This is a conscious choice, allowing us to demonstrate how it is possible to target non-VMM managed, physical servers (e.g. Exchange cluster nodes) using this approach. However, it should be noted that in pure VMM/Hyper-V management scenarios, it would make a great deal of sense to pull the host list out of VMM, reducing the number of external dependencies for the script.
The script in its current state has the following dependencies:
- Must be executed by a user with administrative rights on the targeted hosts and VMs
- Must be executed by a user with at least Read rights to VMM
- The VMM & Windows Failover Clustering PowerShell modules must be installed on the workstation the script is executed from
- RPC channels must be open to the VMs & Hypervisor hosts from the workstation the script is executed from
It wouldn’t take a great deal of work to alter this script to work with different data-sets, be it VMware Virtual Machine lists using the PowerCLI module or just our good friend Active Directory!
I hope this saves someone else some of the time I lost trying to combine SLMGR.vbs and Invoke-Command. My thanks to @RichardJGreen for sound-boarding and sanity-checking this one.
(Apologies for linking the script, as opposed to embedding it, but my WordPress install is hosed at the moment)