使用Powershell的Invoke-WebRequest准备XML以进行POST请求

3

提前道歉,对于这里的理解不够和可能之前已经问过这个问题表示抱歉。我曾经认为通过升级到 Powershell v5.1 就可以解决问题,但是事实证明比我想象的更加复杂,所以我将会更新这个问题。

我们一直在 PS version 4.0 上开发脚本,原因是我们的客户使用的是 Windows 2012 R2 服务器,其标准版本为 PS v4.0。然而,如下所示,这个脚本在 v4.x 上无法正常运行。

这是我的代码,其中包含一个正确格式的 xml 片段。

$NETXNUA = "https://gate.sonile.com/ModSoap";
$ContentType = "text/xml";

# tried this and it this doesn't do anything
# [System.Net.ServicePointManager]::Expect100Continue = $false

$RequestBody = @"
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema">
    <SOAP-ENV:Body>
        <sendMessage
        xmlns="http://gate.sonile.com/ModSoap" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <application xsi:type="xsd:string">RuFus</application>
        <password xsi:type="xsd:string">PingPong</password>
        <content xsi:type="xsd:string">Tiddles</content>
        <class xsi:type="xsd:string">mt_bubbles</class>
        </sendMessage>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"@

try {
    $what = Invoke-WebRequest -Uri $NETXNUA -Method Post -Body $RequestBody -ContentType $ContentType -UseBasicParsing;
    }
catch {
    If ($_.Exception.Response.StatusCode.value__) {
    $crap = ($_.Exception.Response.StatusCode.value__ ).ToString().Trim();
    Write-Output "crap $crap";
    }

    If  ($_.Exception.Response.StatusDescription) {
    $crapdescription = ($_.Exception.Response.StatusDescription).ToString().Trim();
    Write-Output "crapdesc $crapdescription";  
    }

    If  ($_.Exception.Message) {
    $crapMessage = ($_.Exception.Message).ToString().Trim();
    Write-Output "crapmsg $crapMessage";
    }

    If  ($_.ErrorDetails.Message) {
    $ResponseBody = ($_.ErrorDetails.Message).ToString().Trim();
    $ResponseBody = $ResponseBody -replace "\s+", " ";
    }

    Write-Output "default $ResponseBody";
}

当我在标准的Powershell中运行此脚本时,以下是发生的情况:

操作系统为Windows 8.1 Pro

Name                           Value                                                                                                          
----                           -----                                                                                                          
PSVersion                      4.0                                                                                                            
WSManStackVersion              3.0                                                                                                            
SerializationVersion           1.1.0.1                                                                                                        
CLRVersion                     4.0.30319.42000                                                                                                
BuildVersion                   6.3.9600.17400                                                                                                 
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}                                                                                           
PSRemotingProtocolVersion      2.2              

以下是结果,注意"$_.Exception.Message"是唯一有值的项。
crapmsg '"utf-8"' is not a supported encoding name. For information on 
defining a custom encoding, see the documentation for the Encoding.Regi
sterProvider method.
Parameter name: name

换句话说,这是一个可悲的失败,但不管信不信,主机处理了帖子数据。
现在,在更新的v5.1 Powershell下,将完全相同的脚本运行在Windows Server 2008 R2上。
Name                           Value                                                                                                            
----                           -----                                                                                                            
PSVersion                      5.1.14409.1005                                                                                                   
PSEdition                      Desktop                                                                                                          
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                          
BuildVersion                   10.0.14409.1005                                                                                                  
CLRVersion                     4.0.30319.42000                                                                                                  
WSManStackVersion              3.0                                                                                                              
PSRemotingProtocolVersion      2.3                                                                                                              
SerializationVersion           1.1.0.1

下面是从"$_.Exception.Message"得到的结果:

crapmsg Value cannot be null.
Parameter name: name

哇,这有些不同,发生了什么事情..?

那么,让我们在安装了 Powershell v5.1 更新的 Windows Server 2012 R2 Azure VM 上再次尝试相同的脚本。

Name                           Value                                                                                       
----                           -----                                                                                       
PSVersion                      5.1.14409.1005                                                                              
PSEdition                      Desktop                                                                                     
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                     
BuildVersion                   10.0.14409.1005                                                                             
CLRVersion                     4.0.30319.42000                                                                             
WSManStackVersion              3.0                                                                                         
PSRemotingProtocolVersion      2.3                                                                                         
SerializationVersion           1.1.0.1  

同样的结果,和2008 R2服务器一样,只有"$_.Exception.Message"返回了内容。至少这是一致的,因为PS版本是相同的。

crapmsg Value cannot be null.
Parameter name: name

我可以尝试在Windows系列中的流浪汉Windows 10 Home版上安装标准的Powershell v5.1来测试这个脚本。

Name                           Value                                                                                                                                                         
----                           -----                                                                                                                                                         
PSVersion                      5.1.14393.1358                                                                                                                                                
PSEdition                      Desktop                                                                                                                                                       
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                       
BuildVersion                   10.0.14393.1358                                                                                                                                               
CLRVersion                     4.0.30319.42000                                                                                                                                               
WSManStackVersion              3.0                                                                                                                                                           
PSRemotingProtocolVersion      2.3                                                                                                                                                           
SerializationVersion           1.1.0.1 

