6

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.

Aatif Akhter
  • 2,126
  • 1
  • 25
  • 46
  • If you're still running v1 vm's you could get them like this: Get-AzureService | select DateCreated . Once you have the dates you can carry on from there .. Just an additional loop – techmike2kx Sep 10 '15 at 13:06
  • Few of my new vms will be created in two/three month old cloud service. I am not going to create one cloud service for each VM. That's my constraint. Cloud services will be containing old and new vm. – Aatif Akhter Sep 10 '15 at 13:09
  • Do you have Remote PowerShell enabled for all the VMs? – MikeWo Oct 11 '15 at 13:00
  • I do have Remote PowerShell enabled for all the VMs – Aatif Akhter Oct 12 '15 at 13:25

4 Answers4

3

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.

MikeWo
  • 10,887
  • 1
  • 38
  • 44
  • I am encountering an error while performing remote PowerShell command - connecting to remote server xxx.cloudapp.net failed with the following error. WinRM cannot complete the operation... I enabled PS remoting and set the executionpolicy as remotesigned even then its not connecting. – Aatif Akhter Oct 12 '15 at 13:25
  • What's the rest of the error? Did it add the certificate to your cert store? Is this occurring on all machines or just one? Can you connect using New-PsSession even outside of the script? – MikeWo Oct 13 '15 at 19:18
  • Firstly I tried testing your script for single vm(removed foreach loop). I was able to import the certificate in my cert store. After that I encountered the above error. I believe that's some problem with WinRM services. So, I logged in to my test server and explicitly enabled PS-Remoting and set the execution policy to unrestricted. Even then I am getting the same error. However If I start the PS-session on the same test server outside the script it is working fine. – Aatif Akhter Oct 14 '15 at 07:00
  • There's nothing more in the error other than cannot complete the operation? That was the complete error message? I'm not sure why this would be blocked, but I was able to run this across two servers without a problem. I think the approach answers the scenario, it's just figuring out what's blocking the connection at this point. Instead of a PS-Session outside of the script, try running an invoke-command outside the script against the same test server. – MikeWo Oct 14 '15 at 17:38
  • 1
    Dude it worked. Thank you so so much. U deserve 50 bounties. :) – Aatif Akhter Oct 14 '15 at 17:44
  • It is quite strange. Instead of using $remoteUri for invoke-command I used $remoteUri.ToString() I reffered to Michael Washam' blog - http://michaelwasham.com/2013/04/16/windows-azure-powershell-updates-for-iaas-ga/ and it sorted out automatically. Anyways I am happy now. Thank you so much for all your efforts – Aatif Akhter Oct 14 '15 at 17:55
  • @Atf : **Round - Robin** – Nana Partykar Mar 23 '16 at 11:13
1

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

greg_diesel
  • 2,955
  • 1
  • 15
  • 24
  • I do believe info provided by you is very correct logically. But since, I had created my VM using ASM, there is no point swithing to ARM (in this case). However for further test processes I will surely go with ARM. – Aatif Akhter Oct 09 '15 at 10:28
0

Here https://social.msdn.microsoft.com/forums/azure/en-US/3da7750a-1a7d-4c62-b58a-a4b427b2520d/get-azure-vm-creationprovision-date a similar a question has been asked previously.

In short, using PowerShell, what you can do is check the name of the VHD attached the VM (this is only true if you created the VM from an image). From the VHD name you can determine when the related VM was created.

Run the following cmdlets to get the VHD name:

Get-AzureVM <cloud service name> <VM name> | Get-AzureOSDisk | select medialink.

As an alternative to PowerShell, you can also get cloud service and virtual machine related information using the Microsoft Azure Management Libraries. However, this method doesn't bring any additional information.

See https://github.com/kimpihlstrom/azure/tree/master/Azure.Management.ListHostedServices as an example of usage and what information can be obtained.

At the moment there doesn't seem to be any other way of getting the creation date of a VM than to extract it from the file name of the VHD, which is only possible under certain circumstances.

kim
  • 3,385
  • 2
  • 15
  • 21
  • 1
    I already visited that link. Few of my vms are migrated one. They dont follow that vhd naming convention which is discussed in the post. Date does not appear as a substring for the vhd name in my case. – Aatif Akhter Oct 07 '15 at 09:58
0

You might want to check out Azure DevTest Labs. I haven't found much documentation on it, but one of the features touted in the link provided is the ability to set automated shutdowns to minimize costs.

Don Lockhart
  • 894
  • 5
  • 12