Control a Virtual Machine threw VirtualBox and C#

I wanted to manage a VM using only C#, the idea was to create an easy start/stop program which help the user to use it without any knowledge.

This program should cover this :

  • Be able to start/stop the VM
  • Be able to hide everything
  • Be able to get the VM ip (the system on the VM was a complex internet demo site)
  • Be able to know the VM state (to indicate if the VM is currently running or not)

For all of this, VirtualBox provide a nice tool called VirtualBoxManage, which is a command line tool. It seems to be able to do exactly the same stuff as VirtualBox, but in a command line way of course.
I will detail here the commands used to make the system working. I will assume the VM name is « MyLinuxOS », the name can be found by launching VirtualBox and checking the VM name on the left list !

VirtualBoxManage command

I will show here basics to make VirtualBoxManage doing all the stuff :

Starting a VM

Maybe the most simple, and easy to find on internet, the startvm command will start the VM, adding the headless parameters will make the VM hidden to the user :

VirtualBoxManage startvm "MyLinuxOS" --type headless

Stopping a VM

Like starting, stopping is also an easy one :

VirtualBoxManage controlvm "MyLinuxOS" poweroff

Getting the VM ip

The IP is not created when starting the VM, so it can be accessed long time before, or when the VM is not running ! Here is the command :

VirtualBoxManage guestproperty get "MyLinuxOS" "/VirtualBox/GuestInfo/Net/0/V4/IP"

This will return a « Value: 10.4.4.4 » for example, so we should parse the string to remove Value parts…

Knowing the VM state

This one is the most complicated : it seems there is no way to check a VM is started or not. And when I say « started », I’m saying the VM is ready to logon, not just running. But, you can threw VirtualBox send command to the VM like a real user, so you can get that state threw a simple trick :

VirtualBoxManage guestcontrol "MyLinuxOS" execute --image "/bin/uname" --username myLogin --password myPassword --wait-stdout

This will send the command /bin/uname (reply « Linux » on Linux) using a simple logon on the system. Of course, it will not work on OS who don’t have /bin/uname (like Windows for example), but you can send another command if you want.
If the VM is not ready (not launched or not ready to logon), VirtualBoxManage will send message on error output. You should use here a command which reply a basic things (the best is a non-change string, like uname always reply Linux it will never change)

Now all commands have been listed, we can do a basic C# program to manage that !

Manage the VM with C#

First of all, threw C# we will launch the VirtualBoxManage, we should do this using the Process class :

private String launchVBoxManager(String args, String attendedOutput)
{
    Process VBoxManage = new Process();
    VBoxManage.StartInfo.CreateNoWindow = true;
    VBoxManage.StartInfo.FileName = this.virtualBoxManage + "VBoxManage.exe";
    VBoxManage.StartInfo.WorkingDirectory = this.virtualBoxManage;
    VBoxManage.StartInfo.Arguments = args;
    VBoxManage.StartInfo.UseShellExecute = false;

    //We redirect output only if the user supply any attended output
    if (attendedOutput != "")
    {
        VBoxManage.StartInfo.RedirectStandardOutput = true;
    }
    VBoxManage.Start();

    //If we are waiting for an output, we wait until the end of the output
    if (attendedOutput != "")
    {
        String line = "";
        while (!VBoxManage.StandardOutput.EndOfStream)
        {
            Application.DoEvents();
            line = VBoxManage.StandardOutput.ReadToEnd();
            if (line.Trim().StartsWith(attendedOutput))
            {
                return line.Trim();
            }
        }
    }
    return "-1";
}

How does this work ? First of all we allow 2 parameters : the first one, args, will be the parameters sended to VirtualBoxManage. AttendedOutput will be the command result (mostly used for the /bin/uname command to check result). If you pass «  », the function will not take care of that parameter.
If the output is not found or there is no output, the function will return a « -1 » string. In other case it will return the output value found (and only if the output if founded).
this.virtualBoxManage is the string path to the main virtualBox folder. Like : « C:\Program Files\VirtualBox\ »

After that, we create also an alias when there is nothing except args parameters :

private String launchVBoxManager(String args)
{
    return this.launchVBoxManager(args, "");
}

Now we can start creating the function which will use the command line tool :

public void stopVM(String VMName)
{
    launchVBoxManager(" controlvm \"" + VMName + "\" poweroff");
}

VMName got the name « MyLinuxOS ».

public String ipVM(String VMName)
{
    //Checking IP
    String ip = " guestproperty get \"" + VMName + "\" \"/VirtualBox/GuestInfo/Net/0/V4/IP\"";
    String tmpIP = launchVBoxManager(ip, "Value");
    if (tmpIP != "-1")
    {
        return tmpIP.Substring(7);
    }
    else
    {
        return "0.0.0.0";
    }
}

This function will return the IP, or 0.0.0.0 if nothing if found.

public void startVM(String VMName)
{
    String start = " startvm \"" + this.virtualBoxMachineName + "\" --type headless";
    launchVBoxManager(start);
}

And finally, the running test (the most complicated) :

public Boolean statusVM(String VMName, String login, String password)
{
    String checkStatus = " guestcontrol \"" + VMName + "\" execute --image \"/bin/uname\" --username \"" + login + "\" --password \"" + password + "\" --wait-stdout";
    String checkStatusResult = "Linux";
    //Return the boolean result
    return (launchVBoxManager(checkStatus, checkStatusResult) == checkStatusResult);
}

This function will return true if the VM reply, false if there is any problem (VM is not started or not ready to handle request.

How to use thoose functions ?

The final step is to understand how and especially when use thoose functions :

  • startVM and stopVM should be access by a button click or something like this
  • ipVM should be accessed on application start (in fact when you want) : the IP is setted by VirtualBox when you install the VM, not after, so you can access this resource at any time
  • statusVM should be access by a timer which check every X seconds the system is running

For the statusVM, here is an example of usage :

//INSIDE ANY FUNCTION

//Starting timer
System.Timers.Timer updater = new System.Timers.Timer(2000);
//The timer reference to this form
updater.SynchronizingObject = this;
updater.Elapsed += new System.Timers.ElapsedEventHandler(timeToSeeChange);
//Start the time
updater.Start();
timeToSeeChange(null, null);



//THE HANDLER
private void timeToSeeChange(object source, ElapsedEventArgs e)
    Boolean running = statusVM("MyLinuxOS", "MyVirtualMachineLogin", "MyVirtualMachinePassword");
    //Now you know if the VM is ready or not using running (true : running, false : not ready/not running)
}

That’s almost finish, you got a basic C# program wich is able to handle a VM start/stop including IP and ready state ! I personnally use this program to move seeing customers without having internet need !
You can found a pastebin of the class manager (little bit modified) here

Publicités

Un commentaire

  1. fdsa

    This is great, thanks.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :