Public/ps1/Html/Start-ApprxrJobHtml.ps1
|
<#
.SYNOPSIS Executes an HTTP job for Apprxr, handling authentication, headers, and response parsing. .DESCRIPTION Sends an HTTP request (GET or POST) to a specified URL with provided headers, body, and authentication. Handles authentication via Set-ApprxrAuthenticationRoute, logs all request and response details, and returns a structured result. Handles errors and extracts detailed error information from the response. .PARAMETER taskInformation An object containing the job parameters, including url, httpMethod, headers, body, contentType, channelId, id, and type. .PARAMETER DebugMode If specified, enables debug mode which logs the full result object before returning. Can also be controlled via ApprxrHtmlDebugMode configuration setting. .EXAMPLE Start-ApprxrJobHtml -taskInformation @{ url = 'https://example.com/api'; httpMethod = 'POST'; headers = @{ Authorization = 'Bearer ...' }; body = $jsonBody; contentType = 'application/json' } .EXAMPLE Start-ApprxrJobHtml -taskInformation $taskInfo -DebugMode .NOTES Used for running HTTP-based jobs in Apprxr automation, including REST API calls with authentication and custom headers. #> function Start-ApprxrJobHtml { param ( $taskInformation, [switch]$DebugMode ) # Check if debug mode is enabled via configuration if not explicitly set if (-not $DebugMode) { try { $debugConfig = Get-ApprxrConfigurationValue -name "ApprxrHtmlDebugMode" -ErrorAction SilentlyContinue if ($debugConfig -and ($debugConfig -eq $true -or $debugConfig -eq "true" -or $debugConfig -eq "1")) { $DebugMode = $true } } catch { # Configuration value not found, continue without debug mode } } if ($DebugMode) { Log ("DEBUG MODE ENABLED") Log ("Headers: $($taskInformation.headers | Out-String)") Log ("Body: $($taskInformation.body | Out-String)") Log ("Method: $($taskInformation.httpMethod | Out-String)") Log ("Url: $($taskInformation.url | Out-String)") Log ("ContentType: $($taskInformation.contentType | Out-String)") } if (-not $taskInformation.url) { return @{ message= "No url found" sucess= $false } } try { # Populate authentication info using Get-ApprxrAuthenticationRoute $authInfo = Get-ApprxrAuthenticationRoute -hostURI $taskInformation.url -channelId $taskInformation.channelId -id $taskInformation.id -type $taskInformation.type if ($authInfo) { if ($DebugMode) { Log ("Authentication Info: $($authInfo | ConvertTo-Json -Depth 10)") } } } catch { Log ("Error setting authentication: $($_.Exception.Message)") return @{ message= "Error setting authentication: $($_.Exception.Message)" sucess= $false } } $result = @{} $headers = @{} # Handle null or empty headers if ($taskInformation.headers) { $taskInformation.headers.psobject.Properties | ForEach-Object { $headers[$_.Name] = $_.Value } } try { # Decode any Unicode escape sequences in the URL (e.g., \u0026 for &) $decodedUrl = $taskInformation.url -replace '\\u([0-9A-Fa-f]{4})', { [char]([convert]::ToInt32($args[0],16)) } if ($DebugMode) { Log ("Decoded URL: $decodedUrl") } $invokeParams = @{ Uri = $decodedUrl Method = $taskInformation.httpMethod Headers = $headers ErrorAction = 'Stop' } # Add authentication/credential if available if ($authInfo) { $isCore = $PSVersionTable.PSEdition -eq 'Core' # NTLM/Negotiate: Set Credential always, set Authentication only in PowerShell Core if ($authInfo.Authentication -eq 'Negotiate' -or $authInfo.Authentication -eq 'NTLM') { if ($authInfo.PSObject.Properties['username'] -and $authInfo.PSObject.Properties['password'] -and $authInfo.username -and $authInfo.password) { try { $securePassword = ConvertTo-SecureString -String $authInfo.password -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential ($authInfo.username, $securePassword) $invokeParams.Credential = $credential if ($DebugMode) { Log ("Adding Credential for user: $($authInfo.username)") } } catch { Log ("Error creating or assigning credential: $($_.Exception.Message)") throw $_ } } if ($isCore -and $authInfo.PSObject.Properties['Authentication'] -and $authInfo.Authentication) { $invokeParams.Authentication = $authInfo.Authentication if ($DebugMode) { Log ("Adding Authentication (Core): $($authInfo.Authentication)") } } if ($DebugMode) { Log ("Credential and authentication assignment complete. Preparing to invoke web request.") } } elseif ($authInfo.Authentication -eq 'Basic') { # For Basic, add Authorization header manually if ($authInfo.PSObject.Properties['username'] -and $authInfo.PSObject.Properties['password'] -and $authInfo.username -and $authInfo.password) { $pair = "$($authInfo.username):$($authInfo.password)" $bytes = [System.Text.Encoding]::UTF8.GetBytes($pair) $base64 = [Convert]::ToBase64String($bytes) $headers['Authorization'] = "Basic $base64" if ($DebugMode) { Log ("Adding Basic Authorization header for user: $($authInfo.username)") } } if ($isCore -and $authInfo.PSObject.Properties['Authentication'] -and $authInfo.Authentication) { $invokeParams.Authentication = $authInfo.Authentication if ($DebugMode) { Log ("Adding Authentication (Core): $($authInfo.Authentication)") } } } } if ($taskInformation.body) { $bodyToSend = $taskInformation.body if (-not $taskInformation.httpMethod) { $taskInformation.httpMethod = "POST" } if (-not $taskInformation.contentType) { $taskInformation.contentType = "application/json" } $invokeParams.ContentType = $taskInformation.contentType # If body is an object and content type is application/json, serialize to JSON if ($taskInformation.contentType -eq 'application/json' -and ($bodyToSend -is [PSCustomObject] -or $bodyToSend -is [hashtable])) { $bodyToSend = $bodyToSend | ConvertTo-Json -Depth 10 } $invokeParams.Body = $bodyToSend } else { if (-not $taskInformation.httpMethod) { $taskInformation.httpMethod = "GET" } if ($taskInformation.body) { $bodyToSend = $taskInformation.body # If body is an object and content type is application/json, serialize to JSON if ($taskInformation.contentType -eq 'application/json' -and ($bodyToSend -is [PSCustomObject] -or $bodyToSend -is [hashtable])) { $bodyToSend = $bodyToSend | ConvertTo-Json -Depth 10 } $invokeParams.Body = $bodyToSend $invokeParams.ContentType = $taskInformation.contentType } } if ($DebugMode) { Log ("Send Invoke-WebRequest Parameters: $($invokeParams | ConvertTo-Json -Depth 10)") } if ($DebugMode) { Log ("About to call Invoke-WebRequest with params: $($invokeParams | ConvertTo-Json -Depth 10)") } $invokeParams.Uri = "https://ihsc.apprx.eu" $response = Invoke-webrequest @invokeParams if ($DebugMode) { Log ("Invoke-WebRequest completed.") } if ($DebugMode) { Log ("Web request completed successfully.") } if ($DebugMode) { Log ("Processing response...") } $cookiesObj = Get-CookiesObject $response.Cookies if ($DebugMode) { Log ("Cookies Object: $($cookiesObj | ConvertTo-Json -Depth 10)") } if ($null -eq $cookiesObj) { $cookiesObj = @() } $headersObj = @{} if ($response.PSObject.Properties['Headers']) { foreach ($key in $response.Headers.Keys) { $headersObj[$key] = $response.Headers[$key] } } elseif ($response.PSObject.Properties['BaseResponse'] -and $response.BaseResponse.Headers) { foreach ($key in $response.BaseResponse.Headers.Keys) { $headersObj[$key] = $response.BaseResponse.Headers[$key] } } $resultObj = @{} if ($response.PSObject.Properties["StatusCode"]) { $resultObj.StatusCode = $response.StatusCode } if ($response.PSObject.Properties["StatusDescription"]) { $resultObj.StatusDescription = $response.StatusDescription } $resultObj.Headers = $headersObj $resultObj.Cookies = $cookiesObj if ($response.PSObject.Properties["Content"]) { $resultObj.Content = $response.Content } else { $resultObj.Content = $response } if ($response.PSObject.Properties["RawContent"]) { $resultObj.RawContent = $response.RawContent } if ($response.PSObject.Properties["RawContentLength"]) { $resultObj.RawContentLength = $response.RawContentLength } if ($response.PSObject.Properties["BaseResponse"]) { $resultObj.BaseResponse = $response.BaseResponse } Log ("Response: $($resultObj | ConvertTo-Json -Depth 100)") $returnObject = @{ message = $resultObj | ConvertTo-Json -Depth 100 sucess = $true } if ($DebugMode) { Log ("DEBUG MODE - Full Result Object: $($returnObject | ConvertTo-Json -Depth 100)") } return $returnObject } catch { $headersObj = @{} $cookiesObj = @() $errorObj = @{} $errorContent = $null if ($_.Exception.Response) { $resp = $_.Exception.Response # Try to extract the raw response body (the red text) try { $reader = [System.IO.StreamReader]::new($resp.GetResponseStream()) $errorContent = $reader.ReadToEnd() $reader.Close() } catch {} if ($resp.Headers) { foreach ($key in $resp.Headers.Keys) { $headersObj[$key] = $resp.Headers[$key] } } $cookiesObj = Get-CookiesObject $resp.Cookies $errorObj.Headers = $headersObj $errorObj.Cookies = $cookiesObj if ($resp.StatusCode) { $errorObj.StatusCode = $resp.StatusCode } if ($resp.StatusDescription) { $errorObj.StatusDescription = $resp.StatusDescription } if ($resp.Content) { $errorObj.Content = $resp.Content } if ($resp.RawContent) { $errorObj.RawContent = $resp.RawContent } if ($resp.RawContentLength) { $errorObj.RawContentLength = $resp.RawContentLength } if ($resp.BaseResponse) { $errorObj.BaseResponse = $resp.BaseResponse } if ($_.Exception.Message) { $errorObj.Message = $_.Exception.Message } if ($errorContent) { $errorObj.ErrorContent = $errorContent } } else { if ($_.Exception.Message) { $errorObj.Message = $_.Exception.Message } } if ($null -eq $errorObj -or $errorObj.Count -eq 0) { Log ("Exception: $($_.Exception.Message)") } else { Log ("Error: $($errorObj | ConvertTo-Json -Depth 100)") } $returnObject = @{ message = if ($null -eq $errorObj -or $errorObj.Count -eq 0) { $_.Exception.Message } else { $errorObj | ConvertTo-Json -Depth 100 } messageCode = if ($_.Exception.Response) { $_.Exception.Response.StatusCode.value__ } else { $null } sucess = $false } if ($DebugMode) { Log ("DEBUG MODE - Full Error Object: $($returnObject | ConvertTo-Json -Depth 100)") } return $returnObject } } |