You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取AzureRM托管磁盘空间使用与剩余空间——PowerShell技术求助

这个问题我碰到过好多次——Azure的控制平面能轻松拿到托管磁盘的元数据(比如容量、系统类型这些),但磁盘的已用/可用空间属于VM内部操作系统层面的信息,Azure本身不会主动收集这些数据。所以要拿到这两个值,必须从运行中的VM内部去获取。下面给你两种可行的方案,结合你已有的脚本实现完整需求:

核心原理说明

Azure的Get-AzDisk只能获取磁盘的物理属性(比如容量、ID、关联VM等),而文件系统的使用情况是OS内部的状态,只有通过远程执行命令、自定义脚本扩展等方式进入VM内部才能拿到。

方案1:通过PowerShell远程直接获取(适合少量VM)

这个方案适合VM数量不多的场景,直接远程连接到VM执行命令,把磁盘使用数据和你已有的基础信息合并。

完整脚本示例

# 初始化结果数组
$diskReport = @()

# 获取所有Azure VM
$allVMs = Get-AzVM

foreach ($vm in $allVMs) {
    $vmName = $vm.Name
    $rgName = $vm.ResourceGroupName
    $osType = $vm.StorageProfile.OsDisk.OsType

    # 获取VM关联的所有托管磁盘(OS盘+数据盘)
    $vmDisks = Get-AzDisk | Where-Object {
        $_.Id -eq $vm.StorageProfile.OsDisk.ManagedDisk.Id -or
        $vm.StorageProfile.DataDisks.ManagedDisk.Id -contains $_.Id
    }

    foreach ($disk in $vmDisks) {
        # 先收集基础磁盘信息
        $diskInfo = [PSCustomObject]@{
            VMName              = $vmName
            DiskName            = $disk.Name
            CapacityGB          = $disk.DiskSizeGB
            OSType              = $osType
            ResourceGroupName   = $rgName
            UsedSpaceGB         = $null
            FreeSpaceGB         = $null
        }

        # 根据OS类型远程获取磁盘使用情况
        try {
            if ($osType -eq "Windows") {
                # Windows VM:用Invoke-Command远程执行卷查询
                $volumeData = Invoke-Command -ComputerName $vm.PrivateIpAddress `
                    -Credential (Get-Credential) `
                    -ScriptBlock {
                        Get-Volume | Where-Object { $_.DriveType -eq 'Fixed' } |
                        Select-Object DriveLetter, Size, SizeRemaining
                    }

                # 关联磁盘和卷:OS盘默认匹配C:,数据盘根据LUN或盘符调整
                if ($disk.Id -eq $vm.StorageProfile.OsDisk.ManagedDisk.Id) {
                    $osVolume = $volumeData | Where-Object { $_.DriveLetter -eq 'C:' }
                    $diskInfo.UsedSpaceGB = [math]::Round(($osVolume.Size - $osVolume.SizeRemaining)/1GB, 2)
                    $diskInfo.FreeSpaceGB = [math]::Round($osVolume.SizeRemaining/1GB, 2)
                } else {
                    # 数据盘可根据实际盘符/LUN匹配,这里简化取第一个非C:固定卷
                    $dataVolume = $volumeData | Where-Object { $_.DriveLetter -ne 'C:' } | Select-Object -First 1
                    if ($dataVolume) {
                        $diskInfo.UsedSpaceGB = [math]::Round(($dataVolume.Size - $dataVolume.SizeRemaining)/1GB, 2)
                        $diskInfo.FreeSpaceGB = [math]::Round($dataVolume.SizeRemaining/1GB, 2)
                    }
                }
            }
            elseif ($osType -eq "Linux") {
                # Linux VM:用Invoke-AzVMRunCommand执行shell命令
                $runResult = Invoke-AzVMRunCommand -ResourceGroupName $rgName `
                    -VMName $vmName `
                    -CommandId 'RunShellScript' `
                    -ScriptString "df -h --output=source,size,used,avail | grep -v tmpfs | grep -v devtmpfs"

                # 解析磁盘挂载信息
                $outputLines = $runResult.Value[0].Message -split "`n" | Where-Object { $_ -match '/dev/' }
                $diskLun = ($vm.StorageProfile.DataDisks | Where-Object { $_.ManagedDisk.Id -eq $disk.Id }).Lun

                foreach ($line in $outputLines) {
                    $parts = $line -split '\s+' | Where-Object { $_ }
                    $device = $parts[0]
                    $usedGB = [double]($parts[2] -replace 'G','')
                    $freeGB = [double]($parts[3] -replace 'G','')

                    # 关联磁盘:OS盘匹配/dev/sda类设备,数据盘根据LUN匹配(LUN0对应/dev/sdb,以此类推)
                    if ($disk.Id -eq $vm.StorageProfile.OsDisk.ManagedDisk.Id -and $device -match 'sda') {
                        $diskInfo.UsedSpaceGB = [math]::Round($usedGB, 2)
                        $diskInfo.FreeSpaceGB = [math]::Round($freeGB, 2)
                    } elseif ($diskLun -ne $null) {
                        $expectedDevice = "/dev/sd$(char([int][char]'b' + $diskLun))"
                        if ($device -eq $expectedDevice) {
                            $diskInfo.UsedSpaceGB = [math]::Round($usedGB, 2)
                            $diskInfo.FreeSpaceGB = [math]::Round($freeGB, 2)
                        }
                    }
                }
            }
        }
        catch {
            Write-Warning "无法获取VM $vmName 的磁盘使用数据:$_"
        }

        $diskReport += $diskInfo
    }
}

