I recently had a requirement to check the age of VMs deployed in Azure. As I looked it became clear there was no metadata for a VM that shows its creation time. When you think about this it may be logical since if you deprovision a VM (and therefore stop paying for it) then provision it again what is its creation date? When it was first created or when it last was provisioned.
As I dug in there is a log written at VM creation however by default these are only stored for 90 days (unless sent to Log Analytics) BUT if its within 90 days I could find the creation date of any VM. For example:
$logs = Get-AzureRmLog -ResourceProvider Microsoft.Compute -StartTime (Get-Date).AddDays(-90) foreach($log in $logs) { if(($log.OperationName.Value -eq 'Microsoft.Compute/virtualMachines/write') -and ($log.SubStatus.Value -eq 'Created')) { Write-Output "- Found VM creation at $($log.EventTimestamp) for VM $($log.Id.split("/")[8]) in Resource Group $($log.ResourceGroupName) found in Azure logs" # write-output " - ID $($log.Id)" $vmCreationTime = $($log.EventTimestamp) #$log } }
What if the VM was not created in the last 90 days? If the VM uses a managed disk you can check the creation date of the managed disk. If it is NOT using a managed disk then there is not creation time on a page blob however by default VHDs include the creation data and time as part of the file name. Therefore to try and find the creation data of a VM I use a combination of all 3 by first looking for logs for the VM, then look for a managed disk and finally try a data in unmanaged OS disk.
#Must run elevated #Find any creation #$logs = Get-AzureRmLog -ResourceProvider Microsoft.Compute -StartTime (Get-Date).AddDays(-30) #OR #Find creation for a specific VM $vm = get-azurermvm -name 'testnotmanaged' -ResourceGroupName 'testunmanagedrg' $logs = Get-AzureRmLog -ResourceId $vm.Id -StartTime (Get-Date).AddDays(-90) $vmCreationTime = $null foreach($log in $logs) { if(($log.OperationName.Value -eq 'Microsoft.Compute/virtualMachines/write') -and ($log.SubStatus.Value -eq 'Created')) { Write-Output "- Found VM creation at $($log.EventTimestamp) for VM $($log.Id.split("/")[8]) in Resource Group $($log.ResourceGroupName) found in Azure logs" # write-output " - ID $($log.Id)" $vmCreationTime = $($log.EventTimestamp) #$log } } #If could not find a match if($vmCreationTime -eq $null) { #Disk method #Managed Disk $osdisk = $null try {$osdisk = Get-AzureRmDisk -DiskName $vm.StorageProfile.OsDisk.Name -ResourceGroupName RGSavEastUSBurstDemo -ErrorAction SilentlyContinue $vmCreationTime = $($osdisk.TimeCreated)} catch {} if($osdisk -ne $null) { Write-Output "VM creation at $vmCreationTime for VM $($log.Id.split("/")[8]) in Resource Group $($log.ResourceGroupName) via managed disk creation time" } #Obviously flaws here if used an existing disk but its good enough. For unmanaged looks like I can do: if($osdisk -eq $null) { #Unmanaged Disk $vmosdiskloc = $vm.StorageProfile.OsDisk.vhd.Uri $vmosdiskstorageact = $vmosdiskloc.Substring(8).Split(".")[0] #extract out the storage account name by removing the https:// then finding the first part before period (.) $storaccount = Get-AzureRmStorageAccount | where {$_.StorageAccountName -eq $vmosdiskstorageact} $vmosdiskcontainer = $vmosdiskloc.Substring(8).Split("/")[1] #extract the middle path between location and vhd which would be the container $vmosdiskname = $vmosdiskloc.Substring(8).Split("/")[2] $OSBlob = Get-AzureStorageBlob -Context $storaccount.Context -Container $vmosdiskcontainer -Blob $vmosdiskname try {$vmCreationTime = [datetime]::ParseExact(($OSBlob.Name.Substring(($OSBlob.Name.Length-18),14)),'yyyyMMddHHmmss',$null)} catch { $vmCreationTime = $null} if($vmCreationTime -ne $null) { Write-Output "VM creation at $vmCreationTime for VM $($log.Id.split("/")[8]) in Resource Group $($log.ResourceGroupName) via date in page blob for OS disk" } } }
Great!!! Thanks a lot for your help. It worked with the page blob way.
LikeLike
Hi John , how about getting creation time of all VM’s in my subscription ?
LikeLike
You could just have a block at the start getting all resource groups then for each vm in each resource group run the code for specific van. That would do what you need.
LikeLike