- Reading Azure VM name, IP address, and hostname with PowerShell - Fri, Jul 28 2017
- Automating WSUS with PowerShell - Thu, Jul 13 2017
- Disable SSL and TLS 1.0/1.1 on IIS with PowerShell - Tue, Jun 27 2017
Please note: I'm providing the script below as is. Use it at your own risk. It removes and then recreates the VM.
[CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$SvcName, [Parameter(Mandatory=$True)] [string]$SourceVMName, [Parameter(Mandatory=$True)] [string]$NewVMName, [Parameter(Mandatory=$True)] [string]$Subscription ) $file = "c:\temp\Renaming_Azure__VM_$SourceVMName{0:MMddyyyy_HHmm}.log" -f (Get-Date) new-item -path $file -type file -force $dt = Get-Date -UFormat %c Write-Host "Renaming VM $SourceVMName in ServiceName $Svcname" -ForegroundColor Yellow Write-Output "Cloning VM $SourceVMName in ServiceName $Svcname timestamt: $dt" >> $file $vm = Get-AzureVM -ServiceName $SvcName -Name $SourceVMName $OSDisk = $vm | Get-AzureOSDisk $StorageAccountName = $OSDisk.MediaLink.Host.Split('.')[0] Set-AzureSubscription –SubscriptionName $Subscription –CurrentStorageAccountName $StorageAccountName $dt = Get-Date -UFormat %c Write-Host "Stopping and Deallocating the VM $vmName" -ForegroundColor Yellow Write-Output "Stopping and Deallocating VM $vmName, timestamp: $dt" >> $file $vm | Stop-Azurevm -Force -Verbose do{ sleep 5 $status = (get-azurevm -ServiceName $SvcName -Name $vmName).InstanceStatus } until($status -eq "StoppedDeallocated") sleep 30 $vmxml = "C:\temp\$SourceVMName.xml" $vm | Export-AzureVM -Path $vmxml if(Test-Path $vmxml){ $xml = [xml](Get-Content $vmxml) $xml.ChildNodes[1].RoleName = $NewVMName $xml.Save($vmxml) } $vm | Remove-AzureVM -Verbose sleep 30 Import-AzureVM -Path $vmxml | New-AzureVm -ServiceName $SvcName
To understand better how the script works, consider the components an Azure VM comprises. Essentially, an Azure VM is just a set of virtual hard disk (VHD) files plus a configuration file in XML. Thus, all I need to do is export the configuration, create a new VM, and then import the configuration.
Note that even though the VM name changes, everything underneath it stays the same. Hence, if you named your Azure drives after the VM, the script won't change those names.
Let's go through the script:
[CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$SvcName, [Parameter(Mandatory=$True)] [string]$SourceVMName, [Parameter(Mandatory=$True)] [string]$NewVMName, [Parameter(Mandatory=$True)] [string]$Subscription )
As inputs for my script, I just need the cloud service name, the source VM name, the new VM name, and the subscription name. I think the variable names speak for themselves.
$file = "c:\temp\Renaming_Azure__VM_$SourceVMName{0:MMddyyyy_HHmm}.log" -f (Get-Date) new-item -path $file -type file -force $dt = Get-Date -UFormat %c Write-Host "Renaming VM $SourceVMName in ServiceName $Svcname" -ForegroundColor Yellow Write-Output "Cloning VM $SourceVMName in ServiceName $Svcname timestamt: $dt" >> $file
This part creates a log file ($file variable) to keep track of what the script is doing. I'm getting the date and time into the $dt variable and updating the console and log file using Write-Host and Write-Output.
$vm = Get-AzureVM -ServiceName $SvcName -Name $SourceVMName $OSDisk = $vm | Get-AzureOSDisk $StorageAccountName = $OSDisk.MediaLink.Host.Split('.')[0] Set-AzureSubscription –SubscriptionName $Subscription –CurrentStorageAccountName $StorageAccountName
Here I'm getting the VM object and storing it in the $vm variable. After that, I'm getting the Azure disk information and storing it in the $OSDisk variable. I only need this to get the storage account name, which I'm doing in the next step. I'll have to configure this storage account as current for the subscription I'm using. This is required to create a new VM from a configuration file.
$dt = Get-Date -UFormat %c Write-Host "Stopping and Deallocating the VM $vmName" -ForegroundColor Yellow Write-Output "Stopping and Deallocating VM $vmName, timestamp: $dt" >> $file $vm | Stop-Azurevm -Force -Verbose do{ sleep 5 $status = (get-azurevm -ServiceName $SvcName -Name $vmName).InstanceStatus } until($status -eq "StoppedDeallocated") sleep 30
Now I'm updating the log file and console again and then stopping the VM I'm going to rename. After that I'm just running a do-while loop to make sure the VM stops.
$vmxml = "C:\temp\$SourceVMName.xml" $vm | Export-AzureVM -Path $vmxml
Next, I'm exporting the VM configuration into the XML file named in the same way as the source VM.
if(Test-Path $vmxml){ $xml = [xml](Get-Content $vmxml) $xml.ChildNodes[1].RoleName = $NewVMName $xml.Save($vmxml) } $vm | Remove-AzureVM -Verbose sleep 30 Import-AzureVM -Path $vmxml | New-AzureVm -ServiceName $SvcName
Finally, after completing all preparation steps, the renaming part begins. First, I'm checking if the XML file already exists using Test-Path and if it does, I'm getting its content into the $xml variable. Then I replace the RoleName node in the XML to the value of $NewVMName and save the XML file.
This is how it looks like inside of the XML file:
And now comes the scary part: Before importing the VM into Azure with the new name, I need to remove the old one with Remove-AzureVM. If you omit the -DeleteVHD option, the script won't remove the VHD drives.
I then wait for 30 seconds just to be on the safe side and then import the XML file with the new VM name using Import-AzureVM. I pipe this to the New-AzureVM cmdlet, which will have the new name.
This is what you see on the console until the VM stops:
The next screenshot shows the rest of the procedure up until renaming the VM.
Is this supports Azure Arm VM and resource group instead of Cloud Service ?
No it doesn’t. Azure ARM handles VMs a bit differently, this script works only for classic Azure VMs.