Home > vSphere API > Really Easy Ways to Capture VM Screenshot

Really Easy Ways to Capture VM Screenshot

September 8th, 2010 Leave a comment Go to comments

Since vSphere 2.5, there is a feature allowing you to capture screen shot of a running virtual machine. It’s not well publicized but you can find a short description with screenshotSupported (boolean) in the HostCapability data object. Thanks to Nikita for bringing this up in the comment of the vSphere Java API 2.1 GA post.

Indicates whether the screenshot retrival over https is supported for this host’s virtual machines. If true, a screenshot can be retrieved at the HTTPS relative path /screen?id=<managed object ID of virtual machine or snapshot>. If any of the optional parameters ‘top’, ‘left’, ‘bottom’, and ‘right’ is specified, the returned image will be cropped from the rectangle with upper left corner (left, top) and bottom right corner (right – 1, bottom – 1). These values default to the top, left, bottom and right edges of the image. The client must use an authenticated session with privilege VirtualMachine.Interact.ConsoleInteract on the requested virtual machine or, in the case of a snapshot, the virtual machine associated with that snapshot.

Time to learn how to "Google" and manage your VMware and clouds in a fast and secure

HTML5 App

The managed object ID of virtual machine is the value of ManagedObjectReference, which can be easily found using MOB.

Once you have it, you can issue a URL as follows in any browser and get the screen shot in PNG format.

https://esx.acme.com/screen?id=48

Supposedly you can also get the screenshot of a snapshot using a URL like the following:

https://esx.acme.com/mob/?moid=80%2dsnapshot%2d3

It took a long time before I canceled it. So I was not able to make it working. I also tried top/left/bottom/right with no luck. If you make it working, please feel free to share here.

You cannot use the above URL with a vCenter server which manages the host running the VM. The following URL gets you an error saying the webpage cannot be found.

https://vc.acme.com/screen?id=vm%2d693

So capturing screen shot with URL is a host only feature.

In addition to this, you can also use the CreateScreenshot_Task() defined with VirtualMachine type. It works only with ESX(i) as well. The location of the screenshot image file is returned in the Task’s info.result sub-property upon success.

“/vmfs/volumes/4bfac83a-f48e7595-8b0d-00237dfba01d/MyVM/MyVM-screenshot-0.png”

You can have multiple screen shots captured with number incremented as you can find with Web based datastore browser:

MyVM-screenshot-0.png 07-Sep-2010 04:01 292561
MyVM-screenshot-1.png 07-Sep-2010 04:07 292561

As you know to download a file from datastore using HTTP access, you need a URL pattern as follows:

https://esx.acme.com/folder/MyVM/MyVM-screenshot-0.png?dcPath=ha-datacenter&dsName=FCLun2

