You could do this using PowerShell. To stop a service, you use the Stop-Service command. Starting a service is with the Start-Service command. So, you could create a script that had a few entries like the following for each service you need to stop, in order:
Stop-Service ServiceA
do { Start-Sleep -Milliseconds 200}
until ((get-service ServiceA).status -eq 'Stopped')
and to start the services:
Start-Service ServiceA
do { Start-Sleep -Milliseconds 200}
until ((get-service ServiceA).status -eq 'Running')
You could then string 6 of those code blocks together in a script, save it as a .ps1 file, and run it from the powershell prompt as so:
PS C:\> C:\Path\To\Script\script.ps1
I have created a script that meets my needs and I will post it here.
This script performs the following tasks:
- Iterates through all listed physical hosts
- Iterates through all non-excluded VMs
- Gracefully shuts down VMs & waits for shutdown to complete
- Performs synchronous BITS transfer of all VHD files (one at a time) for target VMs to specified location
- Boots target VM after transfer is complete
This script can operate on remote physical hosts and does not need to be run locally. Be sure to run the script with administrative credentials or it will not work correctly.
I am using Windows Server 2008 R2 and so I don't have access to all the fancy commands available in Windows Server 2012.
Also, this is the ultimate expression of "script kiddie" here; I've mashed together about 4 different scripts and then added some logic on top of it. Forgive the inconsistencies in syntax etc.
This script was hand transcribed from a standalone corporate sysem I use, so it may have a few spelling errors. I haven't tried to execute this script directly. The one on my system seems to work just fine.
#Run this script in an administrative instance of powershell
#This script executes based on files in the C:\Scripts directory
cd "C:\Scripts"
#Import the BITS Library so that synchronous transfers can occur easily
Import-Module BitsTransfer
#Note that all these files are delimited by carriage returns - 1 host/vm name per line
#Place these files in the "C:\Scripts" directory on the system running this script
#HyperVParents is the list of remote systems that are hosting VMs that need backup.
$HyperVParents = Get-Content HyperV_Hosts.txt
#ExcludedVMs is the list of VMs that will not be turned off or booted during this process
#NOTE: All VM VHD files in Hyper-V are backed up with this script.
$ExcludedVMs = Get-Content ExcludedVMs.txt
#Build Date String
$filedate = get-date -format "M-d-yyyy"
#Create target directory on remote server for backup if it is not already present
#Replace REMOTESRV with your servername
$TargetPath = "\\REMOTESRV\VHDs\" + $filedate
If(!(Test-Path -Path $TargetPath))
{
New-Item -ItemType directory -Path $TargetPath
}
Foreach ($HyperVParent in $HyperVParents)
{
$VMManagementService = Get-WmiObject -class "Msvm_VirtualSystemManagementService" -namespace "root\virtualization" -ComputerName $HyperVParent
$VMs = Get-WmiObject -Namespace "root\virtualization" -ComputerName $HyperVParent -Query "Select * From MSVM_ComputerSystem where Caption='Virtual Machine'"
Foreach ($VM in $VMs)
{
#Set $VMExcluded to null in order to test the next VM for exclusion
#This routine could probably be more efficient.
$VMExcluded = $null
#Loop through list of excluded VMs to see if current VM is within this list
Foreach ($ExcludedVM in $ExcludedVMs)
{
If ($VM.ElementName -eq $ExcludedVM)
{
$VMExcluded = $true
Write-Host $VM.ElementName, ": Excluded from startup/shutdown process"
}
}
$VMSettingData = Get-WmiObject -Namespace "root\virtualization" -Query "Associators of {$VM} Where ResultClass=Msvm_VirtualSystemSettingData AssocClass=Msvm_SettingsDefineState" -ComputerName $HyperVParent
$VirtualDiskResource = Get-WmiObject -Namespace "root\virtualization" -Query "Associators of {$VMSettingData} Where ResultClass=Msvm_ResourceAllocationSettingData AssocClass=Msvm_VirtualSystemSettingDataComponent" -ComputerName $HyperVParent | Where-Object {$_.ResourceSubType -match "Microsoft Virtual Hard Disk"}
$VHD_Path = $null
$vmGUID = $VM.name
#Start logical check that skips unused systems. They will not be powered off or on.
If ($VMExcluded -eq $null)
{
$Query = "select * from Msvm_computersystem where Name='" + $vmGUID + "'"
$VMTemp = gwmi -namespace root\virtualization -query $Query -ComputerName $HyperVParent
#Only attempt a shutdown if the system is powered on
If ($VMTemp.EnableState -ne "3")
{
Write-Host "System Requires Shutdown:", $VM.ElementName
#Build SQL Query - Use the target GUID here since the Msvm_ShutdownComponent seems to be only targeted with a GUID
$ShutdownQuery = "SELECT * from Msvm_ShutdownComponent WHERE SystemName ='" + $vmGUID + "'"
#Execute the query to select the shutdown component of the target VM
$vmshut = gwmi -namespace root\virtualization -query $ShutdownQuery -ComputerName $HyperVParent
$result = $vmshut.InitiateShutdown("$true","VHD Backup Process");
Write-Host "Shutting Down:", $VM.ElementName
#Wait for system to shutdown
Do {
#Increment 1 sec pauses for each loop
Start-Sleep -s 1
#Use a different variable here so that the original target VM is not modified
#Requery the VM each second to get an updated EnabledState
$VMTemp = gwmi -namespace root\virtualization -query $Query -ComputerName $HyperVParent
}
While ($VMTemp.EnabledState -ne "3");
Write-Host $VM.ElementName, "successfully shutdown"
}
Else
{
Write-Host $VM.ElementName, ": Already shutdown"
}
}
#End Logical check for systems that are unused
#Perform the file transfer of the VHD file afer the VM has shut down.
Foreach ($VHD in $VirtualDiskResource)
{
$VHD_PATH = $VHD.Connection[0] + ","
#Replace colon in path with dollar sign for UNC purposes
$VHD_PATH_TEMP = $VHD.Connection[0] -replace ':','$'
#Build Source String
$BackupSource = "\\" + $HyperVParent + "\" + "VHD_PATH_TEMP"
#Extract VHD Name from the path for use in the target file
$VHDName = Split-Path -Leaf $VHD.Connection[0]
#Build Target String; $TargetPath was built at the initiation of the script
$BackupTarget = $TargetPath + "\" + $VHDName
Write-Host "Beginning Backup:", $VM.ElementName, $BackupSource
#Transfer VHD file to the target server using BITS
StartBitsTransfer -Source $BackupSource -Destination $BackupTarget
Write-Host "Backup Complete:", $VM.ElementName, $BackupTarget
}
#Here backed up systems are turned back on after the file transfer of their VHD is complete.
#Filter out certain unused VMs - unused systems do not need to be booted.
If ($VMExcluded -eq $null)
{
Write-Host "Starting VM:", $VM.ElementName
#Boot the VM before the script loops and moves to the next system.
$result = $VM.requeststatechange(2)
}
}
}
Best Answer
Definitively, you should use Azure Automation to run on schedule a PowerShell Script to shutdown or start your VM in Azure. It is already well documented on Microsoft Web site.
Here are 3 links that explains step by step how to do this
Stop Azure Virtual Machine using Azure Automation Runbook https://gallery.technet.microsoft.com/scriptcenter/Stop-Azure-Virtual-Machine-0b1fea97
Shutting down a Azure VM with Azure Automation http://blogs.technet.com/b/georgewallace/archive/2014/11/05/shutting-down-a-azure-vm-with-azure-automation.aspx
Using Azure Automation to run VMs during office hours only https://blogs.endjin.com/2015/01/using-azure-automation-to-run-vms-during-office-hours-only/
Regards
Stanislas