哇,我简直不敢相信……这是个奇迹!它能够完美地工作,并返回一个200响应和一个XML格式的主机响应,我可以对其进行处理。

StatusCode        : 200
StatusDescription : OK
Content           : <?xml version="1.0" encoding="UTF-8"?>
                    <tns1:Envelope 
xmlns:tns1="http://schemas.xmlsoap.org/soap/envelope/">...etc
RawContent        : HTTP/1.1 200 OK
                    Keep-Alive: timeout=15, max=100
                    Connection: Keep-Alive
                    Content-Length: 411
                    Content-Type: text/xml; charset="utf-8"
                    Date: Thu, 06 Jul 2017 04:02:15 GMT
                    Server: Apache
                    Via: 1.1 ga...
Forms             : 
Headers           : {[Keep-Alive, timeout=15, max=100], [Connection, Keep-
Alive], [Content...etc
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : 
RawContentLength  : 411

如果我的客户能够放弃他们喜欢的麻烦的Windows服务器,改用Windows 10,那么一切都会彻底解决!

最新消息!刚试用了Windows Server 2016 Azure VM,也可以正常使用。

Name                           Value                                                                                               
----                           -----                                                                                               
PSVersion                      5.1.14393.479                                                                                       
PSEdition                      Desktop                                                                                             
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                             
BuildVersion                   10.0.14393.479                                                                                      
CLRVersion                     4.0.30319.42000                                                                                     
WSManStackVersion              3.0                                                                                                 
PSRemotingProtocolVersion      2.3                                                                                                 
SerializationVersion           1.1.0.1  

是否有某个秘密参数可以使此脚本在各种平台和版本的PowerShell上正常工作?

我创建的所有其他使用Invoke-WebRequest的脚本都在PS v4和v5上正常工作,只有这个脚本出现了问题。

非常感谢任何提示。

之前我尝试使用文件输入来读取xml,像这样使用-InFile...

Invoke-WebRequest "https://gateway.mobil.com/MSoap" -Method Post -ContentType "text/xml" -InFile "C:\Scripts\mobil.xml" -OutFile "C:\PWScripts\mobil_out.xml"

那个方法可以,但对于我的应用程序来说不太合适。

1
$ContentType 里面是什么?你能包含一下填充它的代码吗? - Patrick Meinecke
补充@PatrickMeinecke的评论:你得到了什么而不是错误?$what包含什么? - G42
感谢您对@PatrickMeinecke的关注,我已经在我的问题中添加了$ContentType。 - rangi
1
@rangi 不错的调试。请查看此帖子,其中建议使用"application/xml"可能会正确处理标头,以及此帖子,详细介绍如何将PowerShell的Unicode编码文本转换为UTF8 - G42
感谢 @gms0ulman。当我们在v5上运行时,惊喜不断!会研究你的建议。 - rangi
似乎有一个无法解决的问题,正如@vane所发布的那样。 - rangi
1个回答

2
在整个星期里,我为这个脚本辛苦工作了无数小时……奇怪的是,它只在成功返回200状态时失败,而错误则完美返回!原来,Invoke-WebRequest存在一个无法克服的问题,正如@vane在2016年4月发布的Why is Invoke-WebRequest and Invoke-RestMethod failing and succeeding at the same time?中所述。因此,如果我错了,请纠正我,唯一已知的解决方案是恢复到标准的http WebRequest调用,类似于以下方式(将其包装在自己的错误处理中);
    $encodedContent = [System.Text.Encoding]::UTF8.GetBytes($RequestBody)

    $webRequest = [System.Net.WebRequest]::Create($NETXNUA)

    $webRequest.Method = "Post"
    $webRequest.ContentType = $ContentType
    $webRequest.ContentLength = $encodedContent.length

    $requestStream = $webRequest.GetRequestStream()
    $requestStream.Write($encodedContent, 0, $encodedContent.length)
    $requestStream.Close()

    [System.Net.WebResponse] $response = $webRequest.GetResponse();

我已验证这种较老的机制在以下平台上完美运行:
Win 8.1 Pro with PS v4.0
Server 2008 R2 with PS 5.1
Server 2012 R2 with PS 5.1 (Azure VM)
Server 2012 R2 with PS v4.0 (Azure VM)
Win 10 Home with PS 5.1 
Server 2016 with PS v5.1 (Azure VM)

我承认Invoke-WebRequest脚本在Win 10和Server 2016上运行得非常完美,所以最终问题会自然消失!
两年后的2019年11月,一个奇怪的发现...!
将设备升级到Windows 10版本1903并开始运行脚本。
立即发现任何使用Invoke-WebRequest的脚本都无法正常工作。
错误是由于Internet Explorer的安装未完成引起的。
安装IE后,Invoke-WebRequest可以正常运行。
教训:你永远无法完全摆脱IE。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接