Table of Contents

Copilot Prompt to Get All Unattached Disks in an Azure Subscription

Summary: This wiki page shows how I used copilot to get all unattached disks in an Azure subscription. It's part of the 'copilot' tag series in which I showcase the use of copilot in infrastructure related tasks.
Date: 2 December 2025

I've been using copilot for a while now, and I mostly use it without using a prompt. I let it finish my sentences, or create a small comment and wait for a few seconds to let copilot to give me some hints on how to proceed. But sometimes I also use a prompt, and on this page I show you how I used some prompts to create a script.

The hard facts:

The Prompt

Actually, I used two prompts. The first prompt was:

I need an azure cli script that will get all disks from an Azure subscription that have the disk state unattached. In the output I want to see the name, the resourcegroup, the last ownership update time, the location, the time created, the disk size, and the following tags: k8s-azure-created-by, kubernetes.io-created-for-pvc-namespace, kubernetes.io-created-for-pvc-name

This created a script, which with some small modifications worked, except that it didn't return the tags. I found that using the azure cli query option didn't retrieve the tags, so I added another prompt:

The output doesn't display the tags. I think the az disk list can't resolve the tag information. I think you need to retrieve the tags separately for each disk

This created a new script, which again needed some small modifications.

The Final Script

Note that this is the script after my modifications. For the modifications, see below. Copilot also provided the possible ways to start the script:

# Display the output for a subscription
.\get-unattached-disks.ps1 -SubscriptionId "your-subscription-id"
# Export to CSV
.\get-unattached-disks.ps1 -SubscriptionId "your-subscription-id" -OutputToCSV -OutputPath "my-disks.csv"
# Get all unattached disks from Azure subscription with detailed information
# This script retrieves disks with state "Unattached" and displays relevant metadata
 
param(
    [string]$SubscriptionId = $null,
    [switch]$OutputToCSV = $false,
    [string]$OutputPath = "unattached-disks.csv"
)
 
# Set subscription if provided
if ($SubscriptionId) {
    Write-Host "Setting subscription to: $SubscriptionId" -ForegroundColor Yellow
    az account set --subscription $SubscriptionId
}
 
# Get current subscription info
$currentSub = az account show --query "{name:name, id:id}" -o json | ConvertFrom-Json
Write-Host "Current subscription: $($currentSub.name) ($($currentSub.id))" -ForegroundColor Green
 
# First get basic disk information for unattached disks
$basicQuery = @"
[?diskState=='Unattached'].{Name: name, ResourceGroup: resourceGroup, LastOwnershipUpdateTime: LastOwnershipUpdateTime, Location: location, TimeCreated: timeCreated, DiskSizeGB: diskSizeGB}
"@
 
Write-Host "Retrieving basic disk information..." -ForegroundColor Yellow
$basicDisks = az disk list --query $basicQuery -o json | ConvertFrom-Json
 
if ($basicDisks.Count -eq 0) {
    Write-Host "No unattached disks found in the subscription." -ForegroundColor Green
    exit 0
}
 
Write-Host "Found $($basicDisks.Count) unattached disk(s). Retrieving tag information..." -ForegroundColor Yellow
 
# Now retrieve tags for each disk individually
$disks = @()
$counter = 0
foreach ($disk in $basicDisks) {
    $counter++
    Write-Progress -Activity "Retrieving disk tags" -Status "Processing disk $counter of $($basicDisks.Count): $($disk.Name)" -PercentComplete (($counter / $basicDisks.Count) * 100)
 
    # Get tags for this specific disk
    $tags = az disk show --name $disk.Name --resource-group $disk.ResourceGroup --query "tags" -o json | ConvertFrom-Json
 
    # Create enriched disk object
    $enrichedDisk = [PSCustomObject]@{
        Name = $disk.Name
        ResourceGroup = $disk.ResourceGroup
        LastOwnershipUpdateTime = $disk.LastOwnershipUpdateTime
        Location = $disk.Location
        TimeCreated = $disk.TimeCreated
        DiskSizeGB = $disk.DiskSizeGB
        CreatedBy = $tags.'k8s-azure-created-by'
        PVCNamespace = $tags.'kubernetes.io-created-for-pvc-namespace'
        PVCName = $tags.'kubernetes.io-created-for-pvc-name'
        #AllTags = $tags
    }
 
    $disks += $enrichedDisk
}
 
