Fixing 'InFile parameter of Invoke-WebRequest doesn't work' and adding aliases (iwr for invoke-webrequest and irm for invoke-restmethod) to the web cmdlets. (#2848)

* Fixing Invoke-WebRequest InFile parameter

* Adding aliases for Invoke-RestMethod and Invoke-WebRequest

* Adding test cases for Web cmdlets -InFile parameter

* Adding tests for Invoke-WebRequest (iwr) and Invoke-RestMethod (irm) using the cmdlet aliases.

* Remove the extra leading space
This commit is contained in:
Francisco Gamino 2017-02-01 10:14:24 -08:00 committed by Dongbo Wang
parent 1431105251
commit 89a5c17d6b
3 changed files with 175 additions and 51 deletions

View File

@ -280,10 +280,7 @@ namespace Microsoft.PowerShell.Commands
try try
{ {
// open the input file // open the input file
using (FileStream fs = new FileStream(InFile, FileMode.Open)) SetRequestContent(request, new FileStream(InFile, FileMode.Open));
{
SetRequestContent(request, fs);
}
} }
catch (UnauthorizedAccessException) catch (UnauthorizedAccessException)
{ {
@ -331,55 +328,57 @@ namespace Microsoft.PowerShell.Commands
// Set cmdlet context for write progress // Set cmdlet context for write progress
ValidateParameters(); ValidateParameters();
PrepareSession(); PrepareSession();
HttpClient client = GetHttpClient();
HttpRequestMessage request = GetRequest(Uri);
FillRequestStream(request);
try using (HttpClient client = GetHttpClient())
using (HttpRequestMessage request = GetRequest(Uri))
{ {
long requestContentLength = 0; FillRequestStream(request);
if (request.Content != null) try
requestContentLength = request.Content.Headers.ContentLength.Value;
string reqVerboseMsg = String.Format(CultureInfo.CurrentCulture,
"{0} {1} with {2}-byte payload",
request.Method,
request.RequestUri,
requestContentLength);
WriteVerbose(reqVerboseMsg);
HttpResponseMessage response = GetResponse(client, request);
response.EnsureSuccessStatusCode();
string contentType = ContentHelper.GetContentType(response);
string respVerboseMsg = string.Format(CultureInfo.CurrentCulture,
"received {0}-byte response of content type {1}",
response.Content.Headers.ContentLength,
contentType);
WriteVerbose(respVerboseMsg);
ProcessResponse(response);
UpdateSession(response);
// If we hit our maximum redirection count, generate an error.
// Errors with redirection counts of greater than 0 are handled automatically by .NET, but are
// impossible to detect programmatically when we hit this limit. By handling this ourselves
// (and still writing out the result), users can debug actual HTTP redirect problems.
if (WebSession.MaximumRedirection == 0) // Indicate "HttpClientHandler.AllowAutoRedirect == false"
{ {
if (response.StatusCode == HttpStatusCode.Found || long requestContentLength = 0;
response.StatusCode == HttpStatusCode.Moved || if (request.Content != null)
response.StatusCode == HttpStatusCode.MovedPermanently) requestContentLength = request.Content.Headers.ContentLength.Value;
string reqVerboseMsg = String.Format(CultureInfo.CurrentCulture,
"{0} {1} with {2}-byte payload",
request.Method,
request.RequestUri,
requestContentLength);
WriteVerbose(reqVerboseMsg);
HttpResponseMessage response = GetResponse(client, request);
response.EnsureSuccessStatusCode();
string contentType = ContentHelper.GetContentType(response);
string respVerboseMsg = string.Format(CultureInfo.CurrentCulture,
"received {0}-byte response of content type {1}",
response.Content.Headers.ContentLength,
contentType);
WriteVerbose(respVerboseMsg);
ProcessResponse(response);
UpdateSession(response);
// If we hit our maximum redirection count, generate an error.
// Errors with redirection counts of greater than 0 are handled automatically by .NET, but are
// impossible to detect programmatically when we hit this limit. By handling this ourselves
// (and still writing out the result), users can debug actual HTTP redirect problems.
if (WebSession.MaximumRedirection == 0) // Indicate "HttpClientHandler.AllowAutoRedirect == false"
{ {
ErrorRecord er = new ErrorRecord(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request); if (response.StatusCode == HttpStatusCode.Found ||
er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded); response.StatusCode == HttpStatusCode.Moved ||
WriteError(er); response.StatusCode == HttpStatusCode.MovedPermanently)
{
ErrorRecord er = new ErrorRecord(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request);
er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded);
WriteError(er);
}
} }
} }
} catch (HttpRequestException ex)
catch (HttpRequestException ex) {
{ ErrorRecord er = new ErrorRecord(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request);
ErrorRecord er = new ErrorRecord(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); ThrowTerminatingError(er);
ThrowTerminatingError(er); }
} }
} }
catch (CryptographicException ex) catch (CryptographicException ex)

View File

