The following was developed to capture the HTTP Response (if you use the CuRL argument, -w "%{http_code}") , STD Out, STD Err and the Curl Exit Code. It will also detect the received response text encoding and convert it to UTF-8.
#region CuRL
#region Default_Values
$CurlPath = "C:\Windows\System32"; ## Where CuRL.exe is installed; by default it uses the built-in Windows version
#endregion Default_Values
function Convert-StringEncoding {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][AllowNull()][AllowEmptyString()][String]$string,
[Parameter(Mandatory=$true)][System.Text.Encoding]$inputEncoding,
[System.Text.Encoding]$outputEncoding = [System.Text.Encoding]::UTF8
)
[string]$ret = $string;
if (![string]::IsNullOrWhiteSpace($string)) {
if ($inputEncoding -ne $outputEncoding) {
$bytesArr = $inputEncoding.getbytes($string);
$ret = $outputEncoding.GetString($bytesArr);
}
}
return $ret;
}
function Invoke-CuRL {
PARAM (
[Parameter(Mandatory=$TRUE,ValuefromPipeline=$True)][string]$Arguments,
[switch]$ShowAll,
[switch]$NoConvertStdOutFromJSON,
[switch]$UseInvokeExpression,
[switch]$HideExitCodeError
)
Process {
$out = @{}
$out = [hashtable]::Synchronized($out);
if ($UseInvokeExpression.IsPresent -and !$ShowAll.IsPresent) {
### The less informative way; equivalent to just STDOUT. Note: not setup for using parameter, -w '%{http_code}'
$JSON = Invoke-Expression "&`"$CurlPath\curl.exe`" $Arguments ";
if (![string]::IsNullOrWhiteSpace($JSON) -and !$NoConvertStdOutFromJSON.IsPresent) {
$ret = $JSON | ConvertFrom-Json -ErrorAction SilentlyContinue -WarningAction SilentlyContinue;
}
} else {
[System.Diagnostics.ProcessStartInfo]$pinfo = [System.Diagnostics.ProcessStartInfo]::new("$CurlPath\curl.exe");
$pinfo.Arguments = $Arguments -replace "'", '"'; ##ProcessInfo hates single quotes##
$pinfo.RedirectStandardError = $true;
$pinfo.RedirectStandardOutput = $true;
$pinfo.UseShellExecute = $tru;
$pinfo.CreateNoWindow = $true;
$pinfo.Verb = "open";
$pinfo.LoadUserProfile = $true;
[System.Diagnostics.Process]$p = [System.Diagnostics.Process]::new();
$p.StartInfo = $pinfo;
try {
if ($p.Start()) {
$soe = $p.StandardOutput.CurrentEncoding;
$so = $p.StandardOutput.ReadToEnd();
$see = $p.StandardError.CurrentEncoding;
$se = $p.StandardError.ReadToEnd();
$out["exitcode"] = $p.ExitCode;
$p.WaitForExit();
$out["stdout"] = Convert-StringEncoding -string $so -inputEncoding $soe; #convert to UTF-8
$out["stderr"] = Convert-StringEncoding -string $se -inputEncoding $see; #convert to UTF-8
}
if ($Arguments -match 'http_code') { #REST API Exit Code from parameter, -w `"%{http_code}`"
if ($out["stdout"] -match '\d{1,3}$') {
$out["http_code"] = $Matches[0];
$out["stdout"] = $out["stdout"].Substring(0, $out["stdout"].Length - $Matches[0].Length)
}
}
if (![string]::IsNullOrWhiteSpace($out["stdout"]) -and !$NoConvertStdOutFromJSON.IsPresent -and $out["stdout"] -match '\{.*\}' ) {
$out["stdout"] = $out["stdout"] | ConvertFrom-Json -ErrorAction SilentlyContinue -WarningAction SilentlyContinue;
}
if ($ShowAll.IsPresent) {
$ret = [pscustomobject]$out;
} else {
$ret = $out["stdout"];
}
if ($out["exitcode"] -ne 0 -and !$HideExitCodeError.IsPresent) {
Write-Host "`nWARNING: CuRL Exit Code $($out["exitcode"])`n" -ForegroundColor DarkYellow;
}
if ($out["http_code"]) {
switch -Regex ($out["http_code"]) {
"200|201|204|302|401|404" {} #OK or nothing bad
400 { #Bad Request
$RepErr = $TRUE;
$ret = [pscustomobject]$out;
if ($ret.stdout) { if ($ret.stdout.meta) { if ($ret.stdout.meta.message -match 'already been restored') { #Friendlier message
Write-Host "`n Info $_`: $($ret.stdout.meta.message) `n" -ForegroundColor Cyan;
$RepErr = $false;
}}}
if ($RepErr) {
Write-Host "`n ERROR $_`: Bad Request; check your REST API syntax. `n" -ForegroundColor Red;
}
}
405 { Write-Host "`n ERROR $_`: Method not allowed. `n CuRL Arguments: $Arguments `n" -ForegroundColor Red; $ret = [pscustomobject]$out;} #Method not allowed
429 { #Too many requests; try again
Write-Host "`n INFO $_`: Too many REST API requests; waiting 2 seconds and trying again. `n" -ForegroundColor Cyan;
Start-Sleep -Seconds 2;
$ret = Invoke-CuRL -Arguments $Arguments -ShowAll:$ShowAll -NoConvertStdOutFromJSON:$NoConvertStdOutFromJSON -UseInvokeExpression:$UseInvokeExpression -HideExitCodeError:$HideExitCodeError;
}
default {Write-Host "`n ERROR $_`: Uncommon REST API Status Code: $Code. `n See https://restfulapi.net/http-status-codes/ for more information. `n" -ForegroundColor Red; $ret = [pscustomobject]$out;}
}
}
} catch {
Write-Host "`nERROR: Invoke-CuRL: `n $_ `n $($_.ScriptStackTrace)`n" -ForegroundColor Red;
$ret = $null;
}
}
return $ret;
}
}
#endregion CuRL