All scripts
Microsoft 365 552

Windows 365 Cloud PC Inventory Report

Pulls a full inventory of provisioned Windows 365 Cloud PCs from Microsoft Graph, including status, assigned user, image and last modified date, so you can see what is actually running before your next license renewal.

Get-Windows365CloudPCInventory.ps1
<#
.SYNOPSIS
    Reports on all provisioned Windows 365 Cloud PCs in the tenant.

.DESCRIPTION
    Connects to Microsoft Graph and pulls the current inventory of Windows 365
    Cloud PCs, including provisioning status, assigned user, image name, and
    the last modified date. Useful before a license renewal or when you just
    need to know what is actually running versus what was ordered.

.AUTHOR
    Shehryar Hassan

.EXAMPLE
    .\Get-Windows365CloudPCInventory.ps1 -ExportPath "C:\Reports\CloudPCs.csv"

    Connects to Graph, pulls every Cloud PC in the tenant, and writes the
    results to the given CSV path.
#>

[CmdletBinding()]
param(
    [string]$ExportPath = ".\CloudPCInventory.csv"
)

$requiredScopes = @("CloudPC.Read.All")

Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Cyan
Connect-MgGraph -Scopes $requiredScopes -NoWelcome

$uri = "https://graph.microsoft.com/v1.0/deviceManagement/virtualEndpoint/cloudPCs"
$results = @()

do {
    $response = Invoke-MgGraphRequest -Method GET -Uri $uri
    $results += $response.value
    $uri = $response.'@odata.nextLink'
} while ($uri)

if (-not $results -or $results.Count -eq 0) {
    Write-Host "No Cloud PCs found in this tenant." -ForegroundColor Yellow
    return
}

$report = $results | ForEach-Object {
    [PSCustomObject]@{
        DisplayName       = $_.displayName
        ManagedDeviceName = $_.managedDeviceName
        UserPrincipalName = $_.userPrincipalName
        Status            = $_.status
        ProvisioningType  = $_.provisioningType
        ImageDisplayName  = $_.imageDisplayName
        ServicePlanName   = $_.servicePlanName
        LastModifiedDate  = $_.lastModifiedDateTime
        GracePeriodEnd    = $_.gracePeriodEndDateTime
    }
}

$report | Sort-Object Status, UserPrincipalName | Format-Table -AutoSize

$report | Export-Csv -Path $ExportPath -NoTypeInformation -Encoding UTF8
Write-Host "Exported $($report.Count) Cloud PCs to $ExportPath" -ForegroundColor Green

$statusSummary = $report | Group-Object Status | Select-Object Name, Count
Write-Host "`nStatus summary:" -ForegroundColor Cyan
$statusSummary | Format-Table -AutoSize

Disconnect-MgGraph | Out-Null

Read it before you run it, and test in a safe tenant first.