我怎样才能使 Invoke-Webrequest 请求所有页面?

How can I make this Invoke-Webrequest ask for all the pages?

下面的命令遍历一个包含 activity ID 号码的文件,并发送一个请求来检查哪些成员参加了这个 activity。这是批处理文件中的 PowerShell 命令。

Powershell "Get-Content .\idsonly.txt | ForEach-Object {Invoke-WebRequest -Method Get -Headers @{ \"api-version\" = \"2\" ; \"Authorization\" = \"Bearer %token%\"} -Uri %uri%/$_/Members?pagesize=100`&fields=memberid`,hasattended | Select-Object -Expand Content}" ">> memberssact.txt"

问题是有些活动有超过 100 名成员参加,这只会为每个 activity 提供前 100 名成员。如果有的话,我如何让它要求额外的页面?可能返回的最大结果数为 100 和 .

可能性(但我不知道如何实现):

  1. 我在与会者人数旁边有一个 activity ID 列表,从中我可以计算出与会者列表将有多少页。

  2. 如果还有更多页面,响应 header 中会出现“下一页 url”(但如果有,我该如何告诉 PowerShell 获取它? )

  3. 最不喜欢,但可以 brute-force 增加请求的页面数量并告诉它在没有收到响应时停止,但不确定如何。

我在下面提供了一个示例回复 header:

{
  "access-control-expose-headers": "Request-Context",
  "cache-control": "no-cache",
  "content-length": "2",
  "content-security-policy": "default-src 'self' ;base-uri 'self';  object-src 'none'; connect-src 'self'; worker-src 'none'; upgrade-insecure-requests; frame-ancestors 'self'; child-src 'self'; frame-src 'self'; manifest-src 'self'; prefetch-src 'self'; ; font-src 'self' fonts.gstatic.com data:; img-src 'self' data: *.ac.uk *.swagger.io; media-src 'self' ; script-src 'self' 'unsafe-inline' 'report-sample'; style-src 'self' fonts.googleapis.com 'unsafe-inline' 'report-sample' https://fonts.googleapis.com; report-uri /log",
  "content-type": "application/json; charset=utf-8",
  "date": "Mon, 23 May 2022 15:37:06 GMT",
  "expires": "0",
  "last-modified": "Mon, 23 May 2022 15:37:07 GMT",
  "pragma": "no-cache",
  "request-context": "appId=cid-v1:3abf1c0e-2963-49e7-bc48-18ed8b04daa3",
  "strict-transport-security": "max-age=31536000",
  "x-content-type-options": "nosniff",
  "x-frame-options": "DENY",
  "x-pagination": "{\"currentPage\":3,\"pageSize\":100,\"totalCount\":178,\"totalPages\":2,\"previousPageLink\":\"https://url.uk/activities/597850/students?page=2&pageSize=100&sort=hasattended&fields=studentID%2Chasattended\",\"nextPageLink\":\"\"}",
  "x-xss-protection": "1; mode=block"
}

由于您提供了示例响应 header,我更新了下面的代码示例并提供了其工作原理的解释:

Note: This example is not invoking PowerShell as a one-liner. You should move this piece to a script with a parameter for each %VARIABLE% you use in your original command. $Token and $Uri are the variables I've changed to a PowerShell format. I have also removed otherwise-unnecessary string escapes. This could be modified to be a one-liner of course, but for any real scripting logic it should be part of its own script, function, etc.

Param(
  [string]$Token,
  [string]$Uri,
  [string]$IdsFile
)

$ids = Get-Content $idsFile

foreach( $id in $ids ) {

  $nextUri = "$Uri/$id/Members?pagesize=100&fields=memberid,hasattended"

  while( $nextUri ) {
    $response = Invoke-WebRequest -Method Get -Headers @{
      "api-version" = "2"
      Authorization = "Bearer $Token"
    } -Uri $nextUri

    $response.Content >> membersacct.txt
  
    $paginationHeader = $response.Headers.'x-pagination' | ConvertFrom-Json
    $nextUri = $paginationHeader.nextPageLink
  }
}

本质上,它的作用是:

  • 添加了输入参数以方便您使用的 CMD 变量,并允许您提供 idsonly.txt 文件的文件路径。这可以与 PowerShell 脚本一起使用,也可以在 PowerShell 函数定义中使用。
  • $nextUri 设置为您要从
  • 获得结果的初始 URL
  • 执行网络请求,分配给$response变量
  • 写入(追加)$response.Content 到文件
  • 使用 ConvertFrom-JSONx-pagination header 值转换为 PowerShell object。
    • 这会导致 object 比您可能需要的更大,但它会处理 JSON 的解析,因此您不必这样做。
  • 设置$nextUri到下一页,即使没有下一页
  • 如果没有$nextPagewhile循环就会退出
    • 这取决于$nextUri的真实性;换句话说,空字符串的计算结果为 $False,而任何其他字符串值的计算结果为 $True.