Tririga-Manage-Rest.psm1
#!/usr/bin/env pwsh # # PowerShell commands to manage TRIRIGA instances using the Admin REST API # # The commands allow you to refer to your instances by [Environment] [Instance] (eg: DEV NS1). # $script:ModuleRoot = $PSScriptRoot $script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\Tririga-Manage-Rest.psd1").ModuleVersion function ConvertPSObjectToHashtable { param ( [Parameter(ValueFromPipeline)] $InputObject ) process { if ($null -eq $InputObject) { return $null } if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { $collection = @( foreach ($object in $InputObject) { ConvertPSObjectToHashtable $object } ) Write-Output -NoEnumerate $collection } elseif ($InputObject -is [psobject]) { $hash = @{} foreach ($property in $InputObject.PSObject.Properties) { $hash[$property.Name] = (ConvertPSObjectToHashtable $property.Value).PSObject.BaseObject } $hash } else { $InputObject } } } function HasPager() { $oldPreference = $ErrorActionPreference; $ErrorActionPreference = "stop"; try { if(Get-Command "bat"){ return $true } } catch { return $false } finally { $ErrorActionPreference=$oldPreference; } } function CallTririgaApiRaw() { param( [Parameter(Mandatory)] [string]$serverUrlBase, [string]$apiMethod = "GET", [Parameter(Mandatory)] [string]$apiPath, $apiBody, [Parameter(Mandatory)] [string]$username, [Parameter(Mandatory)] [string]$password, [boolean]$useProxy = $false, [string]$proxyUrl = "http://localhost:8080" ) if ($input) { $apiBody = $input } if ($useProxy) { $proxyProps = @{ Proxy = $proxyUrl ProxyUseDefaultCredentials = $true } [System.Net.WebRequest]::DefaultWebProxy = New-Object System.Net.WebProxy($proxyUri, $true) [System.Net.WebRequest]::DefaultWebProxy.BypassProxyOnLocal = $false } else { $proxyProps = @{} } $logonUrl = "$serverUrlBase/p/websignon/signon" $apiUrl = "$serverUrlBase$apiPath" $loginData = @{ "userName"=$username; "password"=$password; "normal"="false"; "api"="true"; } $tririgaSession = $null if($sessionTable) { $tririgaSession = $tririgaSessionTable[$serverUrlBase] } else { $sessionTable = @{} New-Variable -Name tririgaSessionTable -Value $sessionTable -Scope Script -Force } # TODO: The session might be stale, we need a way to check and invalidate $tririgaSession if(!$tririgaSession) { # https://thedavecarroll.com/powershell/how-i-implement-module-variables/ $tririgaSession = [Microsoft.PowerShell.Commands.WebRequestSession]::new() $tririgaSessionTable[$serverUrlBase] = $tririgaSession $loginResponseHeaders = @{} Write-Verbose "No active sessions found. Send Login request to $logonUrl" $loginResponse = Invoke-RestMethod -Method POST ` -WebSession $tririgaSession ` @proxyProps ` -ContentType application/json ` -Body ($loginData | ConvertTo-Json) ` -Uri $logonUrl # -ResponseHeadersVariable loginResponseHeaders ` # ResponseHeadersVariable param is not supported in PS 5: Write-Verbose ($loginResponseHeaders | ConvertTo-Json) # Ignore cookie Secure and HttpOnly attributes # GetAllCookies is not supported in .net framework 4.0 (used by PS 5). It's only in .NET 6+ #ForEach($cookie in $session.Cookies.GetAllCookies()) { if($PSVersionTable.PSVersion.Major -gt 5) { Write-Verbose "Modify Cookies" ForEach($cookie in $tririgaSession.Cookies.GetAllCookies()) { $cookie.Secure = $false $cookie.HttpOnly = $false Write-Verbose $cookie } } else { Write-Verbose "Can't modify Cookies." } } else { Write-Verbose "Active session found. Not logging in again" } if ($VerbosePreference) { Write-Verbose "Send $apiMethod request to $apiUrl" if($apiBody) { Write-Verbose " with data: $($apiBody | ConvertTo-Json)" } } try { $response = Invoke-RestMethod -Method $apiMethod -WebSession $tririgaSession -ContentType application/json -Uri $apiUrl @proxyProps -Body $apiBody return $response } catch { if ($_.Exception.Response.StatusCode.value__ -eq 401) { Write-Error "Got HTTP 401 (unauthorized) error. Your session for $serverUrlBase may have expired. It has been reset. Please Try again." $tririgaSessionTable[$serverUrlBase] = $null } } } function CallTririgaApi() { param( [Parameter(Mandatory)] [string]$environment, [string]$instance = $null, [string]$apiMethod = "GET", $apiBody, [Parameter(Mandatory)] [string]$apiPath, # When no $instance is set, runs on any one instance [switch]$onlyOnAnyOneInstance = $false, [switch]$noTag = $false ) if ($input) { $apiBody = $input } $tririgaEnvironment = $TririgaEnvironments[$environment] if (!$tririgaEnvironment) { Write-Error "The environment `"$environment`" was not found." Write-Error "Possible values are: $(($TririgaEnvironments.keys) -join ', ')" return $null } if ($tririgaEnvironment) { ForEach($inst in $tririgaEnvironment.Servers.keys) { Write-Verbose "CallTririgaApiRaw: On $environment.$inst." # If $instance is set, run only on the given instance if($instance -and !($instance -eq $inst)) { Write-Verbose "Wanted: $instance, Got: $inst. Skip to next" continue } $tririgaInstance = $tririgaEnvironment["Servers"][$inst] $hostUrl = $tririgaInstance["ApiUrl"] if (!$hostUrl){ $hostUrl = $tririgaInstance["Url"] } if (!$hostUrl) { Write-Error "Neither 'ApiUrl' nor 'Url' not set correctly for $environment.$inst" return $null } if (!$tririgaEnvironment.username) { Write-Error "Username property is not set for $environment environment" return $null } if (!$tririgaEnvironment.password) { Write-Error "Password property is not set for $environment environment" return $null } $result = CallTririgaApiRaw -serverUrlBase $hostUrl -apiMethod $apiMethod -apiPath $apiPath -apiBody $apiBody -username $tririgaEnvironment.username -password $tririgaEnvironment.password # TODO: Only do this of the result is PSObject if (!$noTag) { $result | Add-Member -PassThru environment $environment | Add-Member -PassThru instance $inst } # Tag with environment info #$result = $result | Add-Member -PassThru environment $environment #$result = $result | Add-Member -PassThru instance $inst $result if (!$instance -and $onlyOnAnyOneInstance) { Write-Verbose "OnlyAnyOneInstance is set. Stop after the first one." break } } } else { return $null } } # # # Public Methods # # <# .SYNOPSIS Gets TRIRIGA build number .DESCRIPTION Gets TRIRIGA build number Uses the /api/v1/admin/buildNumber method #> function Get-BuildNumber() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on all instances. [Alias("Inst", "I")] [Parameter(Position=1)] [string]$instance, # If set, the response object is returned as-is. Otherwise it is converted to JSON text. [switch]$raw = $false ) $apiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/buildNumber" } CallTririgaApi @apiCall } <# .SYNOPSIS Gets basic information about a TRIRIGA instance .DESCRIPTION Gets basic information about a TRIRIGA instance Uses the /api/v1/admin/summary method .EXAMPLE PS> Get-Summary Local -Raw | Select-Object databaseConnection databaseConnection ------------------ jdbc:oracle:thin:@localhost:1521/XEPDB1 #> function Get-Summary() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on the first instance. [Alias("Inst", "I")] [string]$instance, # If set, the response object is returned as-is. Otherwise it is converted to JSON text. [switch]$raw = $false ) $apiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/summary" OnlyOnAnyOneInstance = $true } CallTririgaApi @apiCall } <# .SYNOPSIS Gets TRIRIGA Agents configuration .DESCRIPTION Gets TRIRIGA Agents configuration Uses the /api/v1/admin/agent/status method #> function Get-Agents() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on the first instance. [Alias("Inst", "I")] [string]$instance, # If provided, only lists the given agent. [Parameter(Position=1)] [string]$agent, # If set, only list agents that are running [switch]$running, # If set, only list agents that are not running [switch]$notRunning ) $agentArg = "" if($agent) { $agentArg = "?agent=$agent" } $apiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/agent/status$agentArg" OnlyOnAnyOneInstance = $true NoTag = $true } $result = CallTririgaApi @apiCall foreach ($property in $result.PSObject.Properties) { if($running -and $property.Value.Status -ne "Running") { continue } if($notRunning -and $property.Value.Status -ne "Not Running") { continue } New-Object PSObject -Property @{ "ID" = $property.Value.startupId; "Agent" = $property.Value.agent; "Hostname" = $property.Value.hostname; "Status" = $property.Value.status; }; } } <# .SYNOPSIS Gets the configured host(s) for the given agent .DESCRIPTION Gets the configured host(s) for the given agent Uses the /api/v1/admin/agent/status method .EXAMPLE PS> Get-AgentHost -Environment LOCAL -Agent WFAgent | ForEach-Object { Write-Host "WFAgent is configured on $_" } WFAgent is configured on localhost WFAgent is configured on somewhere .EXAMPLE PS> Get-AgentHost -Environment LOCAL -Agent WFAgent | ForEach-Object { Write-Host "WFAgent is running on $_" } WFAgent is running on localhost #> function Get-AgentHost() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on the first instance. [Alias("Inst", "I")] [string]$instance, # Set the type of agent to query. Run 'Get-Agents' to see a list of all possible agent types. [Parameter(Mandatory, Position=1)] [string]$agent, # If set, only list the host when the agent is running [switch]$running, # If set, only list the host when the aget is not running [switch]$notRunning ) $agentCall = @{ Environment = $environment Instance = $instance Agent = $agent Running = $running NotRunning = $notRunning } Get-Agents @agentCall | ForEach-Object { $_.Hostname } } <# .SYNOPSIS Gets a list of users who can access the TRIRIGA Admin Console .DESCRIPTION Gets a list of users with access to the TRIRIGA Admin Console Not all listed users have active access. They are in the Admin group an can be granted access. Uses /api/v1/admin/users/list method .EXAMPLE PS> Get-TririgaAdminUsers LOCAL | Where-Object fullaccess -eq True userId fullaccess username fullName ------ ---------- -------- -------- 221931 True system System System #> function Get-AdminUsers() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on the first instance. [Alias("Inst", "I")] [string]$instance ) $apiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/users/list" OnlyOnAnyOneInstance = $true } CallTririgaApi @apiCall ` | ForEach-Object { $_ | Add-Member -PassThru "fullaccess" ( ` $_.adminSummary -and $_.adminUsers -and $_.agents -and $_.buildNumber -and ` $_.caches -and $_.databaseInfo -and $_.databaseQueryTool -and $_.dataConnect -and ` $_.errorLogs -and $_.javaInfo -and $_.licenses -and $_.maintenanceSchedule -and ` $_.metadataAnalysis -and $_.performanceMonitor -and $_.platformLogging -and ` $_.schedulerInfo -and $_.systemInfo -and $_.threadSettings -and $_.usersLoggedIn ` -and $_.workflowAgentInfo -and $_.workflowEvents -and $_.workflowExecuting ` -and $_.mustGatherTool ) } ` | ForEach-Object { New-Object PSObject -Property @{ "userId" = $_.userId; "fullName" = $_.fullName; "username" = $_.username; "fullaccess" = $_.fullaccess; }; } } <# .SYNOPSIS Gets a list of currently logged in users .DESCRIPTION Gets a list of currently logged in users .EXAMPLE PS> Get-TririgaActiveUsers LOCAL | ft #> function Get-ActiveUsers() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on all instances. [Alias("Inst", "I")] [Parameter(Position=1)] [string]$instance, # If set, the response object is returned as-is. Otherwise it is printed as a table. [switch]$raw = $false ) $apiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/activeUsers/list" } $resultHash = (CallTririgaApi @apiCall).Replace('eMail', 'email1') | ConvertFrom-Json $now = Get-Date -AsUTC foreach($item in $resultHash) { # Only PS 7+ #$item["lastTouch"] = (Get-Date -UnixTimeSeconds (([long]$item["lastTouchDateTime"]) / 1000) -AsUTC) $unixTime = (([long]$item.lastTouchDateTime) / 1000) $item | Add-Member lastTouch ((([System.DateTimeOffset]::FromUnixTimeSeconds($unixTime)).DateTime).ToString("s")) $item | Add-Member lastTouchDuration ("{0:dd}d:{0:hh}h:{0:mm}m:{0:ss}s" -f (New-TimeSpan –Start $item.lastTouch –End $now)) } if($raw) { $resultHash } else { $resultHash | Select-Object userAccount,fullName,email,lastTouchDuration } } <# .SYNOPSIS Stops a TRIRIGA agent .DESCRIPTION Stops a TRIRIGA agent Uses the /api/v1/admin/agent/stop method #> function Stop-Agent() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on the first instance. [Alias("Inst", "I")] [string]$instance, # The Agent to stop. All instances of the agent are stopped. [Parameter(Mandatory, Position=1)] [string]$agent ) $statusApiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/agent/status?agent=$agent" OnlyOnAnyOneInstance = $true NoTag = $true } $agentInfo = CallTririgaApi @statusApiCall | ConvertPSObjectToHashtable ForEach($agent in $agentInfo.Keys) { $thisAgent = $agentInfo[$agent] $agentHost = $thisAgent.hostname $agentId = $agent Write-Verbose "Operating on Agent: $agent ($agentHost) [$thisAgent]" # When the configuration is <ANY>, we can't tell what server is actually running the agent # Since it's usually seen with Vagrant, guess localhost if($agentHost -eq "<ANY>"){ $agentHost = "localhost" } $stopApiCall = @{ Environment = $environment Instance = $instance ApiMethod = "POST" ApiPath = "/api/v1/admin/agent/stop?agent=$agent&startOnHost=$agentHost&runningOnHost=$agentHost&startupId=$agentId" OnlyOnAnyOneInstance = $true } $result = CallTririgaApi @stopApiCall # Some values are in single-item arrays. Flatten it and replace the values $result ` | Add-Member -PassThru "agent" ($result.agent -Join ",") -Force ` | Add-Member -PassThru "agentname" $agent -Force ` | Add-Member -PassThru "hostname" ($result.hostname -Join ",") -Force ` | Add-Member -PassThru "status" ($result.status -Join ",") -Force } } <# .SYNOPSIS Starts a TRIRIGA agent .DESCRIPTION Starts a TRIRIGA agent Uses the /api/v1/admin/agent/start method #> function Start-Agent() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on the first instance. [Alias("Inst", "I")] [string]$instance, # The Agent to start. All instances of the agent are started. [Parameter(Mandatory, Position=1)] [string]$agent ) $statusApiCall = @{ Environment = $environment Instance = $instance ApiMethod = "GET" ApiPath = "/api/v1/admin/agent/status?agent=$agent" OnlyOnAnyOneInstance = $true NoTag = $true } $agentInfo = CallTririgaApi @statusApiCall | ConvertPSObjectToHashtable ForEach($agent in $agentInfo.Keys) { $thisAgent = $agentInfo[$agent] $agentHost = $thisAgent.hostname $agentId = $agent Write-Verbose "Operating on Agent: $agent ($agentHost) [$agentId]" if($agentHost -eq "<ANY>"){ $agentHost = "localhost" } $startApiCall = @{ Environment = $environment Instance = $instance ApiMethod = "POST" ApiPath = "/api/v1/admin/agent/start?agent=$agent&hostname=$agentHost&startupId=$agentId" OnlyOnAnyOneInstance = $true } $result = CallTririgaApi @startApiCall # Some values are in single-item arrays. Flatten it and replace the values $result ` | Add-Member -PassThru "agent" ($result.agent -Join ",") -Force ` | Add-Member -PassThru "agentname" $agent -Force ` | Add-Member -PassThru "hostname" ($result.hostname -Join ",") -Force ` | Add-Member -PassThru "status" ($result.status -Join ",") -Force } } <# .SYNOPSIS Updates workflow instance recording setting .DESCRIPTION Updates workflow instance recording setting Uses the /api/v1/admin/workflowAgentInfo/workflowInstance/update method #> function Set-WorkflowInstance() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on all instances. [Alias("Inst", "I")] [Parameter()] [string]$instance, # The value to set. [ValidateSet("ALWAYS", "ERRORS_ONLY", "PER_WORKFLOW_ALWAYS", "PER_WORKFLOW_PRODUCTION", "DATA_LOAD")] [Parameter(Mandatory, Position=1)] [string]$value ) $apiCall = @{ Environment = $environment Instance = $instance ApiMethod = "POST" ApiPath = "/api/v1/admin/workflowAgentInfo/workflowInstance/update?instanceName=$value" } CallTririgaApi @apiCall } <# .SYNOPSIS Sets the workflow instance recording setting to ALWAYS .DESCRIPTION Sets the workflow instance recording setting to ALWAYS Uses the /api/v1/admin/workflowAgentInfo/workflowInstance/update method #> function Enable-WorkflowInstance() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on all instances. [Alias("Inst", "I")] [Parameter()] [string]$instance ) Set-WorkflowInstance -Environment $environment -Value "ALWAYS" -Instance $instance } <# .SYNOPSIS Sets the workflow instance recording setting to ERRORS_ONLY .DESCRIPTION Sets the workflow instance recording setting to ERRORS_ONLY Uses the /api/v1/admin/workflowAgentInfo/workflowInstance/update method #> function Disable-WorkflowInstance() { [CmdletBinding()] param( # The TRIRIGA environment to use. [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [Alias("Env", "E")] [string]$environment, # The TRIRIGA instance within the environment to use. # If omitted, command will act on all instances. [Alias("Inst", "I")] [Parameter()] [string]$instance ) Set-WorkflowInstance -Environment $environment -Value "ERRORS_ONLY" -Instance $instance } |