You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何通过PowerShell调用vSphere REST API精准获取指定数据存储下的虚拟机列表

如何通过PowerShell调用vSphere REST API精准获取指定数据存储下的虚拟机列表

我明白你现在的困扰——想通过PowerShell结合vSphere REST API关联数据存储与它下面的虚拟机,但用filter.datastores参数好像没得到预期结果。让我帮你排查问题并修正脚本,确保能精准拿到每个数据存储对应的VM列表。

问题分析

你的核心逻辑方向是对的:先获取所有数据存储,再遍历每个存储的ID去过滤虚拟机。可能导致filter.datastores不生效的原因主要有两个:

  1. 部分vSphere版本中,filter.datastores需要严格遵循数组参数格式(哪怕只传单个ID)
  2. 脚本中未初始化全局累加变量,会导致使用率计算异常
  3. 缺少错误处理,单个请求失败会直接中断整个脚本

修正后的完整可运行脚本

# 辅助函数:MiB转MB(保留两位小数,符合日常认知的MB单位)
function Convert-MiBtoMB {
    param (
        [double]$MiBValue
    )
    $MBValue = $MiBValue * ([Math]::Pow(2, 20) / [Math]::Pow(10, 6))
    return [Math]::Round($MBValue, 2)
}

# -------------------------- 配置参数区 --------------------------
$server = "your-vcenter-server.fqdn"  # 替换为你的vCenter地址
$user = "your-admin-account"           # 替换为有权限的账号
$pass = "your-password"                # 替换为对应密码
$threshold = 80                        # 存储使用率告警阈值(百分比)
# ----------------------------------------------------------------

# 1. 获取vCenter会话ID(替代Basic Auth,更安全合规)
$basicAuthHeaders = @{
    "Authorization" = "Basic $([Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$user`:$pass")))"
}

# 处理自签名证书警告(生产环境建议导入vCenter的CA证书,不要用这个临时方案)
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
        ServicePoint srvPoint, X509Certificate certificate,
        WebRequest request, int certificateProblem) {
        return true;
    }
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls13

try {
    $sessionId = Invoke-RestMethod -Method POST -Uri "https://$server/api/session" -Headers $basicAuthHeaders -UseBasicParsing
    $sessionHeaders = @{ "vmware-api-session-id" = $sessionId }
    Write-Host "✅ 成功获取vCenter会话ID"
}
catch {
    Write-Error "❌ 获取vCenter会话失败:$($_.Exception.Message)"
    exit 1
}

# 2. 获取所有数据存储基础信息
try {
    $dataStores = (Invoke-RestMethod -Method GET -Uri "https://$server/rest/vcenter/datastore" -Headers $sessionHeaders -UseBasicParsing).value
    Write-Host "✅ 成功获取$($dataStores.Count)个数据存储"
}
catch {
    Write-Error "❌ 获取数据存储列表失败:$($_.Exception.Message)"
    exit 1
}

# 3. 遍历每个数据存储,关联虚拟机并计算使用率
$alertMessages = @()
foreach ($ds in $dataStores) {
    $dsId = $ds.datastore
    $dsName = $ds.name
    # 用PowerShell内置单位转换简化计算,比手动算幂更直观
    $dsFreeSpaceMiB = $ds.free_space / 1MiB
    $dsCapacityMiB = $ds.capacity / 1MiB
    $dsUsedSpaceMiB = $dsCapacityMiB - $dsFreeSpaceMiB
    $dsUsedPercent = [Math]::Round(($dsUsedSpaceMiB / $dsCapacityMiB) * 100, 2)

    # 3.1 精准获取当前存储下的虚拟机(修复Filter参数格式)
    try {
        # 注意:部分vCenter版本需要加[]明确数组参数,去掉[]也能生效可根据环境调整
        $vmUri = "https://$server/rest/vcenter/vm?filter.datastores[]=$dsId"
        $dsVms = (Invoke-RestMethod -Method GET -Uri $vmUri -Headers $sessionHeaders -UseBasicParsing).value
        Write-Host `n📦 数据存储[$dsName] 已找到$($dsVms.Count)台虚拟机
    }
    catch {
        Write-Warning "⚠️ 获取数据存储[$dsName]的虚拟机列表失败:$($_.Exception.Message)"
        $dsVms = @()
    }

    # 3.2 遍历输出当前存储下的VM信息
    $totalVmMemoryTB = 0
    foreach ($vm in $dsVms) {
        $vmName = $vm.name
        $vmMemoryMiB = $vm.memory_size_MiB
        $vmMemoryTB = $vmMemoryMiB / 1TiB
        $totalVmMemoryTB += $vmMemoryTB

        Write-Host "  └─ $vmName | 内存:$([Math]::Round($vmMemoryMiB,0)) MiB"
    }

    # 3.3 检查使用率是否触发阈值告警
    if ($dsUsedPercent -ge $threshold) {
        $freeSpaceMB = Convert-MiBtoMB $dsFreeSpaceMiB
        $alertMessages += "⚠️ 数据存储[$dsName]使用率超标:$dsUsedPercent% | 剩余空间:$freeSpaceMB MB"
    }
}

# 4. 输出最终告警汇总
Write-Host "`n==================== 告警汇总 ===================="
if ($alertMessages.Count -eq 0) {
    Write-Host "✅ 所有数据存储使用率均在阈值范围内"
} else {
    foreach ($msg in $alertMessages) {
        Write-Host $msg
    }
}

# 5. 清理会话(符合vCenter安全最佳实践)
try {
    Invoke-RestMethod -Method DELETE -Uri "https://$server/api/session" -Headers $sessionHeaders -UseBasicParsing
    Write-Host "`n✅ 已销毁vCenter会话"
}
catch {
    Write-Warning "⚠️ 销毁会话失败:$($_.Exception.Message)"
}

关键修改点说明

  1. 修复Filter参数有效性
    部分vCenter的REST框架要求数组参数带[]后缀,所以用filter.datastores[]=$dsId替代原格式,确保过滤逻辑精准生效。如果你的环境去掉[]也能拿到正确结果,也可以直接调整。

  2. 简化单位计算
    用PowerShell内置的单位后缀(1MiB1TiB)替代手动计算[Math]::Pow,代码更易读且不易出错。

  3. 完善错误处理
    给每个API请求加try/catch,单个存储或VM请求失败不会中断整个脚本,还会给出明确的警告信息。

  4. 会话安全优化
    脚本末尾调用DELETE /api/session销毁会话,避免无效会话残留;同时用会话ID认证替代全程Basic Auth,更符合vCenter安全规范。

快速验证方法

如果想单独测试Filter参数是否生效,可以直接在Postman或浏览器中发请求:

GET https://your-vcenter/rest/vcenter/vm?filter.datastores[]=datastore-123
Headers: vmware-api-session-id=你的会话ID

如果返回的VM列表正确,说明参数格式没问题;如果返回所有VM,大概率是当前用户没有该存储下VM的读取权限,或者数据存储ID填写错误。

扩展建议

如果需要更精准的存储使用率统计(比如VM的磁盘实际占用),可以调用/rest/vcenter/vm/{vm-id}/hardware/disk接口,获取每个VM的磁盘大小和对应的存储信息,这样计算的存储使用情况会比内存统计更贴合实际。

火山引擎 最新活动