Write-Progress -Activity "Retrieving disk tags" -Completed
Write-Host "Completed retrieving tag information for all disks." -ForegroundColor Green
Write-Host ""
 
if ($OutputToCSV) {
    # Output to CSV
    $disks | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
    Write-Host "Results exported to: $OutputPath" -ForegroundColor Green
} else {
    # Display in table format
    $disks | Format-Table -AutoSize -Property @(
        'Name',
        'ResourceGroup',
        @{Name='LastOwnershipUpdate'; Expression={$_.LastOwnershipUpdateTime}; Width=20},
        'Location',
        @{Name='TimeCreated'; Expression={$_.TimeCreated}; Width=20},
        @{Name='SizeGB'; Expression={$_.DiskSizeGB}; Width=8},
        @{Name='CreatedBy'; Expression={$_.CreatedBy}; Width=20},
        @{Name='PVCNamespace'; Expression={$_.PVCNamespace}; Width=15},
        @{Name='PVCName'; Expression={$_.PVCName}; Width=15}
    )
}
 
# Summary
Write-Host ""
Write-Host "=== SUMMARY ===" -ForegroundColor Cyan
Write-Host "Total unattached disks: $($disks.Count)" -ForegroundColor White
$totalSizeGB = ($disks | Measure-Object -Property DiskSizeGB -Sum).Sum
Write-Host "Total size: $totalSizeGB GB" -ForegroundColor White
 
# Group by resource group
$byResourceGroup = $disks | Group-Object -Property ResourceGroup | Sort-Object Count -Descending
Write-Host ""
Write-Host "By Resource Group:" -ForegroundColor Cyan
foreach ($group in $byResourceGroup) {
    $groupSizeGB = ($group.Group | Measure-Object -Property DiskSizeGB -Sum).Sum
    Write-Host "  $($group.Name): $($group.Count) disks ($groupSizeGB GB)" -ForegroundColor White
}
 
# Show Kubernetes-related disks
$k8sDisks = $disks | Where-Object { $_.CreatedBy -or $_.PVCNamespace -or $_.PVCName }
if ($k8sDisks.Count -gt 0) {
    Write-Host ""
    Write-Host "Kubernetes-related disks: $($k8sDisks.Count)" -ForegroundColor Magenta
 
    # Show detailed Kubernetes disk information
    Write-Host ""
    Write-Host "Kubernetes Disk Details:" -ForegroundColor Magenta
    $k8sDisks | Format-Table -AutoSize -Property @(
        'Name',
        @{Name='CreatedBy'; Expression={$_.CreatedBy}; Width=20},
        @{Name='PVCNamespace'; Expression={$_.PVCNamespace}; Width=15},
        @{Name='PVCName'; Expression={$_.PVCName}; Width=20},
        @{Name='SizeGB'; Expression={$_.DiskSizeGB}; Width=8}
    )
}

Modifications Made

Tags

In the first version of the script, the query also tried to retrive the tags. This was not allowed by the query syntax, so I had to remove that from the query.

Basic query

Originally, copilot had a very easy to read query, with every field in a separate line. However, that gave the following error:

ERROR: argument --query: invalid jmespath_type value: "[?diskState=='Unattached'].{"
To learn more about --query, please visit: 'https://learn.microsoft.com/cli/azure/query-azure-cli'

I updated the query to be just on one line, which solved the issue.

Basic query fields

Two of the fields the query would ask for did not work. I had to check the actual field names in the output of `az disk list`. The fields `LastOwnershipUpdateTime` and `diskSizeGB` had wrong casing. I updated them to the correct casing.

All Tags

Even though I didin't ask for it, copilot also added the field `AllTags`, which contained all tags as a hashtable. It worked, but it made the csv output messy, so I commented the field out.

This wiki has been made possible by: