«

»

Sep 20 2012

Setting VMware View Desktop State Remotely

Automation has been always the best friend of good System Administrators. Automating repetitive tasks is a key enabler in most IT environments. However, VMware View has some known limitations when talking about automation and remote management.

Besides the Graphical User Interface, local PowerCLI is the only supported management methodology. I say local PowerCLI because none of the VMware View PowerCLI cmdlets allow remote management today. I have previously demonstrated how to use VMware.View.Broker PSSnap-In to configure WinRM sessions and execute remote View PowerCLI (here). It is possible to remotely execute PowerCLI cmdlets using New-PSSession as I demonstrated in my previous post and in the example below.

The PowerShell function below will change the state of a View desktop via ADAM/LDAP database. If pae-VmState is set to READY the VM is accessible, if set to ERROR the VM is not accessible, if set to MAINTENANCE the VM goes into maintenance mode, and if set to DELETING the VM will be deleted.

pae-VmState = “READY”
pae-VmState = “ERROR”
pae-VmState = “MAINTENANCE”
pae-VmState = “DELETING”

The function uses the ADSI adapter to receive an object representation of an Active Directory object and set the new VM state in the ADAM database. This method does not require Remote PowerShell. However to update the ADAM object you will need to find the $_.machine_id via Get-DesktopVM, and this cmdlet will require the remote PowerShell session.

 

Function ViewVM-SetState {
    [cmdletBinding()]
    Param (
        [parameter(Mandatory=$true)]
        [string]$vm,                    #VM name
        [parameter(Mandatory=$true)]
        [ValidateSet("MAINTENANCE","READY","DELETING","ERROR")] 
        [string]$state,                    #State to set the VM to
        [parameter(Mandatory=$true)]
        [string]$ViewIPAddress,            #Connection Server IP Address
        $credential                        #Connection Server Credential
    )

    $ldapBaseURL = 'LDAP://'+$ViewIPAddress + ':389/'
    $script = [scriptblock]::Create("(Get-DesktopVM -Name $vm).machine_id")
    $session = New-PSSession -ComputerName $ViewIPAddress -Credential $credential

    $Machine_Id = Invoke-Command -Session $session -ScriptBlock $script

    $objMachine_Id = [ADSI]($ldapBaseURL + "cn=" + $Machine_Id + ",ou=Servers,dc=vdi,dc=vmware,dc=int")
    $objMachine_Id.PSBase.UserName = "administrator"
    $objMachine_Id.PSBase.Password = "password"

    switch ($state) {
        "MAINTENANCE" { 
            $objMachine_Id.put("pae-vmstate", "MAINTENANCE")
        }
        "READY" {
            $objMachine_Id.put("pae-vmstate", "READY")
        }
        "DELETING" {
            $objMachine_Id.put("pae-vmstate", "DELETING")
        }
        "ERROR" {
            $objMachine_Id.put("pae-vmstate", "ERROR")
        }
        default {
            break
        }
    }
    $objMachine_Id.setinfo()

    Return ""
}

 

This article was first published by Andre Leibovici (@andreleibovici) at myvirtualcloud.net.

 

 

14 comments

Skip to comment form

  1. Mike Gibson

    This information is fantastic. Programmatically placing a VM into Maintenance mode was the last step I required in automating my fornesic data aquisition process in my View environment. I couldn’t believe they didn’t have a cmdlet for this already.

  2. Andre Leibovici

    Mike, I am glad it has helped you.

  3. Nathan Manzi

    I’ve modified this function so that it works when run on a View Connection Server directly, if people don’t want to do the work to get remote View PowerCLI going. Tested against View 5.2. https://gist.github.com/nmanzi/6198708

  4. Andre Leibovici

    Nathan, good job and thanks for sharing with us.

    -Andre

  5. Kurt

    I was just looking into this and came across your article. Nice approach. As an alternative to doing a remote powercli command to look up the machine id, I use a directoryEntry object and set a filter on the pae-DisplayName property. For example:

    $vmName = “DESKTOP23”
    $vdiinfo = new-object DirectoryServices.DirectoryEntry( ($ldapServer + “OU=Servers,DC=vdi,DC=vmware,DC=int”), ($netCred.Domain +”\” + $netCred.Username), $netCred.password)
    $searcher = New-Object System.DirectoryServices.DirectorySearcher($vdiinfo)
    searcher.Filter = “(pae-DisplayName=$vmName)”
    $desktops = $searcher.FindAll()

  6. Andre Leibovici

    Kurt, thanks for sharing.

    -Andre

  7. Craig

    Hi, great post. We are looking to use this to automate putting all virtual desktops on a given ESXi host into maintenance mode.

    Could you please advise how this could be done as the GUI only allows one desktop at a time.

    Thanks!

  8. Blake

    Andre, I am trying to write a script to monitor my pools and make sure that I am not running out of available VM’s (watching available only, not provisioned or used), but I can’t find the variable that contains status. Any thoughts?

  9. Andre Leibovici

    @Blake, I am not sure you need that. Horizon View has an option to always keep a certain number of desktops available, so it will create desktops as needed.

  10. Andre Leibovici

    @Craig, you are right, but will be easier to automated that via PowerShell scripts.

  11. Blake

    Sometimes I run into an issue where I have machines provisioned and View should power them on as available machines are used to keep that minimum number, but it just doesn’t. I have multiple environments that I monitor so I am trying to not have to keep track of each of them manually.

  12. Jason Mathew

    Hello,

    In the script above if I wanted to set a number of VM’s in maintenance mode where would I put that? What I am trying to do is when send a Refresh command to a number of VM’s after I refresh I want to put them in Maintenance mode so during that time my 3rd party system and install apps, setup printers, etc. When that is complete I want to set those same machines to Available status. Any ideas?

    Thanks

  13. Joe Haulton

    Thanks for the PowerCli info, it was not really a lot of fun to work with. The cmdlets take a long time to get the information, so automation at scale is time consuming.
    I did do a script to accomplish what I needed to do, and that is set multiple machines in maintenance mode. It does not use the PowerCli, but connects directly to the ADAM database, finds the information that you were getting with Get-DesktopVM, and makes the change quickly. I also assume that is what Kurt was doing as well, but this is a whole set of code for everyone so they don’t have to trial and error it like me. I did run this remotely as well, so as long as you are an admin on the server with ADAM, you should have no issues and will not need to authenticate separately.
    Powershell is still new to me as I do not use it often enough to be anywhere near where I have been with vbs. Thanks for the starting point, and I hope this helps someone else as well!

    ###########################################
    # VDI Maintenance Script
    # Joe Haulton
    ###########################################

    #Variables

    #State to change to (MAINTENANCE, READY)
    $strState = “MAINTENANCE”

    #Path to File
    $Filepath = “[path to your txt file]”

    #LDAP Server
    $ldapServer = “[your-connectionserver-name]:389”

    #Do Not Change########
    $vdiinfo = [ADSI](“LDAP://” + $ldapServer + “/OU=Servers,DC=vdi,DC=vmware,DC=int”)
    $searcher = New-Object System.DirectoryServices.DirectorySearcher($vdiinfo)
    ######################

    $file = Get-Content $Filepath

    foreach($VMName in $file)
    {

    Write-Host $VMName

    $strDN = Get-DistinguishedName $VMName.Trim

    $strVDIAddInfo = [ADSI](“LDAP://” + $ldapServer + “/” + $strDN)
    $strVDIAddInfo.Put(“pae-vmstate”, $strState)
    $strVDIAddInfo.setinfo()
    $vmName = “”
    }
    ######################

    Function Get-DistinguishedName ($strUserName)
    {
    $searcher = New-Object System.DirectoryServices.DirectorySearcher($vdiInfo)
    $searcher.Filter = “(pae-DisplayName=$vmName)”
    $result = $searcher.FindOne()

    Return $result.GetDirectoryEntry().DistinguishedName
    }

  14. Badri

    How to supply the password in $credential..?

Leave a Reply