Get-UsageAggregates 中 continuationtoken 参数无效
结论
第一次调用 Get-UsageAggregates 时,不要传入空的 -ContinuationToken。只有上一页响应返回了非空令牌,才能添加该参数。令牌必须原样传递,不能用完整的 NextLink 代替,也不要自行拼接、截断或重复编码。
出现这类错误,通常不是因为订阅没有用量数据,而是脚本向接口发送了无效参数,例如:
continuationtoken=
原因
-ContinuationToken 用于分页。第一次请求没有上一页,自然不需要这个参数。
一些旧脚本会先把变量初始化为空,然后在调用命令时无条件传入:
$continuationToken = $null
Get-UsageAggregates `
-ReportedStartTime $reportedStartTime `
-ReportedEndTime $reportedEndTime `
-ContinuationToken $continuationToken
即使 PowerShell 变量是 $null 或空字符串,旧版 cmdlet 仍可能把这个参数提交给服务端。服务端发现参数存在,却没有有效值,就会返回:
InvalidInput: Parameter continuationtoken was missing or had an unacceptable value.
后续分页请求也可能遇到相同错误。常见原因包括传入了完整的 NextLink,或者对令牌又做了一次 URL 编码。
处理方法
第一次请求应完全省略 -ContinuationToken:
$usageData = Get-UsageAggregates `
-ReportedStartTime $reportedStartTime `
-ReportedEndTime $reportedEndTime `
-AggregationGranularity Daily `
-ShowDetails
如果响应对象提供了 ContinuationToken,再继续获取后续页面:
$allUsage = @()
$usageData = Get-UsageAggregates `
-ReportedStartTime $reportedStartTime `
-ReportedEndTime $reportedEndTime `
-AggregationGranularity Daily `
-ShowDetails
$allUsage += $usageData.UsageAggregations
while (-not [string]::IsNullOrWhiteSpace($usageData.ContinuationToken)) {
$usageData = Get-UsageAggregates `
-ReportedStartTime $reportedStartTime `
-ReportedEndTime $reportedEndTime `
-AggregationGranularity Daily `
-ShowDetails `
-ContinuationToken $usageData.ContinuationToken
$allUsage += $usageData.UsageAggregations
}
ContinuationToken 为空时应结束循环,不要继续发送空参数。
使用参数集合避免空值
如果现有脚本不方便分别处理第一次请求和后续请求,可以使用 splatting 动态添加参数:
$continuationToken = $null
$allUsage = @()
do {
$parameters = @{
ReportedStartTime = $reportedStartTime
ReportedEndTime = $reportedEndTime
AggregationGranularity = 'Daily'
ShowDetails = $true
}
if (-not [string]::IsNullOrWhiteSpace($continuationToken)) {
$parameters['ContinuationToken'] = $continuationToken
}
$usageData = Get-UsageAggregates @parameters
$allUsage += $usageData.UsageAggregations
$continuationToken = $usageData.ContinuationToken
}
while (-not [string]::IsNullOrWhiteSpace($continuationToken))
这样可以确保第一次请求中没有 ContinuationToken 参数。
如果响应只有 NextLink
不同版本的 Azure PowerShell 模块可能采用不同的返回结构。如果对象没有 ContinuationToken,只有 NextLink,需要从查询字符串中提取令牌,不能把整个链接直接传给 -ContinuationToken:
$continuationToken = $null
if ($usageData.NextLink -match '[?&]continuationtoken=([^&]+)') {
$continuationToken = [System.Uri]::UnescapeDataString($matches[1])
}
提取令牌后,仍要先检查它是否为空:
if (-not [string]::IsNullOrWhiteSpace($continuationToken)) {
$usageData = Get-UsageAggregates `
-ReportedStartTime $reportedStartTime `
-ReportedEndTime $reportedEndTime `
-AggregationGranularity Daily `
-ShowDetails `
-ContinuationToken $continuationToken
}
如果响应对象已经包含 ContinuationToken 属性,应优先使用该属性,避免自行解析 NextLink。
仍然报错时的检查项
可以先查看实际传入的值:
$continuationToken | Format-Hex
也可以检查长度:
$continuationToken.Length
需要逐项确认:
- 令牌是否为
$null、空字符串或只包含空白字符。 - 是否误将完整的
NextLink传给了-ContinuationToken。 - 是否调用过
Trim()或字符串拆分等操作,导致令牌被截断。 - 是否对已经编码的令牌再次进行了 URL 编码。
- 是否保存令牌后隔了较长时间才继续请求。分页令牌通常只用于紧接着获取下一页,不应作为长期凭据保存。
ReportedStartTime和ReportedEndTime是否有效,以及开始时间是否早于结束时间。
关于旧版命令
Get-UsageAggregates 是较早期的 Azure 用量查询方式。旧博客中提到的模块名称、返回对象和分页行为,可能与当前环境不同。如果删除空令牌后仍然失败,可以先确认实际使用的模块和命令来源:
Get-Command Get-UsageAggregates | Format-List Name, Source, Version
如果仍需维护旧脚本,直接按上述方式修正分页逻辑即可。新建成本或用量采集程序时,应优先评估当前的 Azure Cost Management API、导出功能或对应的新版 PowerShell 命令。旧博客中的接口和模块不适合作为新系统的长期依赖。
备注:内容仅供参考。