Now the question is: how to convert the above UUID in the info.result to the corresponding datastore’s name. It’s relatively easy task, I would leave it to you. Hint: check out the datastore property of HostSystem type.

  1. September 8th, 2010 at 01:25 | #1

    I found workaround: I have read screenshot file content directly by means of SSH2 (http://www.jcraft.com/jsch/).

    The way of using HTTPS for retrieving screenshot file content from ESX is morу complex because in first you need install SSL certificates, then provide login and password for authorization (Basic Auithorization Method) and only after send request in order to get screenshot.

  2. September 8th, 2010 at 22:58 | #2

    Hi Nikita,

    Thanks for sharing your SSH2 approach! With HTTPS, you don’t have to install SSL certificate. Check out the WSClient.java in vijava for the trick to handle this. In general, you want to use HTTPS over SSH because SSH might not be open by default.

    Steve

  3. Abhinav
    September 14th, 2010 at 05:20 | #3

    Can I improve something (I am worried about the way I am parsing image url returned by screenshot task) in the code below?

    public BufferedImage getThumbnail(VirtualMachine vm) throws Exception {
    Task screenshotTask = vm.CreateScreenshot_Task();
    if (TaskInfoState.success.toString().equals(screenshotTask.waitForTask(500, 100))) {
    String fileDatastoreUrl = (String) screenshotTask.getTaskInfo().getResult();
    // file datastore url should be of format
    // “/vmfs/volumes/4c063bc6-f462ed19-2974-002492fdd84e/vesx5.0/vesx5.0-screenshot-0.png”
    // split it into 5 parts as “”, “vmfs”, “volumes”,
    // “4c063bc6-f462ed19-2974-002492fdd84e”, and
    // “vesx5.0/vesx5.0-screenshot-0.png”. Second part is
    // datastore type, fourth part is datastore uuid, and 5th part
    // is filename.
    String[] filenameParts = fileDatastoreUrl.split(“/”, 5);
    String datastoreType = filenameParts[1];
    String datastoreUuid = filenameParts[3];
    String filename = filenameParts[4];

    Datastore[] datastores = vm.getDatastores();
    if (datastores != null) {
    for (Datastore datastore : datastores) {
    DatastoreSummary summary = datastore.getSummary();
    if (datastoreType.equalsIgnoreCase(summary.getType())
    && summary.getUrl().contains(datastoreUuid)) {
    // Found correct datastore.
    String datastoreName = datastore.getName();

    // Find datacenter.
    ManagedEntity datacenter = vm;
    for(; datacenter!=null && !”Datacenter”.equals(datacenter.getMOR().getType()); datacenter = datacenter.getParent());
    String datacenterName = datacenter.getName();

    String serverUrl = vm.getServerConnection().getUrl().toString();

    // Build url as
    // https://xxx.xxx.xxx.xxx/folder/vesx5.0/vesx5.0-screenshot-0.png?dcPath=CBM&dsName=CBM470GB
    // to download screenshot file.
    StringBuilder fileUrlBuilder = new StringBuilder(serverUrl);
    if (!serverUrl.endsWith(“/”)) {
    fileUrlBuilder.append(‘/’);
    }
    fileUrlBuilder.append(“folder/”);
    fileUrlBuilder.append(URLEncoder.encode(filename, “UTF-8”));
    fileUrlBuilder.append(“?dcPath=”);
    fileUrlBuilder.append(URLEncoder.encode(datacenterName, “UTF-8”));
    fileUrlBuilder.append(“&dsName=”);
    fileUrlBuilder.append(URLEncoder.encode(datastoreName, “UTF-8”));
    String fileUrlString = fileUrlBuilder.toString();

    System.out.println(“Downloading screenshot from ” + fileUrlString + ” for vm ”
    + vm.getName());

    String cookie = vm.getServerConnection().getSessionStr();

    URL url = new URL(fileUrlString);
    URLConnection conn = url.openConnection();

    conn.setDoInput(true);
    conn.setDoOutput(true);
    conn.setAllowUserInteraction(true);
    conn.setRequestProperty(“Cookie”, cookie);

    conn.connect();

    InputStream screenInputStream = conn.getInputStream();
    try {
    return ImageIO.read(screenInputStream);
    } finally {
    if(screenInputStream!=null){
    screenInputStream.close();
    }
    if (conn != null && conn instanceof HttpURLConnection) {
    ((HttpURLConnection) conn).disconnect();
    }
    }
    }
    }
    }
    }

    throw new Exception(“Thumbnail is not available.”);
    }

  4. September 14th, 2010 at 10:39 | #4

    Thanks a lot for sharing the code with the community!

    -Steve

  5. April 1st, 2011 at 23:19 | #5

    “In addition to this, you can also use the CreateScreenshot_Task() defined with VirtualMachine type. It works only with ESX(i) as well.”

    That is actually not true, nothing prevents you from executing the CreateScreenshot_Task() from vCenter and retrieving the image from the ESX host (assuming the credentials of the ESX are known) with this method.

  6. April 5th, 2011 at 01:22 | #6

    Thanks Virgil, I think your description is clearer and more precise.

    Steve

  7. September 17th, 2015 at 11:42 | #7

    Grandes cosas por venir.

  1. May 30th, 2012 at 04:00 | #1
  2. January 3rd, 2013 at 11:31 | #2
  3. January 3rd, 2013 at 12:26 | #3
  4. January 5th, 2013 at 03:43 | #4
  5. August 23rd, 2013 at 00:01 | #5