EtherAssist.psm1
<# .SYNOPSIS This module contains functions for managing and interacting with the EtherAssist API, including setting and retrieving API keys, and sending queries to the API. .DESCRIPTION The EtherAssist module provides a set of PowerShell functions for securely managing the EtherAssist API key and querying the EtherAssist API. It includes functions to set and get the API key, and to send questions to the API with customizable response options. .NOTES File Name : EtherAssist.psm1 Author : Ryan Mangan Prerequisite : PowerShell V5.1 Copyright 2024 - EfficientEther Ltd # Functions 1. Set-EAApiConfig: Sets and securely stores the EtherAssist API URL and Key. 2. Get-EAApiConfig: Retrieves the stored EtherAssist API URL and Key. 3. Send-EARequest: Sends a question to the EtherAssist API and processes the response. 4. Invoke-EAQuery: Prompts for a user question and sends it to the EtherAssist API with options to mute certain parts of the response. 5. Send-EACompletions: Sends a basic question to the EtherAssist API and processes the response. #> # Requires -Version 5.1 # Function: Set-EAApiConfig function Set-EAApiConfig { <# .SYNOPSIS Sets and securely stores the EtherAssist API URL and Key. .DESCRIPTION Stores the API key and URL securely in an encrypted format within the user's profile directory. .PARAMETER ApiKey The API key to be securely stored. .PARAMETER ApiUrl The URL of the EtherAssist API to be stored. .EXAMPLE Set-EAApiConfig -ApiKey "your_api_key_here" -ApiUrl "https://<your_api_url_here>" #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$ApiKey, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$ApiUrl ) try { $KeyFilePath = Join-Path $env:USERPROFILE "EtherAssistApiKey.xml" $secureApiKey = ConvertTo-SecureString $ApiKey -AsPlainText -Force $settings = @{ ApiKey = $secureApiKey ApiUrl = $ApiUrl } $settings | Export-Clixml -Path $KeyFilePath } catch { Write-Error "Error storing API Key: $_" } } # Function: Get-EAApiConfig function Get-EAApiConfig { <# .SYNOPSIS Retrieves the stored EtherAssist API Key and URL. .DESCRIPTION Fetches and decrypts the stored API Key and URL from the user's profile directory. .OUTPUTS Hashtable. Returns a hashtable containing the API key and URL. .EXAMPLE $settings = Get-EAApiConfig #> [CmdletBinding()] $KeyFilePath = Join-Path $env:USERPROFILE "EtherAssistApiKey.xml" if (Test-Path $KeyFilePath) { try { $settings = Import-Clixml -Path $KeyFilePath $settings.ApiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($settings.ApiKey)) return $settings } catch { Write-Error "Error retrieving API Key: $_" } } else { Write-Error "API Key and URL are not set. Use Set-EAApiConfig to configure." } } # Function: Invoke-EtherAssistApi function Invoke-EtherAssistApi { <# .SYNOPSIS Invokes a query to the EtherAssist API. .DESCRIPTION Sends a request to the specified EtherAssist API endpoint with the given body. .PARAMETER Endpoint The specific API endpoint to send the request to. .PARAMETER Body The body of the request to be sent to the API. .EXAMPLE $response = Invoke-EtherAssistApi -Endpoint "/question" -Body $body #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Endpoint, [Parameter(Mandatory = $true)] [ValidateNotNull()] [hashtable]$Body ) $settings = Get-EAApiConfig if (-not $settings) { Write-Error "API settings are not set. Use Set-EAApiConfig to set the key and URL." return } $uri = "$($settings.ApiUrl)$Endpoint" $headers = @{ Authorization = "Bearer $($settings.ApiKey)" } Write-Verbose "URI: $uri" Write-Verbose "Headers: $headers" Write-Verbose "Body: $(ConvertTo-Json $Body)" try { $response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body ($Body | ConvertTo-Json) -ContentType "application/json" return $response } catch { Write-Error "Error in calling EtherAssist API: $_" } } # Function: Send-EARequest function Send-EARequest { <# .SYNOPSIS Sends a question to the EtherAssist API and processes the response. .DESCRIPTION Interacts with the EtherAssist API, sending a user-defined question and allowing response customization. The MuteAnswer switch only removes the 'Answer:' label from the response, keeping the answer text. .PARAMETER Question The question to be sent to the EtherAssist API. .PARAMETER UseAdvancedModel If set, uses the advanced model for generating the response. .PARAMETER MuteQuestion If set, omits the question from the response. .PARAMETER MuteDateTime If set, omits the date/time from the response. .PARAMETER MuteAnswer If set, removes the 'Answer:' label from the response, keeping the answer text. .PARAMETER SummarizeText If set, summarizes the provided text. .PARAMETER GenerateErrorCodeDescription If set, generates an error code description and possible solutions. .PARAMETER ConvertVbsToPs If set, converts VBS scripts to PowerShell scripts. .PARAMETER GetAppDescription If set, provides a description for an application. .PARAMETER AnalyzeLogs If set, analyzes log files and provides insights. .PARAMETER GetInstallerArgs If set, provides the installation command for the application. .PARAMETER AnalyzeMsix If set, analyzes a MSIX application manifest. .PARAMETER Title If set, provides a title for the given text. .PARAMETER OutputAsJson If set, returns the response as a JSON string. .PARAMETER OutputAsObject If set, returns the response as a structured PowerShell object. .NOTE Only one of the following switches can be used at a time: -UseAdvancedModel, -SummarizeText, -GenerateErrorCodeDescription, -ConvertVbsToPs, -GetAppDescription, -AnalyzeLogs, -GetInstallerArgs, -AnalyzeMsix, -Title .EXAMPLE Send-EARequest -Question "What is Cyber Essentials?" -OutputAsJson .EXAMPLE Send-EARequest -Question "Tell me a joke" -MuteQuestion -MuteDateTime -MuteAnswer #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Question, [switch]$UseAdvancedModel, [switch]$MuteQuestion, [switch]$MuteDateTime, [switch]$MuteAnswer, [switch]$SummarizeText, [switch]$GenerateErrorCodeDescription, [switch]$ConvertVbsToPs, [switch]$GetAppDescription, [switch]$AnalyzeLogs, [switch]$GetInstallerArgs, [switch]$AnalyzeMsix, [switch]$Title, [switch]$OutputAsJson, [switch]$OutputAsObject ) # Ensure only one processing option is selected $optionsSelected = @($SummarizeText, $GenerateErrorCodeDescription, $ConvertVbsToPs, $GetAppDescription, $AnalyzeLogs, $GetInstallerArgs, $AnalyzeMsix, $Title) | Where-Object { $_.IsPresent } if ($optionsSelected.Count -gt 1) { Write-Error "You can only select one of -SummarizeText, -GenerateErrorCodeDescription, -ConvertVbsToPs, -GetAppDescription, -AnalyzeLogs, -GetInstallerArgs, -AnalyzeMsix, or -Title at a time." return } $endpoint = "/question" $body = @{ question = $Question useAdvancedModel = $UseAdvancedModel.IsPresent } if ($SummarizeText.IsPresent) { $endpoint = "/utils/Summarize" } elseif ($Title.IsPresent) { $endpoint = "/utils/title" } elseif ($GenerateErrorCodeDescription.IsPresent) { $endpoint = "/gen/errorcode" } elseif ($ConvertVbsToPs.IsPresent) { $endpoint = "/gen/convert-vbs-to-ps" } elseif ($GetAppDescription.IsPresent) { $endpoint = "/apps/app-description" } elseif ($AnalyzeLogs.IsPresent) { $endpoint = "/gen/log-analyze" } elseif ($GetInstallerArgs.IsPresent) { $endpoint = "/apps/installer-args" } elseif ($AnalyzeMsix.IsPresent) { $endpoint = "/apps/msix-analysis" } $responseObject = Invoke-EtherAssistApi -Endpoint $endpoint -Body $body if ($responseObject.success -eq $true) { if ($OutputAsJson.IsPresent) { # Create a custom object and then convert it to a JSON string $resultObject = [PSCustomObject]@{ Question = $Question Answer = $responseObject.answer TimeOfQuery = Get-Date -Format 'o' AdditionalData = $responseObject | Select-Object * -ExcludeProperty question, answer } return $resultObject | ConvertTo-Json -Depth 10 } elseif ($OutputAsObject.IsPresent) { # Create a custom object to hold the desired properties $resultObject = [PSCustomObject]@{ Question = $Question Answer = $responseObject.answer TimeOfQuery = Get-Date AdditionalData = $responseObject | Select-Object * -ExcludeProperty question, answer } return $resultObject } else { $responseMessage = @() if (-not $MuteQuestion) { $responseMessage += "Question: $Question" } if (-not $MuteDateTime) { $responseMessage += "Date/Time: $(Get-Date)" } $answerText = $responseObject.answer if (-not $MuteAnswer) { $responseMessage += "Answer: $answerText" } else { $responseMessage += $answerText } $responseMessage -join "`n" } } else { Write-Error "API request was not successful: $($responseObject.errorMessage)" } } # Function: Invoke-EAQuery function Invoke-EAQuery { <# .SYNOPSIS Prompts for a user question and sends it to the EtherAssist API with options to mute certain parts of the response. .DESCRIPTION This function prompts the user to enter a question, which is then sent to the EtherAssist API. The user can choose to mute the question, date/time, and/or answer label in the response. .PARAMETER UseAdvancedModel If set, uses the advanced model for generating the response. .PARAMETER MuteQuestion If set, omits the question from the response. .PARAMETER MuteDateTime If set, omits the date/time from the response. .PARAMETER MuteAnswer If set, removes the 'Answer:' label from the response, keeping only the answer text. .EXAMPLE Invoke-EAQuery -MuteQuestion -MuteDateTime -MuteAnswer #> [CmdletBinding()] param ( [switch]$UseAdvancedModel, [switch]$MuteQuestion, [switch]$MuteDateTime, [switch]$MuteAnswer ) try { # Prompt the user to input the question $question = Read-Host "Please enter the question for EtherAssist" # Call the Send-EARequest function with the user's question and muting options Send-EARequest -Question $question -UseAdvancedModel:$UseAdvancedModel -MuteQuestion:$MuteQuestion -MuteDateTime:$MuteDateTime -MuteAnswer:$MuteAnswer } catch { Write-Error "An error occurred while invoking EtherAssist query: $_" } } # Function: Send-EACompletions function Send-EACompletions { <# .SYNOPSIS Sends a basic question to the EtherAssist API and processes the response. .DESCRIPTION Interacts with the EtherAssist API, sending a user-defined question and allowing response customization. The MuteAnswer switch only removes the 'Answer:' label from the response, keeping the answer text. .PARAMETER Question The question to be sent to the EtherAssist API. .PARAMETER MuteQuestion If set, omits the question from the response. .PARAMETER MuteDateTime If set, omits the date/time from the response. .PARAMETER MuteAnswer If set, removes the 'Answer:' label from the response, keeping the answer text. .PARAMETER Advanced If set, uses the advanced model for generating the response. .PARAMETER OutputAsJson If set, returns the response as a JSON string. .PARAMETER OutputAsObject If set, returns the response as a structured PowerShell object. .EXAMPLE Send-EACompletions -Question "What is Cyber Essentials?" -OutputAsJson .EXAMPLE Send-EACompletions -Question "Tell me a joke" -MuteQuestion -MuteDateTime -MuteAnswer .EXAMPLE Send-EACompletions -Question "Explain the benefits of PowerShell" -Advanced #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Question, [switch]$MuteQuestion, [switch]$MuteDateTime, [switch]$MuteAnswer, [switch]$Advanced, [switch]$OutputAsJson, [switch]$OutputAsObject ) $body = @{ question = $Question useAdvancedModel = $Advanced.IsPresent } $responseObject = Invoke-EtherAssistApi -Endpoint "/completions" -Body $body if ($responseObject.success -eq $true) { if ($OutputAsJson.IsPresent) { # Create a custom object and then convert it to a JSON string $resultObject = [PSCustomObject]@{ Question = $Question Answer = $responseObject.answer TimeOfQuery = Get-Date -Format 'o' AdditionalData = $responseObject | Select-Object * -ExcludeProperty question, answer } return $resultObject | ConvertTo-Json -Depth 10 } elseif ($OutputAsObject.IsPresent) { # Create a custom object to hold the desired properties $resultObject = [PSCustomObject]@{ Question = $Question Answer = $responseObject.answer TimeOfQuery = Get-Date AdditionalData = $responseObject | Select-Object * -ExcludeProperty question, answer } return $resultObject } else { $responseMessage = @() if (-not $MuteQuestion) { $responseMessage += "Question: $Question" } if (-not $MuteDateTime) { $responseMessage += "Date/Time: $(Get-Date)" } $answerText = $responseObject.answer if (-not $MuteAnswer) { $responseMessage += "Answer: $answerText" } else { $responseMessage += $answerText } $responseMessage -join "`n" } } else { Write-Error "API request was not successful: $($responseObject.errorMessage)" } } Export-ModuleMember -Function Set-EAApiConfig, Get-EAApiConfig, Send-EARequest, Invoke-EAQuery, Send-EACompletions |