-- Ben Armstrong, Virtualization Program Manager
Talking about core virtualization at Microsoft (Hyper-V, Virtual PC and Virtual Server).
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:
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; } }}
using
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:
However - if you make any new objects (which you will):
You will get bitten again. This is simply handled by setting the COM security on objects as you create them:
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:
Cheers,Ben