# 输出最终报表
$diskReport | Format-Table VMName, DiskName, CapacityGB, OSType, ResourceGroupName, UsedSpaceGB, FreeSpaceGB -AutoSize
方案2:用自定义脚本扩展批量收集(适合大量VM)

如果你的VM数量很多,逐个远程连接效率太低,可以用Azure自定义脚本扩展批量在VM上运行收集脚本,把数据统一存储到Azure存储账户,再后续合并分析。

步骤示例

  1. 创建收集磁盘使用情况的脚本(分Windows/Linux):

    • Windows脚本(Collect-DiskUsage.ps1):
      $diskData = Get-Volume | Where-Object { $_.DriveType -eq 'Fixed' } |
          Select-Object @{Name='VMName';Expression={$env:COMPUTERNAME}},
              DriveLetter,
              @{Name='CapacityGB';Expression={[math]::Round($_.Size/1GB,2)}},
              @{Name='UsedSpaceGB';Expression={[math]::Round(($_.Size - $_.SizeRemaining)/1GB,2)}},
              @{Name='FreeSpaceGB';Expression={[math]::Round($_.SizeRemaining/1GB,2)}}
      $diskData | ConvertTo-Json | Out-File "C:\DiskUsage.json"
      # 上传到存储账户
      $storageContext = New-AzStorageContext -StorageAccountName "your-storage-account" -StorageAccountKey "your-storage-key"
      Set-AzStorageBlobContent -File "C:\DiskUsage.json" -Container "disk-usage" -Blob "$env:COMPUTERNAME-DiskUsage.json" -Context $storageContext
      
    • Linux脚本(collect-disk-usage.sh):
      VM_NAME=$(hostname)
      df -h --output=source,size,used,avail | grep -v tmpfs | grep -v devtmpfs | awk -v vm="$VM_NAME" '{print "{\"VMName\":\""vm"\",\"Device\":\""$1"\",\"CapacityGB\":\""$2"\",\"UsedSpaceGB\":\""$3"\",\"FreeSpaceGB\":\""$4"\"}"}' > /tmp/disk-usage.json
      # 上传到存储账户(需要安装azcopy或azure-cli)
      az storage blob upload --account-name your-storage-account --account-key your-storage-key --container-name disk-usage --file /tmp/disk-usage.json --name "$VM_NAME-disk-usage.json"
      
  2. 将脚本上传到Azure存储容器,然后批量部署自定义脚本扩展到所有VM:

    $storageAccount = Get-AzStorageAccount -ResourceGroupName "your-rg" -Name "your-storage-account"
    $allVMs = Get-AzVM
    
    foreach ($vm in $allVMs) {
        if ($vm.StorageProfile.OsDisk.OsType -eq "Windows") {
            Set-AzVMCustomScriptExtension -ResourceGroupName $vm.ResourceGroupName `
                -VMName $vm.Name `
                -Name "CollectDiskUsage" `
                -StorageAccountName $storageAccount.StorageAccountName `
                -StorageAccountKey $storageAccount.Context.StorageAccountKey `
                -ContainerName "scripts" `
                -FileName "Collect-DiskUsage.ps1" `
                -Run "Collect-DiskUsage.ps1"
        } else {
            Set-AzVMCustomScriptExtension -ResourceGroupName $vm.ResourceGroupName `
                -VMName $vm.Name `
                -Name "CollectDiskUsage" `
                -StorageAccountName $storageAccount.StorageAccountName `
                -StorageAccountKey $storageAccount.Context.StorageAccountKey `
                -ContainerName "scripts" `
                -FileName "collect-disk-usage.sh" `
                -Run "collect-disk-usage.sh"
        }
    }
    
  3. 从存储账户下载所有json文件,解析后和Get-AzDisk获取的基础信息合并即可。

关键注意事项
  • VM必须处于运行状态,否则无法远程连接或执行脚本扩展。
  • 网络安全组(NSG)需要开放对应端口:Windows开放5985/5986(WinRM),Linux开放22(SSH)。
  • 远程连接需要VM的本地管理员/root权限,或者配置了Azure AD身份验证的权限。
  • 磁盘与卷/设备的关联逻辑可能需要根据你的实际环境调整(比如Linux的NVMe磁盘设备名是/dev/nvme*而不是/dev/sd*)。

内容的提问来源于stack exchange,提问作者Norrin Rad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:07:52