The Auto Start/Stop Script

The following PowerShell script is for starting and stopping VMs, which will be called by the Task Scheduler at specific events. Some variables at the beginning of the script must be set according to how your host system is set up.

  • $vmrun_path: the full path of the VMrun.exe program location.
  • $auto_vms_path: the full path of the folder containing your virtual machines.
  • $start_delay: how many seconds delay between starting VMs.
  • $stop_delay: how many seconds delay between stopping or suspending VMs.

The function Get-AutoVMs is one of the primary work horses in this script. It finds all the VMs which should be controlled in the location specified by $auto_vms_path, and return them in a sorted order according to the +autovm.nn (where nn is the starting order number) filename in each VM's folder.

For example, a VM with a file +autovm.03 in its folder will start before a VM with a file +autovm.05. The stopping/suspending order will be exactly the reverse of the starting sequence. To disable a VM from auto starting/stopping, you simply delete the +autovm.nn file or change it to something like -autovm.nn, for instance.

The parts of script that does actual work to control VMs are the 2 foreach loops, one for starting them and the other for stopping/suspending them. The program VMrun.exe is utilized in those loops. To start a VM, the code 

& "$vmrun_path" -T ws start "$vm" nogui

is used where nogui is specified because it will run at background without a GUI. For stopping and suspending a VM, the script uses

& "$vmrun_path" -T ws $command "$vm" $option

where $command can be 'stop' or 'suspend' and $option can be 'hard' or 'soft'. With option 'soft', VMware will ask the guest system to run corresponding script first. With option 'hard', the guest system will not be given a chance to run its script.

# Get script arguments
# $command: start, stop or suspend
# $option: hard or soft when $command is stop or suspend
param ([string] $command, [string] $option = "soft")

## defaults
# location of vmrun.exe
$vmrun_path = "${Env:ProgramFiles(x86)}\VMware\VMware VIX\VMrun.exe"
# location of virtual machine directory
$auto_vms_path = "E:\Virtual Machines"
# delay interval (in seconds) for starting up and stopping VMs
$start_delay = 90
$stop_delay = 30

## functions
# Get VMs to be auto-started at $path sorted by +autovms.xx name.
function Get-AutoVMs($path) {
    Get-ChildItem "$path\*\+autovm.*" | Sort-Object Name `
    | ForEach-Object {$_.DirectoryName+"\*.vmx"} | Get-ChildItem `
    | ForEach-Object {$_.FullName}
}

# Get running VMs
# NOTE: this only works this VMs started in the same session, so we can't use it here.
function Get-RunningVMs() {
    & "$vmrun_path" -T ws list | Where-Object {$_.EndsWith(".vmx")} `
    | Sort-Object -Descending
}

## main program
if ($command.ToLower() -eq "start") {
    # Retrieve VMs to be auto-start
    $auto_vms = @(Get-AutoVMs $auto_vms_path)

    # Start each VM in the list
    foreach ($vm in $auto_vms) {
        & "$vmrun_path" -T ws start "$vm" nogui
        # Delay a little while.
        if ($vm -ne $auto_vms[-1])
            { Start-Sleep -Seconds $start_delay }
    }
    
    exit 10

} elseif ((("stop", "suspend") -contains $command.ToLower()) `
         -and (("soft", "hard") -contains $option.ToLower())) {
    # Retrieve VMs, and reverse its order.
    #$auto_vms = @(Get-RunningVMs)
    $auto_vms = @(Get-AutoVMs $auto_vms_path)
    [Array]::Reverse($auto_vms)

    # Suspend each VM in the running list.
    foreach ($vm in $auto_vms) {
        & "$vmrun_path" -T ws $command "$vm" $option
        # Delay a little while.
        if ($vm -ne $auto_vms[-1]) 
            { Start-Sleep -Seconds $stop_delay }
    }
    
    exit 20
}

exit 1

Allow the Script to Execute

After you saved the script to your computer and tried to execute it, you will find out that you are not allowed to run it. That is because the default ExecutionPolicy on Windwos 7 is to restrict all PowerShell scripts. You will have to change the ExecutionPolicy to allow an administrator account to execute local PowerShell Scripts. That administrator account will also be the one under which the Task Scheduler action will be run.

First, find Windows Powershell in Start Menu -> All Programs -> Accessories -> Windows Powershell. Right click on it and use 'Run as administrator' if you didn't sign in with an admnistrator account. Enter this command

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

at the prompt (as shown in PIC-1). That will allow the administrator account to execute local and signed remote PowerShell scripts.

PIC-1 Set-ExecutionPolicy

FaLang translation system by Faboba