Private/Invoke-PSAOAIResponseRequest.ps1
|
function Invoke-PSAOAIResponseRequest { [CmdletBinding()] param( [Parameter(Mandatory)][string]$Url, [Parameter(Mandatory)][hashtable]$Headers, [Parameter(Mandatory)][string]$BodyJSON, [ValidateRange(1,2147483647)][int]$TimeoutSec=60 ) # HttpClient avoids PowerShell web-cmdlet verbose/error payload diagnostics. # No default credentials, proxy, redirects, retries or background jobs. $handler = [System.Net.Http.HttpClientHandler]::new() $handler.AllowAutoRedirect = $false $handler.UseProxy = $false $client = [System.Net.Http.HttpClient]::new($handler) $client.Timeout = [System.Threading.Timeout]::InfiniteTimeSpan $cancel = [System.Threading.CancellationTokenSource]::new() $request = $null $response = $null $failure = $null $message = $null try { $cancel.CancelAfter([TimeSpan]::FromSeconds($TimeoutSec)) $request = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Post, $Url) foreach ($name in $Headers.Keys) { [void]$request.Headers.TryAddWithoutValidation($name, [string]$Headers[$name]) } $request.Content = [System.Net.Http.StringContent]::new($BodyJSON, [System.Text.UTF8Encoding]::new($false), 'application/json') $response = $client.SendAsync($request, $cancel.Token).GetAwaiter().GetResult() if (-not $response.IsSuccessStatusCode) { $failure = 'HttpError' $message = "Responses HTTP request failed (status $([int]$response.StatusCode))." if ([int]$response.StatusCode -eq 401) { $message += ' Authentication was not accepted. Verify locally that the endpoint and API key belong to the same Azure resource, that the key is current, and that local API-key authentication is enabled for that resource. Do not share the key or raw response body.' } } else { $bytes = $response.Content.ReadAsByteArrayAsync($cancel.Token).GetAwaiter().GetResult() try { $json = [System.Text.UTF8Encoding]::new($false, $true).GetString($bytes) $result = ConvertFrom-Json -InputObject $json -Depth 100 -NoEnumerate -ErrorAction Stop if ($result -is [array] -or $result -isnot [pscustomobject]) { throw 'Invalid root' } } catch { $failure='ProtocolError'; $message='Responses HTTP result is not a valid UTF-8 JSON object.' } } } catch { if ($cancel.IsCancellationRequested) { $failure='Timeout'; $message='Responses request timed out.' } else { $failure='HttpError'; $message='Responses HTTP transport failed.' } } finally { if ($null -ne $response) { $response.Dispose() } if ($null -ne $request) { $request.Dispose() } $cancel.Dispose() $client.Dispose() $handler.Dispose() } # Create a fresh record outside catch: never retain the HTTP exception or payload. if ($failure) { $PSCmdlet.ThrowTerminatingError([System.Management.Automation.ErrorRecord]::new( [InvalidOperationException]::new($message), "PSAOAI.Response.$failure", 'InvalidOperation', $null)) } return $result } |