VMImages/Get-AzVMImageDeprecationStatus.ps1 (202 lines of code) (raw):

# https://aka.ms/DeprecatedImagesFAQ param( [string]$resourceGroupName = '*', [string]$name = '*', [switch]$all, [Int16]$displayLimit = 20 ) $scriptStartTime = Get-Date $scriptFullName = $MyInvocation.MyCommand.Path $scriptPath = Split-Path -Path $scriptFullName $scriptName = Split-Path -Path $scriptFullName -Leaf $scriptBaseName = $scriptName.Split('.')[0] $instances = New-Object System.Collections.Generic.List[Object] $scalesets = Get-AzVmss -ResourceGroupName $resourceGroupName -VMScaleSetName $name -ErrorAction SilentlyContinue $scalesets | ForEach-Object {$instances.Add($_)} $vms = Get-AzVM -ResourceGroupName $resourceGroupName -Name $name -ErrorAction SilentlyContinue $vms | ForEach-Object {$instances.Add($_)} foreach ($instance in $instances) { if ([string]::IsNullOrEmpty($instance.VirtualMachineProfile)) { if (([string]::IsNullOrEmpty($instance.VirtualMachineScaleSet))) { $instance | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'VM' -Force } else { $instance | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'VMSS Instance' -Force } } else { $instance | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'VMSS' -Force } } $vmssCount = $instances | Where-Object {$_.Type -eq 'VMSS'} | Measure-Object | Select-Object -ExpandProperty Count $vmssInstanceCount = $instances | Where-Object {$_.Type -eq 'VMSS Instance'} | Measure-Object | Select-Object -ExpandProperty Count $vmInstanceCount = $instances | Where-Object {$_.Type -eq 'VM'} | Measure-Object | Select-Object -ExpandProperty Count $totalInstanceCount = $vmssInstanceCount + $vmInstanceCount Write-Output "Total Instances $totalInstanceCount VMSS $vmssCount VMSS Instances $vmssInstanceCount VM Instances $vmInstanceCount" foreach ($instance in $instances) { if ($instance.Type -eq 'VM') { $instance | Add-Member -MemberType NoteProperty -Name ImageReference -Value $instance.StorageProfile.ImageReference -Force } elseif ($instance.Type -eq 'VMSS') { $instance | Add-Member -MemberType NoteProperty -Name ImageReference -Value $instance.VirtualMachineProfile.StorageProfile.ImageReference -Force } $location = $instance.Location $publisher = $instance.ImageReference.Publisher $offer = $instance.ImageReference.Offer $sku = $instance.ImageReference.Sku $version = $instance.ImageReference.Version $exactVersion = $instance.ImageReference.ExactVersion if ([string]::IsNullOrEmpty($exactVersion)) { $exactVersion = $version } if ($publisher -and $offer -and $sku -and $exactVersion) { $imageUrn = "$($publisher):$($offer):$($sku):$($exactVersion)" $imageUrn = $imageUrn.ToLower() $instance.ImageReference | Add-Member -MemberType NoteProperty -Name ImageUrn -Value $imageUrn -Force -ErrorAction SilentlyContinue Write-Output "$($instance.Name.PadRight(15,'.')) $($instance.ImageReference.ImageUrn)" Remove-Variable -Name image,imageState,getAzVmImageError -Force -ErrorAction SilentlyContinue $image = Get-AzVMImage -Location $location -PublisherName $publisher -Offer $offer -Skus $sku -Version $exactVersion -ErrorVariable getAzVmImageError -ErrorAction SilentlyContinue if ($image -and $image.ImageDeprecationStatus) { $instance | Add-Member -MemberType NoteProperty -Name ImageDeprecationStatus -Value $image.ImageDeprecationStatus -Force -ErrorAction SilentlyContinue } elseif ($getAzVmImageError) { $getAzVmImageErrorCode = $getAzVmImageError.Exception.GetBaseException().Response.Content | ConvertFrom-Json | Select-Object -ExpandProperty error | Select-Object -ExpandProperty code if ($getAzVmImageErrorCode -and $getAzVmImageErrorCode -eq 'ImageVersionDeprecated') { $imageState = 'Deprecated' $instance | Add-Member -MemberType NoteProperty -Name ImageDeprecationStatus -Value ([PSCustomObject]@{ImageState = $imageState}) -Force -ErrorAction SilentlyContinue } } if ($instance.ImageDeprecationStatus.ScheduledDeprecationTime) { $scheduledDeprecationTimeISO8601 = Get-Date $instance.ImageDeprecationStatus.ScheduledDeprecationTime -Format 'yyyy-MM-ddTHH:mm:ssZ' $instance.ImageDeprecationStatus | Add-Member -MemberType NoteProperty -Name ScheduledDeprecationTime -Value $scheduledDeprecationTimeISO8601 -Force -ErrorAction SilentlyContinue } } } $global:dbgInstances = $instances $rgName = @{Name = 'RG'; Expression = {$_.ResourceGroupName}} $imageState = @{Name = 'ImageState'; Expression = {$_.ImageDeprecationStatus.ImageState}} $scheduledDeprecationTime = @{Name = 'ScheduledDeprecationTime'; Expression = {$_.ImageDeprecationStatus.ScheduledDeprecationTime}} $alternativeOption = @{Name = 'AlternativeOption'; Expression = {$_.ImageDeprecationStatus.AlternativeOption}} $imageUrn = @{Name = 'ImageUrn'; Expression = {$_.ImageReference.ImageUrn}} $instancesWithCalculatedProperties = $instances | Select-Object Type,Name,$rgName,$imageState,$scheduledDeprecationTime,$imageUrn,$alternativeOption | Sort-Object ScheduledDeprecationTime $instancesWithCalculatedProperties = $instancesWithCalculatedProperties | Where-Object {$_.Type -ne 'VMSS Instance'} $instancesWithCalculatedPropertiesCount = $instancesWithCalculatedProperties | Measure-Object | Select-Object -ExpandProperty Count $global:dbgInstancesWithCalculatedProperties = $instancesWithCalculatedProperties $imageStateActiveInstances = $instancesWithCalculatedProperties | Where-Object ImageState -eq 'Active' $imageStateActiveInstancesCount = $imageStateActiveInstances | Measure-Object | Select-Object -ExpandProperty Count $imageStateDeprecatedInstances = $instancesWithCalculatedProperties | Where-Object ImageState -eq 'Deprecated' $imageStateDeprecatedInstancesCount = $imageStateDeprecatedInstances | Measure-Object | Select-Object -ExpandProperty Count $imageStateScheduledForDeprecationInstances = $instancesWithCalculatedProperties | Where-Object ImageState -eq 'ScheduledForDeprecation' $imageStateScheduledForDeprecationInstancesCount = $imageStateScheduledForDeprecationInstances | Measure-Object | Select-Object -ExpandProperty Count Write-Output "`n$imageStateActiveInstancesCount of $instancesWithCalculatedPropertiesCount instances were created from images where ImageState is Active" Write-Output "$imageStateDeprecatedInstancesCount of $instancesWithCalculatedPropertiesCount instances were created from images where ImageState is Deprecated" Write-Output "$imageStateScheduledForDeprecationInstancesCount of $instancesWithCalculatedPropertiesCount instances were created from images where ImageState is ScheduledForDeprecation" if ($all) { if ($instancesWithCalculatedPropertiesCount -gt $displayLimit) { Write-Output "`nShowing $displayLimit of $instancesWithCalculatedPropertiesCount instances regardless of image deprecation status (use -displayLimit to show more):" } else { Write-Output "`nShowing all instances regardless of image deprecation status:" } $table = $instancesWithCalculatedProperties | Select-Object -First $displayLimit | Format-Table Type,Name,RG,ImageState,ScheduledDeprecationTime,ImageUrn -AutoSize | Out-String -Width 4096 } else { if ($imageStateScheduledForDeprecationInstancesCount -gt $displayLimit) { Write-Output "`nShowing $displayLimit of $imageStateScheduledForDeprecationInstancesCount instances created from images scheduled for deprecation (use -displayLimit to show more, use -all to show all VMs regardless of image deprecation status):" } else { Write-Output "`nShowing instances created from images scheduled for deprecation (use -all to show all VMs regardless of image deprecation status):" } $table = $imageStateScheduledForDeprecationInstances | Select-Object -First $displayLimit | Format-Table Type,Name,RG,ScheduledDeprecationTime,ImageUrn -AutoSize | Out-String -Width 4096 } $table = "`n$($table.Trim())`n" Write-Output $table if ($imageStateScheduledForDeprecationInstancesCount -ge 1 -or ($all -and [string]::IsNullOrEmpty($vms) -eq $false)) { $context = Get-AzContext $subscriptionId = $context.Subscription.Id $fileName = $scriptBaseName if ([string]::IsNullOrEmpty($subscriptionId) -eq $false) { $fileName = [System.String]::Concat($fileName, "-$subscriptionId") } if ([string]::IsNullOrEmpty($PSBoundParameters['resourceGroupName']) -eq $false) { $fileName = [System.String]::Concat($fileName, "-$($PSBoundParameters['resourceGroupName'])") } if ([string]::IsNullOrEmpty($PSBoundParameters['name']) -eq $false) { $fileName = [System.String]::Concat($fileName, "-$($PSBoundParameters['name'])") } if (Test-Path -Path $env:HOME -ErrorAction SilentlyContinue) { $path = $env:HOME } else { $path = $PWD } $csvPath = "$path\$fileName.csv" $jsonPath = "$path\$fileName.json" $txtPath = "$path\$fileName.txt" $zipPath = "$path\imagestate.zip" if ($all) { $instances | Export-Csv -Path $csvPath $instances | ConvertTo-Json -Depth 99 | Out-File -FilePath $jsonPath } else { $imageStateScheduledForDeprecationInstances | Export-Csv -Path $csvPath $imageStateScheduledForDeprecationInstances | ConvertTo-Json -Depth 99 | Out-File -FilePath $jsonPath } $table | Out-File -FilePath $txtPath Write-Output "Writing output to $path`n" if (Test-Path -Path $csvPath -PathType Leaf) { Write-Output " CSV: $csvPath" Get-ChildItem -Path $csvPath | Compress-Archive -DestinationPath $zipPath -Update } if (Test-Path -Path $jsonPath -PathType Leaf) { Write-Output "JSON: $jsonPath" Get-ChildItem -Path $jsonPath | Compress-Archive -DestinationPath $zipPath -Update } if (Test-Path -Path $csvPath -PathType Leaf) { Write-Output " TXT: $txtPath" Get-ChildItem -Path $txtPath | Compress-Archive -DestinationPath $zipPath -Update } if (Test-Path -Path $zipPath -PathType Leaf) { $zipName = Split-Path -Path $zipPath -Leaf Write-Output "`n ZIP: $zipPath" if ($env:AZD_IN_CLOUDSHELL) { Write-Output "`nTo download '$zipName' from cloud shell, select 'Manage Files', 'Download', then enter '$zipName' in the required field, then click 'Download'" } } } $scriptTimespan = New-TimeSpan -Start $scriptStartTime -End (Get-Date) $scriptSeconds = [Math]::Round($scriptTimespan.TotalSeconds, 1) Write-Output "`n$($scriptSeconds)s"