Improved Desktop Restart Script

I've done some work lately to improve my desktop restart script from earlier in the month. I've made a few important changes - now the script will wait (by default 10 seconds) between restart commands so as to not overwhelm the environment. That wait time is a configurable parameter; just invoke the script with the -wait # option to set it to wait for that number of seconds. This is especially useful for nonpersistent pools, as you can pass it a highish number (such as 45 seconds) in order to ensure that the bulk of the desktops in a floating pool remain available at any one time.

I've also improved the script's session handling logic. It will now restart systems with Disconnected sessions (but will still not restart desktops with Connected sessions). It is also no longer sensitive to the domain suffix of the desktops. Finally, I found a condition where it would fail to issue a hard reset for a frozen desktop, if that desktop was so frozen that the VMTools completely stopped reporting. The script now checks for that condition and issues a hard reset accordingly.

I also implemented a few powershell standards for this script. It now has entries for help! That means that you can use "help restart-dt.ps1" to read all about how to use the script. The script also checks for the "-whatif" switch and will output what it would do without actually restarting anything. Finally, I've added some basic logic checking to make sure that the VMware snappins that it needs are available on the system before it runs and have changed the default behavior so that it restarts desktops that match "test*" instead of "*".

As always, this is published for educational purposes and is a firmly "use at your own risk".  Beware of unintended line breaks due to the width of the blog.  While it worked for me in my environment, that is no guarantee that it will work for you in yours.


<#
    .SYNOPSIS
    Script to restart a set of VDI Desktops that may or may not be frozen, ignoring desktops with Connected sessions.
   
    .DESCRIPTION
    This script checks the VMTools status to determine if the desktop is frozen or not and issues either a soft restart or a hard reset depending on the state of the desktop.  It checks with the connection server and ignores any desktops that have a Connected session.
   
    It must be run on a View Connection Server that has VMware PowerCLI installed.
   
    .PARAMETER Whatif
    Only report what actions the script would do, do not issue any commands.  Useful for testing.

    .PARAMETER serverName
    The DNS resolvable name (or IP Address) of the vCenter server.

    .PARAMETER vmName
    The name pattern for the VMs to be restarted (accepts wildcards)

    .PARAMETER wait
    The number of seconds to wait between desktop restarts
   
    .PARAMETER guestOS
    This script only restarts VMs of the configured Guest OS.  Accepts Wildcards, defaults to *Windows 7*
   
    .EXAMPLE
    restart-DT.ps1 -v test*
   
    This will attempt to restart all desktops that have names beginning with "test"
   
    .EXAMPLE
    restart-DT.ps1 -v floating* -w 45
   
    This will attempt to restart all desktops that have names beggining with "floating" and will wait 45 seconds between restart commands
   
    .LINK
    http://virtuallyjason.blogspot.com
   
    Author: Jason Coleman
    Last Modified: 10/10/2013
#>
 

param
(
    [switch]$WhatIf,
    [alias("s")]
    [string]$serverName = "vCenter.mydomain.local",
    [alias("v")]
    [string]$vmName = "test*",
    [alias("w")]
    [int]$wait = 10,
    [string]$guestOS = "*Windows 7*"
)

#Checks to ensure that all required snapins are available, aborts the script if they are not.
$registeredSnapins = get-pssnapin -registered | select name
if (!($registeredSnapins -match "VMware.View.Broker") -or !($registeredSnapins -match "VMware.VimAutomation.Core"))
{
    write-output "Please run from a View Connection Server with the VMware PowerCLI snapins installed."
    Return
}

# Load the VMware snapins
add-pssnapin VMware.VimAutomation.Core
add-pssnapin VMware.View.Broker

#Connect to the vCenter Server
Connect-VIServer $serverName | out-null

#Gets a list of all VMs, filtered by the entered name. 
#Get-view was used instead of get-VM in order to access GuestHeartbeatStatus and GuestOS

$vmList = get-view -ViewType "VirtualMachine" | where {$_.name -like $vmName}
#Gets a list of all remote sessions in the environment
$remoteSessions = Get-RemoteSession | select session,dnsname,state

foreach ($thisVM in $vmList)
{
    #Checks if the guest is a desktop OS
    if ($thisVM.config.guestfullname -like $guestOS)
    {
        #Checks if there is an active session for that VM
        if (($remoteSessions | where {$_.DNSName -like "$($thisVM.name).*"}).state -eq "Connected")
        {
            write-output "$($thisVm.name) has an active session."
        }
        else
        {
            #If the HeartBeatStatus is green, use a soft restart
            if ($thisVM.GuestHeartbeatStatus -eq "green")
            {
                write-output "Soft Restart: $($thisVm.name)"
                if (!($WhatIf))
                {
                    get-vm -name $thisVM.name | Restart-VMGuest | out-null
                }
            }
            #if the HeartBeatStatus is red, use a hard reset
            elseif ($thisVM.GuestHeartbeatStatus -eq "red")
            {
                write-output "Hard Reset: $($thisVM.name)"
                if (!($WhatIf))
                {
                    get-vm -name $thisVM.name | stop-VM -confirm:$false | out-null
                    start-sleep 15
                    get-vm -name $thisVM.name | start-VM | out-null
                }
            }
            #If the HeartBeatStatus is gray, check the power state of the VM and hard reset if it's powered on.
            else
            {
                if ($thisVM.summary.runtime.powerstate -eq "poweredOff")
                {
                    write-output "Ignoring Powered Off VM: $($thisVM.name)"
                }
                elseif ($thisVM.summary.runtime.powerstate -eq "poweredOn")
                {
                    write-output "Hard Reset: $($thisVM.Name)"
                    if (!($WhatIf))
                    {
                        get-vm -name $thisVM.name | stop-VM -confirm:$false | out-null
                        start-sleep 15
                        get-vm -name $thisVM.name | start-VM | out-null
                    }
                }
                else
                {
                    write-output "--> Unknown Power State: $($thisVM.summary.runtime.powerstate) for VM: $($thisVM.Name)"
                }
            }
        }
    }
    sleep $wait
}
#clean up after the script is completed
Disconnect-VIServer $serverName -Confirm:$False
remove-pssnapin VMware.VimAutomation.Core
remove-pssnapin VMware.View.Broker

Comments

  1. Good Evening Jason,

    Thank you for the Script example bellow, it's very much appreciated Sir.

    I'm currently looking into creating the same thing however utilizing VMware ViewManager 6.2.2 and rebooting all Windows 7 OS's. I've tried running the script however I receive an error "Please run from a Connection Broker" perhaps the name Connection Broker has now changed in Horizon View 6.2.2 I look forward to hearing from you and appreciate the support!

    Keep up the good work!

    ReplyDelete
    Replies
    1. I should have called it a Connection Server, rather than a Connection Broker, but it's the windows server that brokers client connections. That error message is generated if the script does not find PowerCLI or the View PowerCLI snapins. Pleas ensure that you have installed PowerCLI on the Connection Server that you want to use to run this. I don't remember off the top of my head, but it looks like View 6 still uses the same snapin names (https://pubs.vmware.com/horizon-view-60/topic/com.vmware.view.integration.doc/view_integration_powershell.5.2.html#992904).

      Delete
  2. Hello Jason, This script is awesome! Thank you for sharing! Do you know how I can get this to run in Task Scheduler as System or some other account where I don't need to worry about making a service account?

    ReplyDelete
  3. Jason, love the script but we would love to have it restart machines that are connected. What commands would I need to add to make that happen? Thanks

    ReplyDelete
    Replies
    1. Sounds like you're putting together a bit of a dangerous script there! But if you want to disable the active connection check, just change this line from:

      if (($remoteSessions | where {$_.DNSName -like "$($thisVM.name).*"}).state -eq "Connected")

      to:
      if ($false)

      Delete

Post a Comment

Sorry guys, I've been getting a lot of spam recently, so I've had to turn on comment moderation. I'll do my best to moderate them swiftly after they're submitted,

Popular posts from this blog

PowerShell Sorting by Multiple Columns

Clone a Standard vSwitch from one ESXi Host to Another

Deleting Orphaned (AKA Zombie) VMDK Files