json Powershell调用-REST方法:发送PUT请求时未正确解释正文内容

lvjbypge  于 2023-03-09  发布在  Shell
关注(0)|答案(1)|浏览(154)

我已经在powershell脚本中使用Invoke-RestMethod构建了一个PUT请求。
此请求类似于:

# Main global var
$securePassword = ConvertTo-SecureString -String $pat -AsPlainText
$credential = [PSCredential]::new($username, $securePassword)
$organization = "myorganization"
$project = "myproject"
$username = "username"
$pat = "myRandomPatFromAzureDevOps"
# AZDO build env var
$buildNumber = "test1.0"
# AZDO Wiki global vars
$page = "Release-Notes-$buildNumber"

$Body = [PsCustomObject]@{ 
    "content" = "$results"
} | ConvertTo-Json 

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")

Invoke-RestMethod -Uri "https://dev.azure.com/$organization/$project/_apis/wiki/wikis/MyWiki.wiki/pages?path=$page&api-version=7.0" -Method 'PUT' -Authentication Basic -Credential $credential -Headers $headers -Body $Body

正如我们在azure devops rest API上看到的,为了在wiki存储库here中添加内容,为了更新wiki,我必须在RequestBody中给予一个名为content的字符串格式参数。
下面是传递给content参数的var $results的内容:

|Id|AreaPath|IterationPath|WorkItemType|State|Title|CloseDate|
|---------|---------------|--------------------|-------------------|------------|------------|--------------------------------|
|8888|Parts Unlimited Team|Parts Unlimited Sprint 2023-03|Bug|Closed|Parts Unlimited Sprint log security password|03-03-2023 13:31:37|
|9999|Parts Unlimited Team|Parts Unlimited Sprint 2023-03|Task|Closed|Parts Unlimited SprintAutomatisation APIs |03-01-2023 08:32:31|

正如你所看到的,我试图将MarkDown表作为字符串传递,为了将结果格式化,我找到并使用了一个名为ConvertTo-MarkDownTable的函数:

function ConvertTo-MarkDownTable {
    [CmdletBinding()] param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] 
        $InputObject
    )
    Begin { 
        $headersDone = $false
        $pattern = '(?<!\\)\|'  # escape every '|' unless already escaped
    }
    Process {
        if (!$headersDone) {
            $headersDone = $true
            # output the header line and below that a dashed line
            # -replace '(?<!\\)\|', '\|' escapes every '|' unless already escaped
            "`n|{0}|" -f (($_.PSObject.Properties.Name -replace $pattern, '\|') -join '|')
            "`n|{0}|" -f (($_.PSObject.Properties.Name -replace '.', '-') -join '|')
        }
        "`n|{0}|" -f (($_.PsObject.Properties.Value -replace $pattern, '\|') -join '|')
    }
}

$results中的初始数据是我从Azure DevOps Rest API的GET方法中恢复的值。当我看到$results的类型时,我看到的是:

# $results.GetType()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

现在,当我运行Invoke-RestMethod时,在bodycontent参数中发送注解:

Invoke-RestMethod -Uri "https://dev.azure.com/$organization/$project/_apis/wiki/wikis/MyWiki.wiki/pages?path=$page&api-version=7.0" -Method 'PUT' -Authentication Basic -Credential $credential -Headers $headers -Body $Body

Output :
path        : /path-to-push-content
order       : 1
gitItemPath : /path%2Dto%2Dcontent.md
subPages    : {}
url         : https://dev.azure.com/myorganization/id-of-event-etag/_apis/wiki/wikis/fid-of-wiki-request/pages
              /%2Fpath-to-push-content
remoteUrl   : https://dev.azure.com/myorganization/id-of-event-etag/_wiki/wikis/fid-of-wiki-request?pagePath=%
              2Fpath-to-push-content
id          : randomId
content     :

但是我已经用POSTMAN测试了这个请求,一切都运行良好,这就是请求:

如您所见,结果被正确地解析和解释。
这是Azure devops wiki上的上传内容:

为什么我的PUT方法请求不能像POSTMAN那样在powershell脚本中发送内容?

hc2pp10m

hc2pp10m1#

由于您传递的媒体类型为application/json

  • 必须将JSON * 字符串 * 传递给Invoke-WebRequest-Body参数
  • 由于$results是一个行的 array,因此必须手动将其元素与换行符连接起来,以形成一个多行字符串:$results -join "n"。如果您依赖于可扩展字符串("$results"`)内部的隐式字符串化,则使用 spaces 连接元素。
  • PowerShell不会自动为您将[pscustomobject]hashtable转换为JSON。

因此,请使用ConvertTo-Json按如下方式构造$Body变量:

$Body = @{ 
  "content" = $results -join "`n"
} | ConvertTo-Json
  • 请注意,传递 hashtable 而不是[pscustomobject]就足够了。
  • 一般警告(此处不适用):嵌套更深的对象/哈希表可能会被 truncated,除非你传递一个足够高的-Depth值给ConvertTo-Json-参见this post

下面是一个自包含的示例,它演示了传递给-Body的JSON字符串是否正确发布:

  • https://postman-echo.com/put * 回显 * 它返回的JSON响应的data属性中的输入JSON。
  • 使用Invoke-RestMethod而不是Invoke-WebRequest会自动将JSON响应解析为[pscustomobject]图,这样更容易将成功的往返过程可视化。
$results = @'
|Id|AreaPath|IterationPath|WorkItemType|State|Title|CloseDate|
|---------|---------------|--------------------|-------------------|------------|------------|--------------------------------|
|8888|Parts Unlimited Team|Parts Unlimited Sprint 2023-03|Bug|Closed|Parts Unlimited Sprint log security password|03-03-2023 13:31:37|
|9999|Parts Unlimited Team|Parts Unlimited Sprint 2023-03|Task|Closed|Parts Unlimited SprintAutomatisation APIs |03-01-2023 08:32:31|
'@

$body = @{ 
  "content" = $results
} | ConvertTo-Json 

(
  Invoke-RestMethod https://postman-echo.com/put `
    -Method PUT `
    -ContentType application/json `
    -Body $body
).data |
  Format-List

输出,显示$results值已正确提交:

content : |Id|AreaPath|IterationPath|WorkItemType|State|Title|CloseDate|
          |---------|---------------|--------------------|-------------------|------------|------------|--------------------------------|
          |8888|Parts Unlimited Team|Parts Unlimited Sprint 2023-03|Bug|Closed|Parts Unlimited Sprint log security password|03-03-2023 13:31:37|
          |9999|Parts Unlimited Team|Parts Unlimited Sprint 2023-03|Task|Closed|Parts Unlimited SprintAutomatisation APIs |03-01-2023 08:32:31|

相关问题