Controlling Virtual Server through PowerShell

A number of people have been asking me about using PowerShell to control Virtual Server.  This is a very cool idea – however, out of the box it does not work.  If you try and access the Virtual Server COM object (with a command like: $vs=new-object –com VirtualServer.Application –Strict) it will succeed – but inspecting the object will show no data:

Virtual Server and PowerShell

The reason this happens is that PowerShell is a .Net application – and as a .Net application it does not run with sufficient privilege to be able to talk to our COM interfaces.  In order to address this – you will need to make a library that allows you to set the COM security level on an object to ‘impersonate’.  Below is a chunk of C# code that does exactly this (I have attached this code in a file to this post as well):



using System;
using System.Runtime.InteropServices;
using System.Reflection;

namespace Microsoft.VirtualServer.Interop
{
   
using System;
   
using System.Runtime.InteropServices;
   
using System.Reflection;

   
public class 
   Powershell
   {
      
const uint EOAC_NONE = 0;
      
const uint RPC_C_AUTHN_WINNT = 10;
      
const uint RPC_C_AUTHZ_NONE = 0;
      
const uint RPC_C_AUTHN_LEVEL_DEFAULT = 0;
      
const uint RPC_C_IMP_LEVEL_IMPERSONATE = 3;

      [
DllImport(
         
“Ole32.dll”
         CharSet =
CharSet.Auto
         )
      ]
      
public static extern int 
      CoSetProxyBlanket(
         
IntPtr pProxy, 
         
uint dwAuthnSvc, 
         
uint dwAuthzSvc,
         
uint pServerPrincName, 
         
uint dwAuthLevel,
         
uint dwImpLevel, 
         
IntPtr pAuthInfo,
         
uint dwCapabilities
      );

      public static int 
      SetSecurity(
         
object objDCOM
         )
      {
         
IntPtr dispatchInterface = Marshal.GetIDispatchForObject(objDCOM);
         
int hr = CoSetProxyBlanket(
            dispatchInterface,
//pProxy
            
RPC_C_AUTHN_WINNT, //dwAuthnSvc
            
RPC_C_AUTHZ_NONE, //dwAuthzSvc
            
0, //pServerPrincName
            
RPC_C_AUTHN_LEVEL_DEFAULT, //dwAuthnLevel
            
RPC_C_IMP_LEVEL_IMPERSONATE, //dwImpLevel
            
IntPtr.Zero, //pAuthInfo
            
EOAC_NONE //dwCapabilities
         
);
         
return hr;
      }
   }
}


You can compile this code into a DLL by saving it in a .CS file, opening the Visual Studio 2005 Command Prompt and running ‘csc /t:library VSWrapperForPSH.cs’.  Once you have done this – you can load this DLL into PowerShell by running ‘[System.Reflection.Assembly]::LoadFrom(“<<path to DLL>>”)’ (note that you need to use the full path to the DLL – if the path is excluded – PowerShell will look in Windows\System32 and complain if the file is not there).


Once you have done all of this – you can now change the COM security level on an object by running ‘[Microsoft.VirtualServer.Interop.Powershell]::SetSecurity($objectName)’.  And as you can see here – you will then be able to access the object properly:

Virtual Server and PowerShell

However – if you make any new objects (which you will):

Virtual Server and PowerShell

You will get bitten again.  This is simply handled by setting the COM security on objects as you create them:

Virtual Server and PowerShell

Well.  Now that we have all of that working – you can expect to see some posts from me in the near future about how to perform different tasks under PowerShell.  But for now – a couple of final notes to make are:



  1. Under Vista hosts – PowerShell needs to be running ‘As Administrator’ for this to work (otherwise you will fail to create the first COM object)


  2. I could not have done this without the help of Mike Kolitz and Jon White (from the PowerShell team) – thanks guys!

Cheers,
Ben

VSWrapperForPSH.cs