@ -5108,6 +5108,11 @@ end
"Stop-Service", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), "Stop-Service", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("sv", new SessionStateAliasEntry("sv",
"Set-Variable", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), "Set-Variable", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
// Web cmdlets aliases
new SessionStateAliasEntry("irm",
"Invoke-RestMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("iwr",
"Invoke-WebRequest", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
// Porting note: #if !UNIX is used to disable aliases for cmdlets which conflict with Linux / OS X // Porting note: #if !UNIX is used to disable aliases for cmdlets which conflict with Linux / OS X
#if !UNIX #if !UNIX
// ac is a native command on OS X // ac is a native command on OS X
@ -5175,10 +5180,6 @@ end
"Get-PSSnapIn", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), "Get-PSSnapIn", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("gwmi", new SessionStateAliasEntry("gwmi",
"Get-WmiObject", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), "Get-WmiObject", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("irm",
"Invoke-RestMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("iwr",
"Invoke-WebRequest", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("iwmi", new SessionStateAliasEntry("iwmi",
"Invoke-WMIMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope), "Invoke-WMIMethod", "", ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope),
new SessionStateAliasEntry("ogv", new SessionStateAliasEntry("ogv",

View File

@ -643,3 +643,127 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" {
$result.Error | Should BeNullOrEmpty $result.Error | Should BeNullOrEmpty
} }
} }
Describe "Validate Invoke-WebRequest and Invoke-RestMethod -InFile" -Tags "Feature" {
Context "InFile parameter negative tests" {
$testCases = @(
#region INVOKE-WEBREQUEST
@{
Name = 'Validate error for Invoke-WebRequest -InFile ""'
ScriptBlock = {Invoke-WebRequest -Uri http://httpbin.org/post -Method Post -InFile ""}
ExpectedFullyQualifiedErrorId = 'WebCmdletInFileNotFilePathException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand'
}
@{
Name = 'Validate error for Invoke-WebRequest -InFile'
ScriptBlock = {Invoke-WebRequest -Uri http://httpbin.org/post -Method Post -InFile}
ExpectedFullyQualifiedErrorId = 'MissingArgument,Microsoft.PowerShell.Commands.InvokeWebRequestCommand'
}
@{
Name = "Validate error for Invoke-WebRequest -InFile $TestDrive\content.txt"
ScriptBlock = {Invoke-WebRequest -Uri http://httpbin.org/post -Method Post -InFile $TestDrive\content.txt}
ExpectedFullyQualifiedErrorId = 'PathNotFound,Microsoft.PowerShell.Commands.InvokeWebRequestCommand'
}
#endregion
#region INVOKE-RESTMETHOD
@{
Name = "Validate error for Invoke-RestMethod -InFile ''"
ScriptBlock = {Invoke-RestMethod -Uri http://httpbin.org/post -Method Post -InFile ''}
ExpectedFullyQualifiedErrorId = 'WebCmdletInFileNotFilePathException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand'
}
@{
Name = "Validate error for Invoke-RestMethod -InFile <null>"
ScriptBlock = {Invoke-RestMethod -Uri http://httpbin.org/post -Method Post -InFile}
ExpectedFullyQualifiedErrorId = 'MissingArgument,Microsoft.PowerShell.Commands.InvokeRestMethodCommand'
}
@{
Name = "Validate error for Invoke-RestMethod -InFile $TestDrive\content.txt"
ScriptBlock = {Invoke-RestMethod -Uri http://httpbin.org/post -Method Post -InFile $TestDrive\content.txt}
ExpectedFullyQualifiedErrorId = 'PathNotFound,Microsoft.PowerShell.Commands.InvokeRestMethodCommand'
}
#endregion
)
It "<Name>" -TestCases $testCases {
param ($scriptblock, $expectedFullyQualifiedErrorId)
try
{
& $scriptblock
throw "No Exception!"
}
catch
{
$_.FullyQualifiedErrorId | should be $ExpectedFullyQualifiedErrorId
}
}
}
Context "InFile parameter positive tests" {
BeforeAll {
$filePath = Join-Path $TestDrive test.txt
New-Item -Path $filePath -Value "hello" -ItemType File -Force
}
It "Invoke-WebRequest -InFile" {
$result = Invoke-WebRequest -InFile $filePath -Uri http://httpbin.org/post -Method Post
$content = $result.Content | ConvertFrom-Json
$content.form | Should Match "hello"
}
It "Invoke-RestMethod -InFile" {
$result = Invoke-RestMethod -InFile $filePath -Uri http://httpbin.org/post -Method Post
$result.form | Should Match "hello"
}
}
}
Describe "Web cmdlets tests using the cmdlet's aliases" -Tags "CI" {
function SearchEngineIsOnline
{
param (
[ValidateNotNullOrEmpty()]
$webAddress
)
$ping = new-object System.Net.NetworkInformation.Ping
$sendPing = $ping.SendPingAsync($webAddress)
return ($sendPing.Result.Status -eq "Success")
}
# Make sure either www.bing.com or www.google.com are online to send a request.
$endPointToUse = $null
foreach ($uri in @("www.bing.com", "www.google.com"))
{
if (SearchEngineIsOnline $uri)
{
$endPointToUse = $uri
break
}
}
# If neither www.bing.com nor www.google.com are online, then skip the tests.
$skipTests = ($endPointToUse -eq $null)
$finalUri = $endPointToUse + "?q=how+many+feet+in+a+mile"
It "Execute Invoke-WebRequest --> 'iwr -URI $finalUri'" -Skip:$skipTests {
$result = iwr -URI $finalUri -TimeoutSec 5
$result.StatusCode | Should Be "200"
$result.Links | Should Not Be $null
}
It "Execute Invoke-RestMethod --> 'irm -URI $finalUri'" -Skip:$skipTests {
$result = irm -URI $finalUri -TimeoutSec 5
foreach ($word in @("200", "how", "many", "feet", "in", "mile"))
{
$result | Should Match $word
}
}
}