HOWTO: Remotely start and stop a Virtual Machine on Virtual Server 2005

Here is one of the usual questions about Virtual Server - how to remotely control the Guest VM. Actually, Virtual Server 2005 Administration API is pretty rich and supports these scenarios - you just need to write a little bit of code to do so. Small price to pay for automation.

Question:

I would like to remotley save and turn off my guest OS once a week so I can back up all the files associated.

Is it possible to have the backup server send a command to the Host OS and have it save then turn off the OS do the backup then turn the Guest OS back on?

Answer:

The Virtual Server 2005 Administration API definitely supports this. In general, if you can do it from within the web-browser based Administration interface, you can automate it via script and do everything remotely. The key here is that you must learn a tiny bit of basic scripting and a little bit about how to use Virtual Server.

The documentation is included with the default Virtual Server installation at:

I highly recommend that you look through product documentation to write the necessary automation that you need for your scenario

Now, if you are like 99.99% of the Virtual Server user base, you probably did want to hear me say "it's possible - just write the code yourself." Instead, you probably want me to just give you free, functional code. Well, I will get to that... but first, you will have to listen to the explanation because without it, you will not get very far. I will show you enough of the basics to do what you need - if you want to make it useful for your needs, you can take initiative to finish it up. I deliberately left the "do the backup" part up to you to decide - I just show you how to get the filenames of the VHDs that you want to backup.

The Task

This task actually has two separate components:

  1. The ability to have the script act on a remote machine
  2. The script to turn on/off a Virtual Machine by name

Let's do the easy one first - how to enable remote administration of a Virtual server.

Enabling Remote Administration

Given a default installation of Virtual Server 2005 with some Virtual Machines, to enable remote administration you need to ensure:

  1. Virtual Server DCOM component allows remote instantiation and activation by the remote NT user.
    1. dcomcnfg
    2. Navigate to "Component Services\My Computer\DCOM Config" node
    3. Right click on "Virtual Server" package and select Properties
    4. Select the "Security" tab
    5. Click "Edit" for the "Launch and Activation Permissions" section
    6. Give "Authenticated Users" Remote Activation and Local Activation Permissions
    7. OK out of everything
  2. The ports of the Virtual Server DCOM server is accessible by the remote caller (i.e. Firewall is not blocking).
    1. If the Host is running Windows Server 2003 SP1 or Windows XP SP2 the Windows Firewall may be already running. Or you may have some other Firewall running. In any case, you want to make sure that there is no firewall blocking access between your remote client and the Virtual Server

    2. If using Windows Firewall, you can run the following NETSH command to make sure Virtual Server DCOM server is accessible through the Windows firewall.

       NETSH.EXE Firewall set AllowedProgram "%ProgramFiles%\Microsoft Virtual Server\vssrvc.exe" VS2005 Enable
      
  3. The remote caller also has Virtual Server Core Component installed so that they can originate the DCOM call
  4. The NT user making the DCOM call is allowed access to both the Virtual Server DCOM component (what we did in step #1) AND has Execute permission in Virtual Server security (only Administrators have this right by default).

You can configure Virtual Server security by:

  1. Navigating from the homepage of the VS Administration Website and choosing "Server Properties".
  2. Then selecting "Virtual Server security".
  3. Finally Adding an entry to allow the NT user at least the "Control" permission (which gives that user access to the VS Admin API) and probably also the "Modify" and "Read" properties.

JScript Code to turn On/Off a Virtual Machine

Assuming that you have Remote administration enabled, the following JScript code should be able to run on the remote computer as the NT user with privileges to both remotely activate and access the VS Admin API and remotely contact the DCOM Server of Virtual Server to start/stop a virtual machine.

You are going to want to also read the following blog entry for the "WaitForTask" script routine useful for managing and waiting for various Virtual Machine operations to "finish".

//David

 //
// Remote Start/Stop a Virtual Machine
//
var CRLF = "\r\n";
var VM_STATE_OFF = 1;
var VM_STATE_RUNNING = 5;

var strServer = "VS Server"
var strVMName = "Guest VM Name"

var objVS = new ActiveXObject( "VirtualServer.Application", strServer );
var objVM = objVS.FindVirtualMachine( strVMName );
var objTask;
var enumHardDiskConnection;
var objHardDiskConnection;
var objHardDisk;
var strFileToCopyFrom;

//
// If the Virtual Machine was found
//
if ( objVM != null )
{
    WScript.Echo( "Found Virtual Machine named: " + strVMName );

    //
    // Only attempt to wait for graceful shutdown of a running VM
    //
    // This requires VM Additions to be installed in the Guest.
    //
    // I have seen it not work on occassions and the VM is just
    // "hanging" and never shuts down.
    //
    if ( objVM.State == VM_STATE_RUNNING )
    {
        try
        {
            WScript.Echo( "Gracefully shutting down VM..." );
            task = objVM.GuestOS.Shutdown();
            WaitForTask( task );
        }
        catch ( e )
        {
            //
            // Failed graceful shutdown. Just turn the power off on
            // the Guest VM
            //
            WScript.Echo( "Forcefully shutting down VM..." );
            task = objVM.TurnOff();
            WaitForTask( task );
        }
    }

    //
    // Run your backup operation on the VHDs
    //
    enumHardDiskConnection = new Enumerator( objVM.HardDiskConnections );
    for (   ;
            !enumHardDiskConnection.atEnd();
            enumHardDiskConnection.moveNext() )
    {
        objHardDiskConnection = enumHardDiskConnection.item();
        objHardDisk = objHardDiskConnection.HardDisk;
        strFileToCopyFrom = objHardDisk.File;

        WScript.Echo( "Source VHD (relative to " + strServer + "): " + CRLF +
                      strFileToCopyFrom );
    }


    //
    // Only attempt to start up the turned-off VM
    //
    if ( objVM.State == VM_STATE_OFF )
    {
        WScript.Echo( "Starting up VM..." );
        objTask = objVM.StartUp();
        WaitForTask( objTask );
    }
}
else
{
    WScript.Echo( "Did not find Virtual Machine named: " + strVMName );
}