Private/Common/Invoke-MgcHttpRequest.ps1
|
function Invoke-MgcHttpRequest { <# .SYNOPSIS Issues an HTTP request and returns a uniform response regardless of PS version. .DESCRIPTION PowerShell 7 added 'Invoke-WebRequest -SkipHttpErrorCheck' which suppresses the exception on 4xx/5xx and returns the response object. Windows PowerShell 5.1 doesn't have that switch - it always throws on HTTP errors, and the response is available only via $_.Exception.Response (with a different shape). This helper unifies both behaviors. Returns a PSCustomObject with: - StatusCode: [int] HTTP status code - Headers: hashtable of response headers - Content: string (decoded UTF-8) of the response body .PARAMETER Parameters Hashtable of parameters to pass to Invoke-WebRequest (Uri, Method, Headers, Body, etc.). Do NOT set SkipHttpErrorCheck or ErrorAction - this helper manages those. #> [CmdletBinding()] param( [Parameter(Mandatory)][hashtable]$Parameters ) $useSkipFlag = $PSVersionTable.PSVersion.Major -ge 7 # PS 5.1's Invoke-WebRequest defaults to IE-based parsing which is slow + brittle. if (-not $useSkipFlag) { $Parameters['UseBasicParsing'] = $true } $bodyToString = { param($c) if ($null -eq $c) { return $null } if ($c -is [byte[]]) { if ($c.Length -eq 0) { return $null } return [System.Text.Encoding]::UTF8.GetString($c) } return [string]$c } $headersToHashtable = { param($h) $out = @{} if ($null -eq $h) { return $out } # PS 7 headers may be IDictionary-like or WebHeaderCollection if ($h -is [System.Collections.IDictionary]) { foreach ($k in $h.Keys) { $out[$k] = $h[$k] } } elseif ($h.AllKeys) { foreach ($k in $h.AllKeys) { $out[$k] = $h[$k] } } return $out } if ($useSkipFlag) { $Parameters['SkipHttpErrorCheck'] = $true $Parameters['ErrorAction'] = 'Stop' $resp = Invoke-WebRequest @Parameters return [pscustomobject]@{ StatusCode = [int]$resp.StatusCode Headers = (& $headersToHashtable $resp.Headers) Content = (& $bodyToString $resp.Content) } } # Windows PowerShell 5.1 path: throws on 4xx/5xx, catch and extract. try { $Parameters['ErrorAction'] = 'Stop' $resp = Invoke-WebRequest @Parameters return [pscustomobject]@{ StatusCode = [int]$resp.StatusCode Headers = (& $headersToHashtable $resp.Headers) Content = (& $bodyToString $resp.Content) } } catch [System.Net.WebException] { $errResp = $_.Exception.Response if (-not $errResp) { throw } $statusCode = [int]$errResp.StatusCode $body = $null try { $stream = $errResp.GetResponseStream() $reader = New-Object System.IO.StreamReader($stream) $body = $reader.ReadToEnd() $reader.Dispose() $stream.Dispose() } catch { } $headers = & $headersToHashtable $errResp.Headers return [pscustomobject]@{ StatusCode = $statusCode Headers = $headers Content = $body } } } |