[OT] : Windows Activation, en masse
This weekend I discovered a minor issue in one of my virtual environments. I had built out 100 VMs based on a Hyper-V template, but I forgot to activate the original source before creating the template, so all of the machines were suddenly out of compliance. While easy enough on a one- or two-machine basis to just log into the machine and activate manually, there was no way I was even going to dream of repeating that process on 100 machines.
My First Reaction : PowerShell
Whenever I do anything with this number of machines, I assume there's an easy way to do it in PowerShell. My searching throughout the 'toobz led to many promising scripts; unfortunately, most dealt with the old WMI class used prior to Windows 7 and Windows Server 2008 R2: Win32_WindowsProductActivation. In the latest versions of the operating system, trying to utilize this class leads to generic "Invalid Class" errors; the methods and properties associated with this class have been split out into two new classes: SoftwareLicensingProduct and SoftwareLicensingService (did I mention I'm really glad they're moving away from the Win32_ prefix?). The only PowerShell script I found that dealt with these new classes was a function created by James O'Neill; sadly, I could not get his version to work. I spent about an hour trying to tweak the script to make it work, but couldn't get past various errors. By default, the error I received was as follows:
At line:30 char:18
+ Register-Computer <<<< "<product key>","<computer>"
+ CategoryInfo : InvalidData: (:) [Register-Computer], ParameterBindin…mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Register-Computer
Not sure if this is an issue with the RegEx, but after removing the validation on the parameter and subsequently going through various other iterations, seeing many different error messages come out of the script, I gave up. A man only has so much patience, especially on the weekend.
Going Back to Basic(s)
I don't want to say anything bad about PowerShell at this point, except that it's not the only tool in the toolbox, and it's not the magical cure for all that ails you. One thing I knew I would have little trouble getting to work would be VBScript. Assuming that I have 100 machines named VM-001, VM-002, … , VM-099, VM-100, I could use the following script to activate them all in one swoop (sorry it's not color-coded, but it is fairly short):
For i = 1 to 100 srv = "VM-" & right("000" & i, 3) wmi = "winmgmts:{impersonationLevel=impersonate}!\\" & srv & "\root\cimv2" For Each o in GetObject(wmi).InstancesOf("SoftwareLicensingProduct") If o.ProductKeyID & "" > "" Then o.Activate() Next For Each o in GetObject(wmi).InstancesOf("SoftwareLicensingService") o.RefreshLicenseStatus() Next Next
Now, I don't handle all of the little nuances that James was concerned about, but it certainly did the job, and allowed me to move on with my Sunday. Once I had the script nicely formatted, it took about 6 minutes to run against all 100 servers, and random spot checks on VM-034, VM-066 and VM-092 proved that the machines had all been activated.
Note that without the RefreshLicenseStatus() call, when you log into any machine (at least within a certain amount of time), you'll get a prompt about verifying that Windows is genuine. When you proceed, it will simply tell you that Windows has been successfully activated. I also realize that your list of servers might not be so conveniently-named; you can just as easily pull the list of servers from a text file or database.
Hopefully this will come in handy for someone as forgetful as me.
Very helpful! And I like your point about taking the most direct path to solve problems.
Very nicely done, Aaron!