Checking the creation time of an Azure IaaS VM

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" }
    }
}

 

3 thoughts on “Checking the creation time of an Azure IaaS VM

    1. 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.

      Like

Leave a Reply to eric81 Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: