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

Comments

  • Anonymous
    June 13, 2006
    > you can expect to see some posts from me in the near future about how to perform different tasks under PowerShell

    Hmm, why don't you give us some ideas that we could try implementing? I'm not familiar enough with Virtual Server to come up with ideas myself.
  • Anonymous
    June 19, 2006
    Persone los pioneros non rabata. Great...
  • Anonymous
    June 24, 2006
    Do you think there might be some way to roll up 'change files' with online backups using powershell?
  • Anonymous
    June 24, 2006
    adsi4nt - sure. It's just scripting.

    Since this is over COM Interop of the VS Admin COM API, you can write the same logic in JScript/VBScript, C/C++, .Net, or PowerShell and then invoke it in any.

    It is your choice where the programming language and logic resides.

    //David