One of my jobs involves looking after a number of demonstration and line of business servers running (mostly) on Virtual Server 2005 R2. Because I’m physically located around 90 miles away from the servers and I have no time allocated to managing the infrastructure, I need to automate as much as possible – which means scripting. The problem is that my scripting abilities are best described as basic. I can write batch files and I can hack around with other people’s scripts – that’s about it – but I did attend a Windows PowerShell Fundamentals course a few weeks back and really enjoyed it, so I decided to write some PowerShell scripts to help out.
Virtual Server 2005 R2 has a Component Object Model (COM) API for programmatic control and monitoring of the environment (this is what the Virtual Server Administration web interface is built upon). For a quick introduction to this API, Microsoft has an on-demand webcast (recorded in December 2004), where Robert Larson explained using the Virtual Server COM API to create scripts to automate tasks like virtual machine (VM) creation, configuration, enumeration, and provisioning VMs.
The Virtual Server COM API has 42 interfaces and hundreds of calls; however the two key interfaces are for virtual machines (IVMVirtualMachine) and the Virtual Server service (IVMVirtualServer). Further details can be found in the Programmers Guide (which is supplied with Virtual Server) and there is a script repository for Virtual Server available on the Microsoft TechNet website.
Because the scripting model is based on COM, developers are not tied to a specific scripting language. This means that, theoretically, Windows PowerShell can be used to access the COM API (although in practice, my PowerShell scripts for Virtual Server are very similar to their VBScript equivalents).
Every script using the Virtual Server COM API needs to initiate the VirtualServer.Application object. For Visual Basic, this would mean calling:
Because I want to use PowerShell, I have to do something similar; however there is a complication – as Ben Armstrong explains in his post on controlling Virtual Server through PowerShell, PowerShell is a Microsoft.NET application and as such does not have sufficient priviledges to communicate with the Virtual Server COM interfaces. There is a workaround though:
- Compile the C# code that Ben supplies on his blog to produce a dynamic link library (.DLL) that can be used to impersonate the COM security on the required object (I initially had some trouble with this but everything was fine once I located the compiler). I placed the resulting VSWrapperForPSH.dll file in %userprofile%\Documents\WindowsPowerShell\
- Load the DLL into PowerShell using
[System.Reflection.Assembly]::loadfrom("%userprofile%\Documents\WindowsPowerShell\VSWrapperForPSH.dll") > $null(I do this in my %userprofile%\Documents\WindowsPowerShell\profile.ps1 file as Ben suggests in his follow-up post on PowerShell tweaks for controlling Virtual Server).
- After creating each object using the Virtual Server COM API (e.g.
$vs=New-Object â€“com VirtualServer.Application â€“Strict), set the security on the object with
[Microsoft.VirtualServer.Interop.PowerShell]::SetSecurity($vs). Again, following Ben Armstrong’s advice, I do this with a PowerShell script called Set-Security.ps1 which contains the following code:
Then, each time I create a new object I call
Having got the basics in place, it’s fairly straightforward to manipulate the COM objects in PowerShell and I followed Ben’s examples for listing registered VMs on a given host, querying guest operating system information and examining .VHD files. I then spent quite a lot of time writing a script which will output all the information on a given virtual machine but although it was an interesting exercise, I’m not convinced it has much value. What I did learn was that:
- Piping objects through Get-Member is can be useful for understanding the available methods and properties.
- Where a collection is returned (e.g. the NetworkAdapters property on a virtual machine object), individual items within the collection can be accessed with .item($item) and a count of the number of items within a collection can be obtained with .count, for example:
$vs=New-Object -com VirtualServer.Application -strict
Write-Host $vm.Name "has" $dvdromdrives.count "CD/DVD-ROM drives"
Of course, System Center Virtual Machine Manager (SCVMM) includes it’s own PowerShell extensions and therefore makes all of this work totally unnecessary but at least it’s an option for those who are unwilling or unable to spend extra money on SCVMM.