# Ignore Measure-HelpSynopsis warnings in the PSScript Analyzer [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('Alkami.PowerShell.PSScriptAnalyzerRules\Measure-HelpSynopsis', '', Scope = 'Class')] # Ignore Measure-HelpSynopsis warnings in the PSScript Analyzer - PS Classes can't do CmdletBinding, afaict [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('Alkami.PowerShell.PSScriptAnalyzerRules\Measure-CmdletBinding', '', Scope = 'Class')] Class SecretServerConnection { [string]$api [string]$site [string]$userName [string]$domain [string]$password [string]$tokenRoute [ScriptBlock]$commonFilters = { "?filter.includeRestricted=true&filter.searchtext=$searchString&filter.folderId=$folderId&filter.includeSubFolders=true" } [ScriptBlock]$updateEndpoint [System.Collections.Generic.Dictionary[[String], [String]]]$commonHeader $token SecretServerConnection() { } SecretServerConnection([string]$site, [string]$userName, [string]$password) { $this.site = $site $this.tokenRoute = "$site/oauth2/token" $this.api = $site, "api/v1" -join "/" $this.updateEndpoint = { "/secrets/$secretId/fields/$fieldToUpdate" } $this.userName = $userName $this.password = $password $this.commonHeader = [System.Collections.Generic.Dictionary[[String], [String]]]::new() } [void]Authenticate() { $this.Authenticate($False) } [void]Authenticate([bool]$UseTwoFactor) { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $creds = @{ username = $this.username password = $this.password grant_type = "password" } $headers = $null If ($UseTwoFactor) { $headers = @{ "OTP" = (Read-Host -Prompt "Enter your OTP for 2FA: ") } } try { $response = Invoke-RestMethod $this.tokenRoute -Method Post -Body $creds -Headers $headers $this.token = $response.access_token; if ($this.commonHeader.Count -gt 0) { $this.commonHeader.Clear() } $this.commonHeader.Add("Authorization", "Bearer $($this.token)") } catch { throw $_ } } [object]GetSecretByName([string]$secretName, [string]$folderId) { # $searchString is used in $commonFilters above. This "not used" warning is a lie. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positive')] $searchString = $secretName $filters = $this.commonFilters.Invoke() Write-Debug "$($this.api)/secrets/lookup$filters" $result = Invoke-RestMethod "$($this.api)/secrets$filters" -Headers $this.commonHeader return $result } [object]GetSecretById([string]$secretId) { Write-Debug "$($this.api)/secrets/$secretId" $response = Invoke-RestMethod "$($this.api)/secrets/$secretId" -Headers $this.commonHeader return $response } [object]GetSecretByFolderId([string]$folderId) { $parameters = "?filter.folderId=$folderId" $response = Invoke-RestMethod "$($this.api)/secrets/$parameters" -Headers $this.commonHeader return $response.records } [object]GetSecretTemplateById([int]$templateId, [int]$folderId) { $secret = Invoke-RestMethod "$($this.api)/secrets/stub?filter.secrettemplateid=$templateId&filter.folderId=$folderId" -Headers $this.commonHeader return $secret } [int]GetSecretTemplateIdByName([string]$templateName) { $searchString = "?filter.searchText=$templateName" $secret = Invoke-RestMethod -Method Get "$($this.api)/secret-templates$searchString" -Headers $this.commonHeader if ($secret.records) { $record = $secret.records | Where-Object { $_.name -eq $templateName } return $record.id; } return -1 } [int]CreateSecret([object]$secret, [int]$folderId, [string]$secretName) { $secret.name = $secretName $secret.siteId = 1 $secret.folderId = $folderId # Get Secret Template first, set up the template with various items and their values and then pass it to create secret $requestCreateSecretParams = $secret | ConvertTo-Json $secret = Invoke-RestMethod "$($this.api)/secrets/" -Method Post -Body $requestCreateSecretParams -Headers $this.commonHeader -ContentType "application/json" return $secret.id } [object]UpdateField([string]$secretId, [string]$fieldToUpdate, [string]$newValue) { $body = @{ value = $newValue } | ConvertTo-Json $response = Invoke-RestMethod -Method Put -Uri "$($this.api)$($this.updateEndpoint.Invoke())" -Headers $this.commonHeader -ContentType "application/json" -Body $body return $response } [object]GetField([string]$secretId, [string]$field) { $response = Invoke-RestMethod -Method Get -Uri "$($this.api)$($this.updateEndpoint.Invoke())" -Headers $this.commonHeader return $response.Records } [void]UploadFile([int]$secretId, [string]$fieldToUpdate, [string]$filePath) { $fileName = Get-ChildItem $filePath | Select-Object -ExpandProperty Name $requestUploadFileParams = @{ fileName = $fileName; fileAttachment = [IO.File]::ReadAllBytes($filePath) } | ConvertTo-Json Invoke-RestMethod -Method Put -Uri "$($this.api)$($this.updateEndpoint.Invoke())" -Headers $this.commonHeader -Body $requestUploadFileParams -ContentType "application/json" } [bool]DownloadFile([int]$secretId, [string]$fieldToupdate, [string]$filePath) { # invokeing $this.updateEndpoint.Invoke() sets variables hidden above in SecretServerConnection Write-Debug "$($this.api)$($this.updateEndpoint.Invoke())" try { Invoke-RestMethod -Method Get -Uri "$($this.api)$($this.updateEndpoint.Invoke())" -Headers $this.commonHeader -OutFile $filePath | Out-Null return $true } catch { Write-Warning "An error occurred while downloading a file." Write-Warning -Message "StatusCode: $($_.Exception.Response.StatusCode.value__)" Write-Warning -Message "StatusDescription: $($_.Exception.Response.StatusDescription)" return $false } } [int]AddFolder([int]$parentFolderId, [string]$folderName, [bool]$inheritPermissions, [bool]$inheritSecretPolicy) { $folderStub = Invoke-RestMethod "$($this.api)/folders/stub" -Method GET -Headers $this.commonHeader -ContentType "application/json" $folderStub.folderName = $folderName $folderStub.folderTypeId = 1 $folderStub.inheritPermissions = $inheritPermissions $folderStub.inheritSecretPolicy = $inheritSecretPolicy $folderStub.parentFolderId = $parentFolderId $folderArgs = $folderStub | ConvertTo-Json $folderAddResult = Invoke-RestMethod "$($this.api)/folders" -Method POST -Body $folderArgs -Headers $this.commonHeader -ContentType "application/json" return $folderAddResult.id } [int]AddFolder([int]$parentFolderId, [string]$folderName) { return $this.AddFolder($parentFolderId, $folderName, $true, $true) } [object]GetFolderById([int]$folderId) { $folderGetResult = Invoke-RestMethod "$($this.api)/folders/$folderId" -Method GET -Headers $this.commonHeader -ContentType "application/json" return $folderGetResult.records } [object]GetChildFolders([int]$parentId) { $parameters = "?filter.parentFolderId=$parentId" $folderGetResult = Invoke-RestMethod "$($this.api)/folders/$parameters" -Method GET -Headers $this.commonHeader -ContentType "application/json" return $folderGetResult.records } [object]GetFolderIdByName([string]$folderName) { $searchFilter = "?filter.searchText=$folderName" $searchResults = Invoke-RestMethod "$($this.api)/folders$searchFilter" -Method GET -Headers $this.commonHeader -ContentType "application/json" return $searchResults.Records.Id } [object]GetFolderIdByName([string]$folderName, [int]$parentFolderId) { $searchString = $folderName $folderId = $parentFolderId $filters = "?filter.includeRestricted=true&filter.parentFolderId=$folderId&filter.searchtext=%$searchString" Write-Debug $filters $searchResults = Invoke-RestMethod "$($this.api)/folders$filters" -Method GET -Headers $this.commonHeader -ContentType "application/json" return $searchResults.Records.Id } }