Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terminate Azure VM after 30 days automatically

In my day today activity I create test vm in azure and then delete it. For some reason this time I am planning to create 100 test vms and I want to implement a scheduling mechanism (through powershell or AzureRunbook) so that the servers created can be automatically deleted after 30 days...

The problem is I can find out the created date of a cloud service using Powershell but not the date of creation of VM. Few of the cloud service are containing old VMs also whom I dont want to delete.

I am thinking of a different naming convention of vm so that I can use that for deletion time using-

if($vm.name -like "mypattern*")
{
     $out1 = $vm.Name
     $out2 = $vm.ServiceName
     Remove-AzureVM -Name $out1 -ServiceName $out2 -DeleteVHD
     sleep -Seconds 60
 } 

I believe there must be more approaches other than this. What can be alternative option for this. I prefer powershell.

like image 274
Aatif Akhter Avatar asked Sep 10 '15 10:09

Aatif Akhter


2 Answers

Based on your scenario as I understand it, you are trying to find the date a VM was created. The VMs in question are "Classic" VMs, meaning they are deployed to Cloud Service containers and are not created via Azure Resource Manager. Some of the VMs have already been created, and some will be created by your script going forward. Some of the cloud service containers also have been around a while and some might be newer.

I was unable to find a way to retrieve the VM creation date via the Service Management API; however, if we can reach the actual VM then we have more to go on. The script below assumes that the VM creation date is the same as the OS Install date on the VM (which should be a pretty good indicator I'd think, I verified it's the not the date of source image, but rather the date of the VM creation). For this to work you need to have the PowerShell Remote endpoint enabled on the VMs, which is there by default when you create a VM, and you must run the script under local admin rights since it messes with the certificate store.

$remoteCreds = Get-Credential
$maxVMAgeInDays = 30
#Classic VMs
Get-AzureVM | ForEach-Object { 
    #Need to ensure we have the self-signed VM certificate installed to authenticate and secure the connection.
    $winRmCertThumbprint = $_.Vm.DefaultWinRmCertificateThumbprint 
    $certPath = "Cert:\LocalMachine\Root\$winRmCertThumbprint"
    if (!(Test-Path -Path $certPath)){
        #Cert for VM isn't found, importing.
        $winRmCert = Get-AzureCertificate -ServiceName $_.ServiceName -Thumbprint $winRmCertThumbprint -ThumbprintAlgorithm sha1

        $certTempFile = [IO.Path]::GetTempFileName()
        $winRmCert.Data | Out-File $certTempFile

        # Target The Cert That Needs To Be Imported
        $CertToImport = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $certTempFile

        $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine"
        $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
        $store.Add($CertToImport)
        $store.Close()

        "Imported cert: $certPath"

        #clean up temp file
        Remove-Item $certTempFile
    } 

    #Retrieve the powerShell Remote port for this machine.
    $remoteUri = Get-AzureWinRMUri -ServiceName $_.ServiceName -Name $_.Name

    $osInstallDate = Invoke-Command -ConnectionUri $remoteUri -Credential $remoteCreds -ScriptBlock { ([WMI]'').ConvertToDateTime((Get-WmiObject Win32_OperatingSystem).InstallDate)  }

    $vmAgeInDays = (New-TimeSpan -Start $osInstallDate  -End (Get-Date)).Days
    if ($vmAgeInDays -gt $maxVMAgeInDays) {
        "$($_.Name) VM in $($_.ServiceName) cloud service is older than $maxVMAgeInDays ... you can remove it."
        #Add your code to remove the VM
    } else {
        "$($_.Name) VM in $($_.ServiceName) cloud service is only $($vmAgeInDays) old."        
        #Do soemthing else or just remove the else.
    }
}

The script assumes you've already performed the Add-AzureAccount and selected the subscription you want to work with. It will prompt you for the credentials for the VMs, which this particular script assumes you have one credential that has been set up to that works for every VM. This can be the credential you provided upon VM creation, or one you've added to the correct rights to each VM afterwards. Since you're saying your creating the 100s of VMs via a script my guess is that they will all have the same admin credential. For your existing VMs you may have to add the account manually to them (which could be painful depending on how many you have).

The script loops through each VM and checks to see if the WinRM certificate is loaded on the local machine. If not, it pulls it down and installs it. This is required to secure the remote PowerShell Session. I took the code from Michael Washam's script on TechNet.

After we know we have the cert to secure the connection it them performs a remote PowerShell command to retrieve the OS Install date (a tip I found on the ScioSoft blog). Finally it performs a check for the age of the VM based on that date and can then perform whatever action you want it to. In your case you can then delete it. You'll want to make sure when you delete the VM you also clean up the underlying disks, etc. if you really want to clean things out.

Finally, to improve the script I'd suggest for any VM you delete you can then then clean up your cert store by removing the cert via the thumbprint.

This will work for Classic VMs, which it sounds like you have. Someone has already given you a way to deal with the ARM based VMs via tagging, which would remove the need to actually deal with the remote commands.

like image 108
MikeWo Avatar answered Oct 20 '22 19:10

MikeWo


You can find the VMs that you are searching for by adding tags to them.

In Azure Powershell you can add the Resource Manager Cmdlets Install-Module AzureRM Install-AzureRM

See https://msdn.microsoft.com/en-us/library/azure/mt125356.aspx

Here is a complete article from Microsoft on tagging your VMs (Powershell is at the bottom)

https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-tagging-arm/

Then when you create these 100 test VMs. Be sure to tag them at that time since at creation time you will know which is which. Using Set-AzureResource

$tags =@{Name="LaunchDate";Value="09-01-2015"}

Set-AzureResource -Name MyWindowsVM -ResourceGroupName MyResourceGroup -ResourceType "Microsoft.Compute/VirtualMachines" -ApiVersion 2015-05-01-preview -Tag $tags

like image 42
greg_diesel Avatar answered Oct 20 '22 20:10

greg_diesel