From 007de7ab96756beeae07a66feaa5ba82ba7d92ca Mon Sep 17 00:00:00 2001 From: evetovicsm <5862838+evetovicsm@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:30:02 +0200 Subject: [PATCH 01/10] Added certificate authentication option to Connect-SafeguardSPS --- src/sessionapi.psm1 | 199 ++++++++++---------------------------------- 1 file changed, 43 insertions(+), 156 deletions(-) diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index c7d7242..e6a0aec 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -5,12 +5,16 @@ function Connect-Sps Param( [Parameter(Mandatory=$true,Position=0)] [string]$SessionMaster, - [Parameter(Mandatory=$true,Position=1)] + [Parameter(Mandatory=$false)] [string]$SessionUsername, - [Parameter(Mandatory=$true,Position=2)] + [Parameter(Mandatory=$false)] [SecureString]$SessionPassword, [Parameter(Mandatory=$false)] - [switch]$Insecure + [switch]$Insecure, + [Parameter(Mandatory=$false)] + [string]$CertificateFile, + [Parameter(Mandatory=$false)] + [string]$Thumbprint ) if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } @@ -23,15 +27,19 @@ function Connect-Sps Disable-SslVerification if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } } - - $local:PasswordPlainText = [System.Net.NetworkCredential]::new("", $SessionPassword).Password - + write-host $Thumbrint try { + + if($Thumbprint){Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication?type=x509" -SessionVariable HttpSession -CertificateThumbprint $Thumbprint | Write-Verbose } + elseif($CertificateFile){ Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication?type=x509" -SessionVariable HttpSession -Certificate $CertificateFile | Write-Verbose } + else + { + $local:PasswordPlainText = [System.Net.NetworkCredential]::new("", $SessionPassword).Password $local:BasicAuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $SessionUsername, $local:PasswordPlainText))) Remove-Variable -Scope local PasswordPlainText - Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication" -SessionVariable HttpSession ` - -Headers @{ Authorization = ("Basic {0}" -f $local:BasicAuthInfo) } | Write-Verbose + Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication" -SessionVariable HttpSession -Headers @{ Authorization = ("Basic {0}" -f $local:BasicAuthInfo) } | Write-Verbose + } } catch { @@ -40,7 +48,9 @@ function Connect-Sps } finally { + if($local:BasicAuthInfo){ Remove-Variable -Scope local BasicAuthInfo + } } $HttpSession @@ -116,9 +126,7 @@ function Invoke-SpsWithoutBody [Parameter(Mandatory=$false)] [object]$Parameters, [Parameter(Mandatory=$false)] - [string]$InFile, - [Parameter(Mandatory=$false)] - [string]$OutFile + [string]$InFile ) if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } @@ -135,14 +143,8 @@ function Invoke-SpsWithoutBody } if ($InFile) { - Write-Verbose "InFile=$InFile" $arguments = $arguments + @{ InFile = $InFile } } - if($OutFile) - { - Write-Verbose "OutFile=$OutFile" - $arguments = $arguments + @{ OutFile = $OutFile } - } Invoke-RestMethod @arguments } @@ -163,9 +165,7 @@ function Invoke-SpsInternal [Parameter(Mandatory=$false)] [HashTable]$Parameters, [Parameter(Mandatory=$false)] - [string]$InFile, - [Parameter(Mandatory=$false)] - [string]$OutFile + [string]$InFile ) if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } @@ -176,7 +176,7 @@ function Invoke-SpsInternal switch ($Method.ToLower()) { {$_ -in "get","delete"} { - Invoke-SpsWithoutBody $Method $RelativeUrl $Headers -Parameters $Parameters -OutFile $OutFile + Invoke-SpsWithoutBody $Method $RelativeUrl $Headers -Parameters $Parameters break } {$_ -in "put","post"} { @@ -527,23 +527,30 @@ function Connect-SafeguardSps Param( [Parameter(Mandatory=$true,Position=0)] [string]$Appliance, - [Parameter(Mandatory=$true,Position=1)] + [Parameter(Mandatory=$false)] [string]$Username, [Parameter(Mandatory=$false)] [SecureString]$Password, [Parameter(Mandatory=$false)] - [switch]$Insecure + [switch]$Insecure, + [Parameter(Mandatory=$false)] + [string]$CertificateFile, + [Parameter(Mandatory=$false)] + [string]$Thumbprint ) if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if (-not $Password) + + if($CertificateFile){ $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -CertificateFile $CertificateFile -Insecure:$Insecure)} + elseif($Thumbprint){ $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -Thumbprint $Thumbprint -Insecure:$Insecure)} + else { - $Password = (Read-Host "Password" -AsSecureString) + if (-not $Password) {$Password = (Read-Host "Password" -AsSecureString) } + $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -SessionUsername $Username -SessionPassword $Password -Insecure:$Insecure) } - $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -SessionUsername $Username -SessionPassword $Password -Insecure:$Insecure) + Set-Variable -Name "SafeguardSpsSession" -Scope Global -Value @{ "Appliance" = $Appliance; "Insecure" = $Insecure; @@ -642,12 +649,6 @@ A switch to return data as pretty JSON string. .PARAMETER BodyOutput A switch to just return the body as a PowerShell object. -.PARAMETER InFile -Path to an input file for upload. - -.PARAMETER OutFile -Name of output file for downloads. - .INPUTS None. @@ -692,9 +693,7 @@ function Invoke-SafeguardSpsMethod [Parameter(Mandatory=$false)] [switch]$BodyOutput, [Parameter(Mandatory=$false)] - [string]$InFile, - [Parameter(Mandatory=$false)] - [string]$OutFile + [string]$InFile ) if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } @@ -738,7 +737,6 @@ function Invoke-SafeguardSpsMethod JsonBody = $JsonBody; Parameters = $Parameters; InFile = $InFile; - OutFile = $OutFile; } if ($JsonOutput) { @@ -1196,6 +1194,9 @@ function Get-SafeguardSpsInfo { [CmdletBinding()] Param( + [parameter(Mandatory, Position = 0)] + [string] + $FilePath ) if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } @@ -1211,9 +1212,6 @@ Uploads a new firmware to SPS. .DESCRIPTION This command takes a path to an SPS firmware and uploads it to an open firmware slot. -.PARAMETER FilePath -Path to the SPS firmware .iso - .EXAMPLE Import-SafeguardSpsFirmware -FilePath #> @@ -1240,10 +1238,6 @@ Get Safeguard SPS appliance version via the Web API. .DESCRIPTION This cmdlet will display the version of Safeguard SPS. -.PARAMETER AltSyntax -Display the version property instead of the firmware_version property. - - .EXAMPLE Get-SafeguardSpsVersion @@ -1315,16 +1309,9 @@ function Test-SafeguardSpsFirmware slot_id = $Slot } - try - { - $summary = (Invoke-SafeguardSpsMethod POST firmware/test -Body $Body).body.test_summary - Write-Verbose $summary - return $true - } - catch - { - return $false - } + $summary = (Invoke-SafeguardSpsMethod POST firmware/test -Body $Body).body.test_summary + Write-Verbose $summary + return $summary.StartsWith("Upgrade is allowed;") } <# @@ -1334,12 +1321,6 @@ Starts a firmware upgrade. .DESCRIPTION This command upgrades SPS with the firmware installed into the indicated slot. -.PARAMETER Slot -The slot index index of the firmware (1-4) - -.PARAMETER Message -The message to display while upgrading firmware - .EXAMPLE Install-SafeguardSpsFirmware -Slot 3 -Message "Upgrading SPS firmware..." #> @@ -1375,12 +1356,6 @@ Install-SafeguardSpsUpgrade .DESCRIPTION This command automates the steps for uploading and installing an SPS firmware upgrade. -.PARAMETER FilePath -THe path to the firmware .iso - -.PARAMETER TargetVersion -The version of the firmware. - .EXAMPLE Install-SafeguardSpsPatch -FilePath #> @@ -1399,48 +1374,22 @@ function Install-SafeguardSpsUpgrade if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - if($TargetVersion -eq (Get-SafeguardSpsVersion)) - { - Write-Host "$TargetVersion is already installed" - return - } - $activity = "Installing SPS upgrade" Write-Progress -Activity $activity -Status 'Importing firmware' -PercentComplete 15 - Write-Verbose "Starting firmware upload..." Import-SafeguardSpsFirmware $FilePath - Write-Verbose "Firmware upload complete." $slots = (Get-SafeguardSpsFirmwareSlot).items.body for($i = 0; $i -lt $slots.count; $i++) { if($slots[$i].version -ieq $TargetVersion) { - Write-Verbose "Found target firmware '$($TargetVersion)' in slot $i" Write-Progress -Activity $activity -Status "Testing firmware in slot $i" -PercentComplete 65 if( Test-SafeguardSpsFirmware -Slot $i ) { Write-Progress -Activity $activity -Status "Installing $TargetVersion from slot $i" -PercentComplete 75 - Write-Verbose "Installing firmware in slot $i" Install-SafeguardSpsFirmware -Slot $i -Message "Upgrading SPS firmware to $TargetVersion" Write-Progress -Activity $activity -Status "Finished" -PercentComplete 100 - Start-Sleep 60 - Write-Verbose "Waiting for SPS to restart..." - for($i = 0; $i -lt 20; $i++) - { - try - { - $currentVersion = Get-SafeguardSpsVersion - if($currentVersion -eq $TargetVersion) - { - Write-Host "Upgrade complete: SPS is at version $currentVersion" - return - } - } - catch { - } - Start-Sleep 15 - } - throw "Timed out waiting for SPS to reach version $TargetVersion" + Start-Sleep 1 + return } else { @@ -1450,65 +1399,3 @@ function Install-SafeguardSpsUpgrade } throw "Firmware with version $TargetVersion could not be found in any firmware slot." } - -<# -.SYNOPSIS -Get-SafeguardSpsSupportBundle - -.DESCRIPTION -This command downloads an SPS support bundle. - -.PARAMETER OutFile -The output file name. If this is omitted, a unique name will be generated. - -.EXAMPLE -Get-SafeguardSpsSupportBundle -#> -function Get-SafeguardSpsSupportBundle -{ - [CmdletBinding()] - Param( - [parameter(Mandatory = $false, Position = 0)] - [string] $OutFile - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $pct = 5 - $activity = 'Get SPS Support Bundle' - Write-Progress -Activity $activity -Status 'Generating support bundle' -PercentComplete $pct - $response = Invoke-SafeguardSpsMethod POST troubleshooting/support-bundle - $jobId = $response.key - - $maxTime = (Get-Date).AddMinutes(10) - $pct += 15 - while((Get-Date) -lt $maxTime) { - $status = Invoke-SafeguardSpsMethod GET "troubleshooting/support-bundle/$($jobId)" - if($status.body.status -ieq "finished") { - break; - } - start-sleep -Seconds 10 - $pct += 1 - Write-Progress -Activity $activity -Status 'Waiting for support bundle generation to complete' -PercentComplete $pct - } - - if ((Get-Date) -gt $maxTime) { - throw "Timed out waiting for support bundle generation." - } - - $pct = 80 - Write-Progress -Activity $activity -Status 'Downloading support bundle' -PercentComplete $pct - if(-not $OutFile) { - $OutFile = "sps-$($safeguardspssession.Appliance)-$(get-date -f yyyy-MM-dd-HH-mm-ss).tar.gz" - } - - Invoke-SafeguardSpsMethod GET "troubleshooting/support-bundle/$($jobId)/download" -OutFile $OutFile - Write-Progress -Activity $activity -Status 'Deleting support bundle from SPS' -PercentComplete 90 - - $null = Invoke-SafeguardSpsMethod DELETE "troubleshooting/support-bundle/$($jobId)" - Write-Progress -Activity $activity -Status 'Complete' -PercentComplete 100 - - Write-Host -ForegroundColor Green "Saved SPS support bundle to: $OutFile" -} - From 84c68e1dda9bd261e488982b6254edf06429d3fe Mon Sep 17 00:00:00 2001 From: evetovicsm <5862838+evetovicsm@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:34:13 +0200 Subject: [PATCH 02/10] Removed an extra debug line. --- src/sessionapi.psm1 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index e6a0aec..0565260 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -27,7 +27,6 @@ function Connect-Sps Disable-SslVerification if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } } - write-host $Thumbrint try { From 5a5865e37b5976c3c585ddff94f81fb79db9afbe Mon Sep 17 00:00:00 2001 From: evetovicsm <5862838+evetovicsm@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:42:11 +0200 Subject: [PATCH 03/10] Updated .SYNOPSIS for Connect-SafeguardSps with the new parameters --- src/sessionapi.psm1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index 0565260..3687556 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -503,6 +503,12 @@ The username to authenticate as. .PARAMETER Password SecureString containing the password. +.PARAMETER Thumbprint +Thumbprint of the certificate in the Users local certificate store. + +.PARAMETER CertificateFile +Path to the pfx certificate on the filesystem. + .INPUTS None. From 66b8bfe55e3dde15e3adf5398e6a58447355504a Mon Sep 17 00:00:00 2001 From: evetovicsm <5862838+evetovicsm@users.noreply.github.com> Date: Tue, 20 Jun 2023 14:28:36 +0200 Subject: [PATCH 04/10] Added LocalLogin switch param to Connect-SafeguardSps --- src/sessionapi.psm1 | 2819 ++++++++++++++++++++++--------------------- 1 file changed, 1413 insertions(+), 1406 deletions(-) diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index 3687556..ac0fa4e 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -1,1406 +1,1413 @@ -# Helpers -function Connect-Sps -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$SessionMaster, - [Parameter(Mandatory=$false)] - [string]$SessionUsername, - [Parameter(Mandatory=$false)] - [SecureString]$SessionPassword, - [Parameter(Mandatory=$false)] - [switch]$Insecure, - [Parameter(Mandatory=$false)] - [string]$CertificateFile, - [Parameter(Mandatory=$false)] - [string]$Thumbprint - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Import-Module -Name "$PSScriptRoot\sslhandling.psm1" -Scope Local - Edit-SslVersionSupport - if ($Insecure) - { - Disable-SslVerification - if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } - } - try - { - - if($Thumbprint){Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication?type=x509" -SessionVariable HttpSession -CertificateThumbprint $Thumbprint | Write-Verbose } - elseif($CertificateFile){ Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication?type=x509" -SessionVariable HttpSession -Certificate $CertificateFile | Write-Verbose } - else - { - $local:PasswordPlainText = [System.Net.NetworkCredential]::new("", $SessionPassword).Password - $local:BasicAuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $SessionUsername, $local:PasswordPlainText))) - Remove-Variable -Scope local PasswordPlainText - Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication" -SessionVariable HttpSession -Headers @{ Authorization = ("Basic {0}" -f $local:BasicAuthInfo) } | Write-Verbose - } - } - catch - { - Import-Module -Name "$PSScriptRoot\sg-utilities.psm1" -Scope Local - Out-SafeguardExceptionIfPossible $_ - } - finally - { - if($local:BasicAuthInfo){ - Remove-Variable -Scope local BasicAuthInfo - } - } - - $HttpSession -} -function New-SpsUrl -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$RelativeUrl, - [Parameter(Mandatory=$false)] - [object]$Parameters - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:Url = "https://$($SafeguardSpsSession.Appliance)/api/$RelativeUrl" - if ($Parameters -and $Parameters.Length -gt 0) - { - $local:Url += "?" - $Parameters.Keys | ForEach-Object { - $local:Url += ($_ + "=" + [uri]::EscapeDataString($Parameters.Item($_)) + "&") - } - $local:Url = $local:Url -replace ".$" - } - $local:Url -} -function Invoke-SpsWithBody -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Method, - [Parameter(Mandatory=$true,Position=1)] - [string]$RelativeUrl, - [Parameter(Mandatory=$true,Position=2)] - [object]$Headers, - [Parameter(Mandatory=$false)] - [object]$Body, - [Parameter(Mandatory=$false)] - [object]$JsonBody, - [Parameter(Mandatory=$false)] - [object]$Parameters - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:BodyInternal = $JsonBody - if ($Body) - { - $local:BodyInternal = (ConvertTo-Json -Depth 100 -InputObject $Body) - } - $local:Url = (New-SpsUrl $RelativeUrl -Parameters $Parameters) - Write-Verbose "Url=$($local:Url)" - Write-Verbose "Parameters=$(ConvertTo-Json -InputObject $Parameters)" - Write-Verbose "---Request Body---" - Write-Verbose "$($local:BodyInternal)" - Invoke-RestMethod -WebSession $SafeguardSpsSession.Session -Method $Method -Headers $Headers -Uri $local:Url ` - -Body ([System.Text.Encoding]::UTF8.GetBytes($local:BodyInternal)) ` -} -function Invoke-SpsWithoutBody -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Method, - [Parameter(Mandatory=$true,Position=1)] - [string]$RelativeUrl, - [Parameter(Mandatory=$true,Position=2)] - [object]$Headers, - [Parameter(Mandatory=$false)] - [object]$Parameters, - [Parameter(Mandatory=$false)] - [string]$InFile - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:Url = (New-SpsUrl $RelativeUrl -Parameters $Parameters) - Write-Verbose "Url=$($local:Url)" - Write-Verbose "Parameters=$(ConvertTo-Json -InputObject $Parameters)" - $arguments = @{ - WebSession = $SafeguardSpsSession.Session; - Method = $Method; - Headers = $Headers; - Uri = $local:Url; - } - if ($InFile) - { - $arguments = $arguments + @{ InFile = $InFile } - } - - Invoke-RestMethod @arguments -} -function Invoke-SpsInternal -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Method, - [Parameter(Mandatory=$true,Position=1)] - [string]$RelativeUrl, - [Parameter(Mandatory=$true,Position=2)] - [object]$Headers, - [Parameter(Mandatory=$false)] - [object]$Body, - [Parameter(Mandatory=$false)] - [string]$JsonBody, - [Parameter(Mandatory=$false)] - [HashTable]$Parameters, - [Parameter(Mandatory=$false)] - [string]$InFile - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - try - { - switch ($Method.ToLower()) - { - {$_ -in "get","delete"} { - Invoke-SpsWithoutBody $Method $RelativeUrl $Headers -Parameters $Parameters - break - } - {$_ -in "put","post"} { - if($InFile) - { - Invoke-SpsWithoutBody $Method $RelativeUrl $Headers -Parameters $Parameters -InFile $InFile - } - else - { - Invoke-SpsWithBody $Method $RelativeUrl $Headers ` - -Body $Body -JsonBody $JsonBody -Parameters $Parameters - } - break - } - } - } - catch - { - Import-Module -Name "$PSScriptRoot\sg-utilities.psm1" -Scope Local - Out-SafeguardExceptionIfPossible $_ - } -} - -<# -.SYNOPSIS -Get the welcome wizard status for a newly deployed SPS. - -.DESCRIPTION -When SPS first deploys it boots with a DHCP address and needs to be initialized for -secure use. In the UI, an administrator can go through the welcome wizard experience -to provide the necessary information. This cmdlet provides a method to determine -whether the welcome wizard has been completed or not. - -.PARAMETER Appliance -DHCP address of newly deployed Safeguard SPS appliance. - -.INPUTS -None. - -.OUTPUTS -None - -.EXAMPLE -Get-SafeguardSpsWelcomeWizardStatus -Appliance 10.5.37.96 - -#> -function Get-SafeguardSpsWelcomeWizardStatus -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Appliance - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - (Invoke-RestMethod -Method GET -Headers @{'Accept' = 'application/json'} -Uri "https://$($Appliance)/api/setup" -SkipCertificateCheck).status -} - -<# -.SYNOPSIS -Complete the welcome wizard on a newly deployed SPS so that you can begin using it -via the UI or API. - -.DESCRIPTION -When SPS first deploys it boots with a DHCP address and needs to be initialized for -secure use. In the UI, an administrator can go through the welcome wizard experience -to provide the necessary information. This cmdlet provides a programmatic interface -to complete the same task. - -.PARAMETER Appliance -DHCP address of newly deployed Safeguard SPS appliance. - -.PARAMETER LicenseFile -A string containing the path to a Safeguard license file. - -.PARAMETER RootPassword -A secure string containing the desired root password. Default: . - -.PARAMETER AdminPassword -A secure string containing the desired admin password. Default: . - -.PARAMETER CaCertificateFile -A string containing the path to a CA certificate file in PEM format. - -.PARAMETER WebServerCertificateFile -A string containing the path to a web server certificate file in PEM format. - -.PARAMETER WebServerPrivateKeyFile -A string containing the path to a web server private key file in PEM format. - -.PARAMETER TimeStampingCertificateFile -A string containing the path to a timestamp authority certificate file in PEM format. - -.PARAMETER TimeStampingPrivateKeyFile -A string containing the path to a timestamp authority private key file in PEM format. - -.PARAMETER HostName -A string containing the desired hostname for SPS. - -.PARAMETER DomainName -A string containing the desired DNS suffix for SPS. - -.PARAMETER IpAddressWithNetMask -A string containing the desired IP address for SPS with netmask in CIDR format. - -.PARAMETER Gateway -A string containing the desired gateway IP address for SPS. - -.PARAMETER PrimaryDns -A string containing the desired primary DNS server IP address for SPS. - -.PARAMETER SmtpServer -A string containing the desired SMTP server. - -.PARAMETER AdminEmail -A string containing the administrator's email. - -.PARAMETER TimeZone -A string containing the IANA time zone for SPS. - -.PARAMETER PrimaryNtpServer -A string containing the desired primary NTP server. - -.PARAMETER Timeout -A timeout value in seconds to wait for SPS to complete (default: 600 seconds or 10 minutes). - -.INPUTS -None. - -.OUTPUTS -None - -.EXAMPLE -Complete-SafeguardSpsWelcomeWizard -Appliance 10.5.37.96 -LicenseFile License.txt -CaCertificateFile CA.cert.pem -WebServerCertificateFile server.cert.pem -WebServerPrivateKeyFile server.key.pem -TimeStampingCertificateFile TSA.cert.pem -TimeStampingPrivateKeyFile TSA.key.pem -HostName sps -DomainName example.corp -IpAddressWithNetMask 10.5.32.205/24 -Gateway 10.5.32.1 -PrimaryDns 10.5.32.37 -SmtpServer mail.example.corp -AdminEmail admin@example.corp -TimeZone "America/Denver" -PrimaryNtpServer time.windows.com - -#> -function Complete-SafeguardSpsWelcomeWizard -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Appliance, - [Parameter(Mandatory=$true)] - [string]$LicenseFile, - [Parameter(Mandatory=$false)] - [SecureString]$RootPassword, - [Parameter(Mandatory=$false)] - [SecureString]$AdminPassword, - [Parameter(Mandatory=$true)] - [string]$CaCertificateFile, - [Parameter(Mandatory=$true)] - [string]$WebServerCertificateFile, - [Parameter(Mandatory=$true)] - [string]$WebServerPrivateKeyFile, - [Parameter(Mandatory=$true)] - [string]$TimeStampingCertificateFile, - [Parameter(Mandatory=$true)] - [string]$TimeStampingPrivateKeyFile, - [Parameter(Mandatory=$true)] - [string]$HostName, - [Parameter(Mandatory=$true)] - [string]$DomainName, - [Parameter(Mandatory=$true)] - [string]$IpAddressWithNetMask, - [Parameter(Mandatory=$true)] - [string]$Gateway, - [Parameter(Mandatory=$true)] - [string]$PrimaryDns, - [Parameter(Mandatory=$true)] - [string]$SmtpServer, - [Parameter(Mandatory=$true)] - [string]$AdminEmail, - [Parameter(Mandatory=$true)] - [string]$TimeZone, - [Parameter(Mandatory=$true)] - [string]$PrimaryNtpServer, - [Parameter(Mandatory=$false)] - [int]$Timeout = 600, - [Parameter(Mandatory=$false)] - [switch]$PollOriginalIp - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:Response = (Invoke-RestMethod -Method GET -Headers @{'Accept' = 'application/json'} -Uri "https://$($Appliance)/api/setup" -SkipCertificateCheck) - if ($local:Response.status -ine "uninitialized") - { - Write-Host -ForegroundColor "Configuration Status: $($local:Response.status)" - throw "Configuration is not uninitialized" - } - - # Validate files and convert to strings ready for JSON - $local:LicenseContents = ((Get-Content $LicenseFile -Raw) -replace "`r","") -replace "`n","\n" - $local:Ca = ((Get-Content $CaCertificateFile -Raw) -replace "`r","") -replace "`n","\n" - $local:WebServer = ((Get-Content $WebServerCertificateFile -Raw) -replace "`r","") -replace "`n","\n" - $local:WebServerKey = ((Get-Content $WebServerPrivateKeyFile -Raw) -replace "`r","") -replace "`n","\n" - $local:TimeStamping = ((Get-Content $TimeStampingCertificateFile -Raw) -replace "`r","") -replace "`n","\n" - $local:TimeStampingKey = ((Get-Content $TimeStampingPrivateKeyFile -Raw) -replace "`r","") -replace "`n","\n" - - # Prompt for / convert passwords - if (-not $RootPassword) - { - $RootPassword = (Read-Host "SPS Root Password" -AsSecureString) - } - if (-not $AdminPassword) - { - $AdminPassword = (Read-Host "SPS Admin Password" -AsSecureString) - } - $local:RootPasswordPlainText = [System.Net.NetworkCredential]::new("", $RootPassword).Password - $local:AdminPasswordPlainText = [System.Net.NetworkCredential]::new("", $AdminPassword).Password - - # Validate other inputs - Import-Module -Name "$PSScriptRoot\ps-utilities.psm1" -Scope Local - if (-not (Test-IpAddress $Gateway)) - { - throw "Gateway `"$Gateway`" is not an IP address" - } - $local:Parts = ($IpAddressWithNetMask -split '/') - if ($local:Parts.Count -ne 2 -or -not (Test-IpAddress $local:Parts[0]) -or $local:Parts[1] -lt 0 -or $local:Parts[1] -gt 31) - { - throw "IpAddressWithNetMask `"$IpAddressWithNetMask`" must be CIDR format" - } - if (-not (Test-IpAddress $PrimaryDns)) - { - throw "PrimaryDns `"$PrimaryDns` is not an IP address" - } - - $local:JsonBody = @" -{ - "accept_eula": true, - "license": "$local:LicenseContents", - "administration": { - "root_password": "$local:RootPasswordPlainText", - "admin_password": "$local:AdminPasswordPlainText" - }, - "certificates": { - "ca": { - "certificate": "$local:Ca" - }, - "webserver": { - "certificate": "$local:WebServer", - "private_key": "$local:WebServerKey" - }, - "tsa": { - "certificate": "$local:TimeStamping", - "private_key": "$local:TimeStampingKey" - } - }, - "network": { - "hostname": "$HostName", - "domainname": "$DomainName", - "initial_address": "$IpAddressWithNetMask", - "gateway": "$Gateway", - "vlantag": null, - "primary_dns": "$PrimaryDns" - }, - "email": { - "smtp_server": "$SmtpServer", - "admin_email": "$AdminEmail" - }, - "datetime": { - "timezone": "$TimeZone", - "primary_ntp_server": "$PrimaryNtpServer" - } -} -"@ - Write-Host "Posting configuration data..." - if ($PollOriginalIp) - { - $local:PollAddress = $Appliance - } - else - { - $local:PollAddress = $local:Parts[0] - } - # On an address change SPS does not return a response, and Invoke-RestMethod errors out - try { $local:Status = (Invoke-RestMethod -Method POST -Headers @{'Content-type' = 'application/json'} -Timeout $Timeout ` - -Uri "https://$($Appliance)/api/setup" -Body $local:JsonBody -SkipCertificateCheck).status } - catch { $local:Status = "unknown" } - - Start-Sleep 5 # up front wait to solve new transition timing issues - - $local:StartTime = (Get-Date) - $local:TimeElapsed = 10 - if ($Timeout -lt 10) { $Timeout = 10 } - do { - Write-Progress -Activity "Waiting for completed status" -Status "Current: $($local:Status)" -PercentComplete (($local:TimeElapsed / $Timeout) * 100) - try { $local:Status = (Invoke-RestMethod -Method Get -Headers @{'Accept'='application/json'} -Uri "https://$($local:PollAddress)/api/setup" ` - -SkipCertificateCheck -timeout $Timeout).status } - catch { $local:Status = "unknown" } - Start-Sleep 2 - $local:TimeElapsed = (((Get-Date) - $local:StartTime).TotalSeconds) - if ($local:TimeElapsed -gt $Timeout) - { - throw "Timed out waiting for completed status, timeout was $Timeout seconds" - } - } until ($local:Status -ieq "completed" -or $local:Status -ieq "booting") - Write-Progress -Activity "Waiting for completed status" -Status "Current: $($local:Status)" -PercentComplete 100 -} - -<# -.SYNOPSIS -Log into a Safeguard SPS appliance in this Powershell session for the purposes -of using the SPS Web API. - -.DESCRIPTION -This utility can help you securely create a login session with a Safeguard SPS -appliance and save it as a global variable. - -The password may be passed in as a SecureString. By default, this -script will securely prompt for the password. - -.PARAMETER Appliance -IP address or hostname of a Safeguard SPS appliance. - -.PARAMETER Insecure -Ignore verification of Safeguard SPS appliance SSL certificate--will be ignored for entire session. - -.PARAMETER Username -The username to authenticate as. - -.PARAMETER Password -SecureString containing the password. - -.PARAMETER Thumbprint -Thumbprint of the certificate in the Users local certificate store. - -.PARAMETER CertificateFile -Path to the pfx certificate on the filesystem. - -.INPUTS -None. - -.OUTPUTS -None (with session variable filled out for calling Sps Web API). - - -.EXAMPLE -Connect-SafeguardSps 10.5.32.54 admin -Insecure - -Login Successful. - -.EXAMPLE -Connect-SafeguardSps sps1.mycompany.corp admin - -Login Successful. -#> -function Connect-SafeguardSps -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Appliance, - [Parameter(Mandatory=$false)] - [string]$Username, - [Parameter(Mandatory=$false)] - [SecureString]$Password, - [Parameter(Mandatory=$false)] - [switch]$Insecure, - [Parameter(Mandatory=$false)] - [string]$CertificateFile, - [Parameter(Mandatory=$false)] - [string]$Thumbprint - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if($CertificateFile){ $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -CertificateFile $CertificateFile -Insecure:$Insecure)} - elseif($Thumbprint){ $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -Thumbprint $Thumbprint -Insecure:$Insecure)} - else - { - if (-not $Password) {$Password = (Read-Host "Password" -AsSecureString) } - $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -SessionUsername $Username -SessionPassword $Password -Insecure:$Insecure) - } - - - Set-Variable -Name "SafeguardSpsSession" -Scope Global -Value @{ - "Appliance" = $Appliance; - "Insecure" = $Insecure; - "Session" = $local:HttpSession - } - Write-Host "Login Successful." -} - -<# -.SYNOPSIS -Log out of a Safeguard SPS appliance when finished using the SPS Web API. - -.DESCRIPTION -This utility will remove the session variable -that was created by the Connect-SafeguardSps cmdlet. - -.INPUTS -None. - -.OUTPUTS -None. - -.EXAMPLE -Disconnect-SafeguardSps - -Log out Successful. - -#> -function Disconnect-SafeguardSps -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if (-not $SafeguardSpsSession) - { - Write-Host "Not logged in." - } - else - { - Write-Host "Session variable removed." - Set-Variable -Name "SafeguardSpsSession" -Scope Global -Value $null - } -} - -<# -.SYNOPSIS -Call a method in the Safeguard SPS Web API. - -.DESCRIPTION -This utility is useful for calling the Safeguard SPS Web API for testing or -scripting purposes. It provides a couple benefits over using curl.exe or -Invoke-RestMethod by generating or reusing a secure session and composing -the Url, headers, parameters, and body for the request. - -This script is meant to be used with the Connect-SafeguardSps cmdlet which -will generate and store a variable in the session so that it doesn't need -to be passed to each call to the API. Call Disconnect-SafeguardSps when -finished. - -Safeguard SPS Web API is implemented as HATEOAS. To get started crawling -through the API, call Show-SafeguardSpsEndpoint. Then, you can follow to -the different API areas, such as configuration or health-status. - -.PARAMETER Appliance -IP address or hostname of a Safeguard appliance. - -.PARAMETER Method -HTTP method verb you would like to use: GET, PUT, POST, DELETE. - -.PARAMETER RelativeUrl -Relative portion of the Url you would like to call starting after /api. - -.PARAMETER Accept -Specify the Accept header (default: application/json), Use text/csv to request CSV output. - -.PARAMETER ContentType -Specify the Content-type header (default: application/json). - -.PARAMETER Body -A hash table containing an object to PUT or POST to the Url. - -.PARAMETER JsonBody -A pre-formatted JSON string to PUT or Post to the URl. If -Body is also specified, this is ignored. -It can sometimes be difficult to get arrays of objects to behave properly with hashtables in Powershell. - -.PARAMETER Parameters -A hash table containing the HTTP query parameters to add to the Url. - -.PARAMETER JsonOutput -A switch to return data as pretty JSON string. - -.PARAMETER BodyOutput -A switch to just return the body as a PowerShell object. - -.INPUTS -None. - -.OUTPUTS -JSON response from Safeguard Web API. - -.EXAMPLE -Invoke-SafeguardSpsMethod GET starling/join - -.EXAMPLE -Invoke-SafeguardSpsMethod GET / -JsonOutput - -.EXAMPLE -Open-SafeguardSpsTransaction -$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) -$body.admin_address = "admin@mycompany.corp" -Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body -Close-SafeguardSpsTransaction -#> -function Invoke-SafeguardSpsMethod -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$Method, - [Parameter(Mandatory=$true,Position=1)] - [string]$RelativeUrl, - [Parameter(Mandatory=$false)] - [string]$Accept = "application/json", - [Parameter(Mandatory=$false)] - [string]$ContentType = "application/json", - [Parameter(Mandatory=$false)] - [object]$Body, - [Parameter(Mandatory=$false)] - [string]$JsonBody, - [Parameter(Mandatory=$false)] - [HashTable]$Parameters, - [Parameter(Mandatory=$false)] - [HashTable]$ExtraHeaders, - [Parameter(Mandatory=$false)] - [switch]$JsonOutput, - [Parameter(Mandatory=$false)] - [switch]$BodyOutput, - [Parameter(Mandatory=$false)] - [string]$InFile - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if (-not $SafeguardSpsSession) - { - throw "This cmdlet requires that you log in with the Connect-SafeguardSps cmdlet" - } - - $local:Insecure = $SafeguardSpsSession.Insecure - Write-Verbose "Insecure=$($local:Insecure)" - Import-Module -Name "$PSScriptRoot\sslhandling.psm1" -Scope Local - Edit-SslVersionSupport - if ($local:Insecure) - { - Disable-SslVerification - if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } - } - - $local:Headers = @{ - "Accept" = $Accept; - "Content-type" = $ContentType; - } - - foreach ($key in $ExtraHeaders.Keys) - { - $local:Headers[$key] = $ExtraHeaders[$key] - } - - Write-Verbose "---Request---" - Write-Verbose "Headers=$(ConvertTo-Json -InputObject $local:Headers)" - - try - { - $arguments = @{ - Method = $Method; - RelativeUrl = $RelativeUrl; - Headers = $local:Headers; - Body = $Body; - JsonBody = $JsonBody; - Parameters = $Parameters; - InFile = $InFile; - } - if ($JsonOutput) - { - (Invoke-SpsInternal @arguments) | ConvertTo-Json -Depth 100 - } - elseif ($BodyOutput) - { - $local:Response = (Invoke-SpsInternal @arguments) - if ($local:Response.body) - { - $local:Response.body - } - else - { - Write-Verbose "No body returned in response" - } - } - else - { - Invoke-SpsInternal @arguments - } - } - finally - { - if ($local:Insecure) - { - Enable-SslVerification - if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } - } - } -} - -<# -.SYNOPSIS -Open a transaction for making changes via the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet is used to create a transaction necessary to make changes via -the Safeguard SPS API. Recent versions of SPS will open a transaction -automatically, but this cmdlet may be used to open a transaction explicitly. - -In order to permanently save changes made via the Safeguard SPS API, you -must also call Close-SafeguardSpsTransaction or its alias -Save-SafeguardSpsTransaction. Clear-SafeguardSpsTransaction can be used to -cancel changes. - -.INPUTS -None. - -.OUTPUTS -JSON response from Safeguard Web API. - -.EXAMPLE -Open-SafeguardSpsTransaction -$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) -$body.admin_address = "admin@mycompany.corp" -Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body -Close-SafeguardSpsTransaction -#> -function Open-SafeguardSpsTransaction -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Invoke-SafeguardSpsMethod POST transaction -} - -<# -.SYNOPSIS -Close a transaction and save changes made via the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet is used to end a transaction and permanently save the changes -made via the Safeguard SPS API. This cmdlet is meant to be used with -Open-SafeguardSpsTransaction. Save-SafeguardSpsTransaction is an alias -for this cmdlet. Clear-SafeguardSpsTransaction can be used to cancel changes. - -To see the status of a transaction, use Get-SafeguardSpsTransaction. To -see only the changes that are about to be made via a transaction, use -Show-SafeguardSpsTransactionChange. - -.INPUTS -None. - -.OUTPUTS -JSON response from Safeguard Web API. - -.EXAMPLE -Open-SafeguardSpsTransaction -$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) -$body.admin_address = "admin@mycompany.corp" -Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body -Close-SafeguardSpsTransaction -#> -function Close-SafeguardSpsTransaction -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Invoke-SafeguardSpsMethod PUT transaction -Body @{ status = "commit" } -} -New-Alias -Name Save-SafeguardSpsTransaction -Value Close-SafeguardSpsTransaction - -<# -.SYNOPSIS -Get the status of a transaction using the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet will report the status of an SPS transaction. The status 'closed' -means no transaction is pending. The status 'open' means the transaction is -pending. Close-SafeguardSpsTransaction can be used to permanently save changes. -Clear-SafeguardSpsTransaction can be used to cancel changes. The remaining -seconds is the time before the transaction will cancel automatically and the -login session will be terminated. - -.INPUTS -None. - -.OUTPUTS -JSON response from Safeguard Web API. - -.EXAMPLE -Open-SafeguardSpsTransaction -$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) -$body.admin_address = "admin@mycompany.corp" -Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body -Get-SafeguardSpsTransaction -Clear-SafeguardSpsTransaction -#> -function Get-SafeguardSpsTransaction -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:response = (Invoke-SafeguardSpsMethod GET transaction) - $local:TransactionInfo = [ordered]@{ - Status = $local:response.body.status; - CommitMessage = $local:response.body.commit_message; - RemainingSeconds = $local:response.meta.remaining_seconds; - Changes = @() - } - if ($local:response.meta.changes) - { - $local:Changes = (Invoke-SafeguardSpsMethod GET transaction/changes).changes - if ($local:Changes) { $local:TransactionInfo.Changes = $local:Changes } - } - New-Object PSObject -Property $local:TransactionInfo -} - -<# -.SYNOPSIS -Show the pending changes in a transaction using the Safeguard SPS Web API. - -.DESCRIPTION -Transactions are required to make changes via the Safeguard SPS Web API. The -transaction must be closed or saved before changes become permanent. This cmdlet -will show what values will be permanently changed if the transaction is closed. - -.INPUTS -None. - -.OUTPUTS -JSON response from Safeguard Web API. - -.EXAMPLE -Open-SafeguardSpsTransaction -$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) -$body.admin_address = "admin@mycompany.corp" -Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body -Show-SafeguardSpsTransactionChange -#> -function Show-SafeguardSpsTransactionChange -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - (Get-SafeguardSpsTransaction).Changes | ConvertTo-Json -Depth 100 -} - -<# -.SYNOPSIS -Cancel a transaction using the Safeguard SPS Web API. - -.DESCRIPTION -Transactions are required to make changes via the Safeguard SPS Web API. The -transaction must be closed or saved before changes become permanent. This cmdlet -may be used to cancel pending changes. - -.INPUTS -None. - -.OUTPUTS -JSON response from Safeguard Web API. - -.EXAMPLE -Open-SafeguardSpsTransaction -$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) -$body.admin_address = "admin@mycompany.corp" -Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body -Get-SafeguardSpsTransaction -Clear-SafeguardSpsTransaction -#> -function Clear-SafeguardSpsTransaction -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Invoke-SafeguardSpsMethod DELETE transaction -} - -<# -.SYNOPSIS -Call a method in the Safeguard SPS Web API. - -.DESCRIPTION -Safeguard SPS Web API is implemented as HATEOAS. This cmdlet is helpful for -crawling through the API. You can explore the different API areas, such as -configuration or health-status. - -.PARAMETER RelativeUrl -Relative portion of the Url you would like to call starting after /api. - -.EXAMPLE -Show-SafeguardSpsEndpoint configuration - -.EXAMPLE -Show-SafeguardSpsEndpoint configuration/ssh/connections -#> -function Show-SafeguardSpsEndpoint -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$false,Position=0)] - [string]$RelativeUrl - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if (-not $RelativeUrl) { $RelativeUrl = "/" } - - $local:Response = (Invoke-SafeguardSpsMethod GET $RelativeUrl) - if ($local:Response.items) - { - $local:Response.items | Select-Object key,meta - } - else - { - $local:Response.meta.href - } -} - -<# -.SYNOPSIS -Gather join information from Safeguard SPS and open a browser to Starling to -complete the join via the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet with call the Safeguard SPS API to determine the join status, and -if not joined, it will gather the information necessary to start the join -process using the system browser. The join process requires copying and pasting -credentials and token endpoint back from the browser to complete the join. -Credentials will not be echoed to the screen. - -.PARAMETER Environment -Which Starling environment to join (default: prod) - -.EXAMPLE -Invoke-SafeguardSpsStarlingJoinBrowser -#> -function Invoke-SafeguardSpsStarlingJoinBrowser -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$false,Position=0)] - [ValidateSet("dev", "devtest", "stage", "prod", IgnoreCase=$true)] - [string]$Environment = "prod" - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:Info = (Invoke-SafeguardSpsMethod GET configuration/starling).body - if ($local:Info.join_info) - { - Write-Host -ForegroundColor Yellow "Safeguard SPS is already joined to Starling" - $local:Info.join_info - Write-Host -ForegroundColor Yellow "You must unjoin before you can rejoin Starling" - } - else - { - $local:JoinBody = (Invoke-SafeguardSpsMethod GET starling/join).body - $local:InstanceName = $local:JoinBody.product_instance - $local:TimsLicense = $local:JoinBody.product_tims - switch ($Environment) - { - "dev" { $local:Suffix = "-dev"; $Environment = "dev"; break } - "devtest" { $local:Suffix = "-devtest"; $Environment = "devtest"; break } - "stage" { $local:Suffix = "-stage"; $Environment = "stage"; break } - "prod" { $local:Suffix = ""; $Environment = "prod"; break } - } - $local:JoinUrl = "https://account$($local:Suffix).cloud.oneidentity.com/join/Safeguard/$($local:InstanceName)/$($local:TimsLicense)" - - Import-Module -Name "$PSScriptRoot\ps-utilities.psm1" -Scope Local - - Write-Host -ForegroundColor Yellow "This command will use an external browser to join Safeguard SPS ($($local:InstanceName)) to Starling ($Environment)." - Write-host "You will be required to copy and paste interactively from the browser to answer prompts for join information." - $local:Confirmed = (Get-Confirmation "Join to Starling" "Are you sure you want to use an external browser to join to Starling?" ` - "Show the browser." "Cancels this operation.") - - if ($local:Confirmed) - { - Start-Process $local:JoinUrl - - Write-Host "Following the successful join in the browser, provide the following:" - $local:Creds = (Read-Host "Credential String" -MaskInput) - $local:Endpoint = (Read-Host "Token Endpoint") - $local:Body = [ordered]@{ - environment = $Environment; - token_endpoint = $local:Endpoint; - credential_string = $local:Creds; - } - $local:JoinBody | Add-Member -NotePropertyMembers $local:Body -TypeName PSCustomObject - - Invoke-SafeguardSpsMethod POST "starling/join" -Body $local:JoinBody - - Write-Host -ForegroundColor Yellow "You may close the external browser." - } - } -} - -<# -.SYNOPSIS -Remove the Starling join via the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet with call the Safeguard SPS API to remove a Starling join. You -cannot unjoin if SRA is enabled. - -.EXAMPLE -Remove-SafeguardSpsStarlingJoin -#> -function Remove-SafeguardSpsStarlingJoin -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Invoke-SafeguardSpsMethod DELETE starling/join -} - -<# -.SYNOPSIS -Enable Safeguard Remote Access in Starling via the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet will enable Safeguard Remote Access in Starling if this Safeguard SPS -is joined to Starling. - -.EXAMPLE -Enable-SafeguardSpsStarlingJoin -#> -function Enable-SafeguardSpsRemoteAccess -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:Info = (Invoke-SafeguardSpsMethod GET configuration/starling).Body - if ($local:Info.remote_access.enabled) - { - Write-Warning "Safeguard Remote Access is already enabled" - } - else - { - $local:Info.remote_access.enabled = $true - Open-SafeguardSpsTransaction - Invoke-SafeguardSpsMethod PUT configuration/starling -Body $local:Info - Save-SafeguardSpsTransaction - } -} -New-Alias -Name Enable-SafeguardSpsSra -Value Enable-SafeguardSpsRemoteAccess - -<# -.SYNOPSIS -Disable Safeguard Remote Access in Starling via the Safeguard SPS Web API. - -.DESCRIPTION -This cmdlet will disable Safeguard Remote Access in Starling if this Safeguard SPS -is joined to Starling. - -.EXAMPLE -Disable-SafeguardSpsRemoteAccess -#> -function Disable-SafeguardSpsRemoteAccess -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $local:Info = (Invoke-SafeguardSpsMethod GET configuration/starling).Body - if ($local:Info.remote_access.enabled) - { - $local:Info.remote_access.enabled = $false - Open-SafeguardSpsTransaction - Invoke-SafeguardSpsMethod PUT configuration/starling -Body $local:Info - Save-SafeguardSpsTransaction - } - else - { - Write-Warning "Safeguard Remote Access is already disabled" - } -} -New-Alias -Name Disable-SafeguardSpsSra -Value Disable-SafeguardSpsRemoteAccess - -<# -Get Safeguard SPS appliance information via the Web API. - -.DESCRIPTION -This cmdlet will display basic information about Safeguard SPS. - -.EXAMPLE -Get-SafeguardSpsInfo -#> -function Get-SafeguardSpsInfo -{ - [CmdletBinding()] - Param( - [parameter(Mandatory, Position = 0)] - [string] - $FilePath - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - (Invoke-SafeguardSpsMethod GET info).body -} - -<# -.SYNOPSIS -Uploads a new firmware to SPS. - -.DESCRIPTION -This command takes a path to an SPS firmware and uploads it to an open firmware slot. - -.EXAMPLE -Import-SafeguardSpsFirmware -FilePath -#> -function Import-SafeguardSpsFirmware -{ - [CmdletBinding()] - Param( - [parameter(Mandatory, Position = 0)] - [string] - $FilePath - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Invoke-SafeguardSpsMethod POST upload/firmware -InFile $FilePath -ContentType 'application/x-iso9660-image' - -} - -<# -.SYNOPSIS -Get Safeguard SPS appliance version via the Web API. - -.DESCRIPTION -This cmdlet will display the version of Safeguard SPS. - -.EXAMPLE -Get-SafeguardSpsVersion - -.EXAMPLE -Get-SafeguardSpsVersion -AltSyntax -#> -function Get-SafeguardSpsVersion -{ - [CmdletBinding()] - Param( - [Parameter(Mandatory=$false)] - [switch]$AltSyntax - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if ($AltSyntax) - { - (Get-SafeguardSpsInfo).version - } - else - { - (Get-SafeguardSpsInfo).firmware_version - } -} - -<# -.SYNOPSIS -Returns the SPS firmware slot information. - -.DESCRIPTION -Returns the SPS firmware slot information. - -.EXAMPLE -Get-SafeguardSpsFirmwareSlot -#> -function Get-SafeguardSpsFirmwareSlot -{ - [CmdletBinding()] - Param( - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - Invoke-SafeguardSpsMethod GET firmware/slots -} - -<# -.SYNOPSIS -Tests a firmware slot. - -.DESCRIPTION -This command tests that the firmware slot contains valid firmware that can be installed and returns a boolean result. - -.EXAMPLE -Test-SafeguardSpsFirmware -Slot 3 -#> -function Test-SafeguardSpsFirmware -{ - [CmdletBinding()] - Param( - [parameter(Mandatory)] - [int]$Slot - ) - - $Body = @{ - slot_id = $Slot - } - - $summary = (Invoke-SafeguardSpsMethod POST firmware/test -Body $Body).body.test_summary - Write-Verbose $summary - return $summary.StartsWith("Upgrade is allowed;") -} - -<# -.SYNOPSIS -Starts a firmware upgrade. - -.DESCRIPTION -This command upgrades SPS with the firmware installed into the indicated slot. - -.EXAMPLE -Install-SafeguardSpsFirmware -Slot 3 -Message "Upgrading SPS firmware..." -#> -function Install-SafeguardSpsFirmware -{ - [CmdletBinding()] - Param( - [parameter(Mandatory)] - [int]$Slot, - [parameter(Mandatory)] - [string]$Message - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - if(-not $Message) - { - $Message = "Upgrading SPS firmware..." - } - $Body = @{ - slot_id = $Slot - message = $Message - } - - Invoke-SafeguardSpsMethod POST firmware/upgrade -Body $Body -} - -<# -.SYNOPSIS -Install-SafeguardSpsUpgrade - -.DESCRIPTION -This command automates the steps for uploading and installing an SPS firmware upgrade. - -.EXAMPLE -Install-SafeguardSpsPatch -FilePath -#> -function Install-SafeguardSpsUpgrade -{ - [CmdletBinding()] - Param( - [parameter(Mandatory, Position = 0)] - [string] - $FilePath, - [parameter(Mandatory, Position = 1)] - [string] - $TargetVersion - ) - - if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } - if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } - - $activity = "Installing SPS upgrade" - Write-Progress -Activity $activity -Status 'Importing firmware' -PercentComplete 15 - Import-SafeguardSpsFirmware $FilePath - $slots = (Get-SafeguardSpsFirmwareSlot).items.body - for($i = 0; $i -lt $slots.count; $i++) - { - if($slots[$i].version -ieq $TargetVersion) - { - Write-Progress -Activity $activity -Status "Testing firmware in slot $i" -PercentComplete 65 - if( Test-SafeguardSpsFirmware -Slot $i ) - { - Write-Progress -Activity $activity -Status "Installing $TargetVersion from slot $i" -PercentComplete 75 - Install-SafeguardSpsFirmware -Slot $i -Message "Upgrading SPS firmware to $TargetVersion" - Write-Progress -Activity $activity -Status "Finished" -PercentComplete 100 - Start-Sleep 1 - return - } - else - { - throw "Firmware at slot $i failed upgrade test. For details run: Test-SafeguardSpsFirmware -Slot $i" - } - } - } - throw "Firmware with version $TargetVersion could not be found in any firmware slot." -} +# Helpers +function Connect-Sps +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$SessionMaster, + [Parameter(Mandatory=$false)] + [string]$SessionUsername, + [Parameter(Mandatory=$false)] + [SecureString]$SessionPassword, + [Parameter(Mandatory=$false)] + [switch]$Insecure, + [Parameter(Mandatory=$false)] + [switch]$LocalLogin, + [Parameter(Mandatory=$false)] + [string]$CertificateFile, + [Parameter(Mandatory=$false)] + [string]$Thumbprint + + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Import-Module -Name "$PSScriptRoot\sslhandling.psm1" -Scope Local + Edit-SslVersionSupport + if ($Insecure) + { + Disable-SslVerification + if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } + } + write-host $Thumbrint + try + { + + if($Thumbprint){Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication?type=x509" -SessionVariable HttpSession -CertificateThumbprint $Thumbprint | Write-Verbose } + elseif($CertificateFile){ Invoke-RestMethod -Uri "https://$SessionMaster/api/authentication?type=x509" -SessionVariable HttpSession -Certificate $CertificateFile | Write-Verbose } + else + { + $sps_auth_uri = "https://$SessionMaster/api/authentication" + if($LocalLogin){ $sps_auth_uri = "https://$SessionMaster/api/authentication?login_method=local"} + + $local:PasswordPlainText = [System.Net.NetworkCredential]::new("", $SessionPassword).Password + $local:BasicAuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $SessionUsername, $local:PasswordPlainText))) + Remove-Variable -Scope local PasswordPlainText + + Invoke-RestMethod -Uri $sps_auth_uri -SessionVariable HttpSession -Headers @{ Authorization = ("Basic {0}" -f $local:BasicAuthInfo) } | Write-Verbose + } + } + catch + { + Import-Module -Name "$PSScriptRoot\sg-utilities.psm1" -Scope Local + Out-SafeguardExceptionIfPossible $_ + } + finally + { + if($local:BasicAuthInfo){ + Remove-Variable -Scope local BasicAuthInfo + } + } + + $HttpSession +} +function New-SpsUrl +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$RelativeUrl, + [Parameter(Mandatory=$false)] + [object]$Parameters + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:Url = "https://$($SafeguardSpsSession.Appliance)/api/$RelativeUrl" + if ($Parameters -and $Parameters.Length -gt 0) + { + $local:Url += "?" + $Parameters.Keys | ForEach-Object { + $local:Url += ($_ + "=" + [uri]::EscapeDataString($Parameters.Item($_)) + "&") + } + $local:Url = $local:Url -replace ".$" + } + $local:Url +} +function Invoke-SpsWithBody +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Method, + [Parameter(Mandatory=$true,Position=1)] + [string]$RelativeUrl, + [Parameter(Mandatory=$true,Position=2)] + [object]$Headers, + [Parameter(Mandatory=$false)] + [object]$Body, + [Parameter(Mandatory=$false)] + [object]$JsonBody, + [Parameter(Mandatory=$false)] + [object]$Parameters + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:BodyInternal = $JsonBody + if ($Body) + { + $local:BodyInternal = (ConvertTo-Json -Depth 100 -InputObject $Body) + } + $local:Url = (New-SpsUrl $RelativeUrl -Parameters $Parameters) + Write-Verbose "Url=$($local:Url)" + Write-Verbose "Parameters=$(ConvertTo-Json -InputObject $Parameters)" + Write-Verbose "---Request Body---" + Write-Verbose "$($local:BodyInternal)" + Invoke-RestMethod -WebSession $SafeguardSpsSession.Session -Method $Method -Headers $Headers -Uri $local:Url ` + -Body ([System.Text.Encoding]::UTF8.GetBytes($local:BodyInternal)) ` +} +function Invoke-SpsWithoutBody +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Method, + [Parameter(Mandatory=$true,Position=1)] + [string]$RelativeUrl, + [Parameter(Mandatory=$true,Position=2)] + [object]$Headers, + [Parameter(Mandatory=$false)] + [object]$Parameters, + [Parameter(Mandatory=$false)] + [string]$InFile + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:Url = (New-SpsUrl $RelativeUrl -Parameters $Parameters) + Write-Verbose "Url=$($local:Url)" + Write-Verbose "Parameters=$(ConvertTo-Json -InputObject $Parameters)" + $arguments = @{ + WebSession = $SafeguardSpsSession.Session; + Method = $Method; + Headers = $Headers; + Uri = $local:Url; + } + if ($InFile) + { + $arguments = $arguments + @{ InFile = $InFile } + } + + Invoke-RestMethod @arguments +} +function Invoke-SpsInternal +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Method, + [Parameter(Mandatory=$true,Position=1)] + [string]$RelativeUrl, + [Parameter(Mandatory=$true,Position=2)] + [object]$Headers, + [Parameter(Mandatory=$false)] + [object]$Body, + [Parameter(Mandatory=$false)] + [string]$JsonBody, + [Parameter(Mandatory=$false)] + [HashTable]$Parameters, + [Parameter(Mandatory=$false)] + [string]$InFile + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + try + { + switch ($Method.ToLower()) + { + {$_ -in "get","delete"} { + Invoke-SpsWithoutBody $Method $RelativeUrl $Headers -Parameters $Parameters + break + } + {$_ -in "put","post"} { + if($InFile) + { + Invoke-SpsWithoutBody $Method $RelativeUrl $Headers -Parameters $Parameters -InFile $InFile + } + else + { + Invoke-SpsWithBody $Method $RelativeUrl $Headers ` + -Body $Body -JsonBody $JsonBody -Parameters $Parameters + } + break + } + } + } + catch + { + Import-Module -Name "$PSScriptRoot\sg-utilities.psm1" -Scope Local + Out-SafeguardExceptionIfPossible $_ + } +} + +<# +.SYNOPSIS +Get the welcome wizard status for a newly deployed SPS. + +.DESCRIPTION +When SPS first deploys it boots with a DHCP address and needs to be initialized for +secure use. In the UI, an administrator can go through the welcome wizard experience +to provide the necessary information. This cmdlet provides a method to determine +whether the welcome wizard has been completed or not. + +.PARAMETER Appliance +DHCP address of newly deployed Safeguard SPS appliance. + +.INPUTS +None. + +.OUTPUTS +None + +.EXAMPLE +Get-SafeguardSpsWelcomeWizardStatus -Appliance 10.5.37.96 + +#> +function Get-SafeguardSpsWelcomeWizardStatus +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Appliance + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + (Invoke-RestMethod -Method GET -Headers @{'Accept' = 'application/json'} -Uri "https://$($Appliance)/api/setup" -SkipCertificateCheck).status +} + +<# +.SYNOPSIS +Complete the welcome wizard on a newly deployed SPS so that you can begin using it +via the UI or API. + +.DESCRIPTION +When SPS first deploys it boots with a DHCP address and needs to be initialized for +secure use. In the UI, an administrator can go through the welcome wizard experience +to provide the necessary information. This cmdlet provides a programmatic interface +to complete the same task. + +.PARAMETER Appliance +DHCP address of newly deployed Safeguard SPS appliance. + +.PARAMETER LicenseFile +A string containing the path to a Safeguard license file. + +.PARAMETER RootPassword +A secure string containing the desired root password. Default: . + +.PARAMETER AdminPassword +A secure string containing the desired admin password. Default: . + +.PARAMETER CaCertificateFile +A string containing the path to a CA certificate file in PEM format. + +.PARAMETER WebServerCertificateFile +A string containing the path to a web server certificate file in PEM format. + +.PARAMETER WebServerPrivateKeyFile +A string containing the path to a web server private key file in PEM format. + +.PARAMETER TimeStampingCertificateFile +A string containing the path to a timestamp authority certificate file in PEM format. + +.PARAMETER TimeStampingPrivateKeyFile +A string containing the path to a timestamp authority private key file in PEM format. + +.PARAMETER HostName +A string containing the desired hostname for SPS. + +.PARAMETER DomainName +A string containing the desired DNS suffix for SPS. + +.PARAMETER IpAddressWithNetMask +A string containing the desired IP address for SPS with netmask in CIDR format. + +.PARAMETER Gateway +A string containing the desired gateway IP address for SPS. + +.PARAMETER PrimaryDns +A string containing the desired primary DNS server IP address for SPS. + +.PARAMETER SmtpServer +A string containing the desired SMTP server. + +.PARAMETER AdminEmail +A string containing the administrator's email. + +.PARAMETER TimeZone +A string containing the IANA time zone for SPS. + +.PARAMETER PrimaryNtpServer +A string containing the desired primary NTP server. + +.PARAMETER Timeout +A timeout value in seconds to wait for SPS to complete (default: 600 seconds or 10 minutes). + +.INPUTS +None. + +.OUTPUTS +None + +.EXAMPLE +Complete-SafeguardSpsWelcomeWizard -Appliance 10.5.37.96 -LicenseFile License.txt -CaCertificateFile CA.cert.pem -WebServerCertificateFile server.cert.pem -WebServerPrivateKeyFile server.key.pem -TimeStampingCertificateFile TSA.cert.pem -TimeStampingPrivateKeyFile TSA.key.pem -HostName sps -DomainName example.corp -IpAddressWithNetMask 10.5.32.205/24 -Gateway 10.5.32.1 -PrimaryDns 10.5.32.37 -SmtpServer mail.example.corp -AdminEmail admin@example.corp -TimeZone "America/Denver" -PrimaryNtpServer time.windows.com + +#> +function Complete-SafeguardSpsWelcomeWizard +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Appliance, + [Parameter(Mandatory=$true)] + [string]$LicenseFile, + [Parameter(Mandatory=$false)] + [SecureString]$RootPassword, + [Parameter(Mandatory=$false)] + [SecureString]$AdminPassword, + [Parameter(Mandatory=$true)] + [string]$CaCertificateFile, + [Parameter(Mandatory=$true)] + [string]$WebServerCertificateFile, + [Parameter(Mandatory=$true)] + [string]$WebServerPrivateKeyFile, + [Parameter(Mandatory=$true)] + [string]$TimeStampingCertificateFile, + [Parameter(Mandatory=$true)] + [string]$TimeStampingPrivateKeyFile, + [Parameter(Mandatory=$true)] + [string]$HostName, + [Parameter(Mandatory=$true)] + [string]$DomainName, + [Parameter(Mandatory=$true)] + [string]$IpAddressWithNetMask, + [Parameter(Mandatory=$true)] + [string]$Gateway, + [Parameter(Mandatory=$true)] + [string]$PrimaryDns, + [Parameter(Mandatory=$true)] + [string]$SmtpServer, + [Parameter(Mandatory=$true)] + [string]$AdminEmail, + [Parameter(Mandatory=$true)] + [string]$TimeZone, + [Parameter(Mandatory=$true)] + [string]$PrimaryNtpServer, + [Parameter(Mandatory=$false)] + [int]$Timeout = 600, + [Parameter(Mandatory=$false)] + [switch]$PollOriginalIp + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:Response = (Invoke-RestMethod -Method GET -Headers @{'Accept' = 'application/json'} -Uri "https://$($Appliance)/api/setup" -SkipCertificateCheck) + if ($local:Response.status -ine "uninitialized") + { + Write-Host -ForegroundColor "Configuration Status: $($local:Response.status)" + throw "Configuration is not uninitialized" + } + + # Validate files and convert to strings ready for JSON + $local:LicenseContents = ((Get-Content $LicenseFile -Raw) -replace "`r","") -replace "`n","\n" + $local:Ca = ((Get-Content $CaCertificateFile -Raw) -replace "`r","") -replace "`n","\n" + $local:WebServer = ((Get-Content $WebServerCertificateFile -Raw) -replace "`r","") -replace "`n","\n" + $local:WebServerKey = ((Get-Content $WebServerPrivateKeyFile -Raw) -replace "`r","") -replace "`n","\n" + $local:TimeStamping = ((Get-Content $TimeStampingCertificateFile -Raw) -replace "`r","") -replace "`n","\n" + $local:TimeStampingKey = ((Get-Content $TimeStampingPrivateKeyFile -Raw) -replace "`r","") -replace "`n","\n" + + # Prompt for / convert passwords + if (-not $RootPassword) + { + $RootPassword = (Read-Host "SPS Root Password" -AsSecureString) + } + if (-not $AdminPassword) + { + $AdminPassword = (Read-Host "SPS Admin Password" -AsSecureString) + } + $local:RootPasswordPlainText = [System.Net.NetworkCredential]::new("", $RootPassword).Password + $local:AdminPasswordPlainText = [System.Net.NetworkCredential]::new("", $AdminPassword).Password + + # Validate other inputs + Import-Module -Name "$PSScriptRoot\ps-utilities.psm1" -Scope Local + if (-not (Test-IpAddress $Gateway)) + { + throw "Gateway `"$Gateway`" is not an IP address" + } + $local:Parts = ($IpAddressWithNetMask -split '/') + if ($local:Parts.Count -ne 2 -or -not (Test-IpAddress $local:Parts[0]) -or $local:Parts[1] -lt 0 -or $local:Parts[1] -gt 31) + { + throw "IpAddressWithNetMask `"$IpAddressWithNetMask`" must be CIDR format" + } + if (-not (Test-IpAddress $PrimaryDns)) + { + throw "PrimaryDns `"$PrimaryDns` is not an IP address" + } + + $local:JsonBody = @" +{ + "accept_eula": true, + "license": "$local:LicenseContents", + "administration": { + "root_password": "$local:RootPasswordPlainText", + "admin_password": "$local:AdminPasswordPlainText" + }, + "certificates": { + "ca": { + "certificate": "$local:Ca" + }, + "webserver": { + "certificate": "$local:WebServer", + "private_key": "$local:WebServerKey" + }, + "tsa": { + "certificate": "$local:TimeStamping", + "private_key": "$local:TimeStampingKey" + } + }, + "network": { + "hostname": "$HostName", + "domainname": "$DomainName", + "initial_address": "$IpAddressWithNetMask", + "gateway": "$Gateway", + "vlantag": null, + "primary_dns": "$PrimaryDns" + }, + "email": { + "smtp_server": "$SmtpServer", + "admin_email": "$AdminEmail" + }, + "datetime": { + "timezone": "$TimeZone", + "primary_ntp_server": "$PrimaryNtpServer" + } +} +"@ + Write-Host "Posting configuration data..." + if ($PollOriginalIp) + { + $local:PollAddress = $Appliance + } + else + { + $local:PollAddress = $local:Parts[0] + } + # On an address change SPS does not return a response, and Invoke-RestMethod errors out + try { $local:Status = (Invoke-RestMethod -Method POST -Headers @{'Content-type' = 'application/json'} -Timeout $Timeout ` + -Uri "https://$($Appliance)/api/setup" -Body $local:JsonBody -SkipCertificateCheck).status } + catch { $local:Status = "unknown" } + + Start-Sleep 5 # up front wait to solve new transition timing issues + + $local:StartTime = (Get-Date) + $local:TimeElapsed = 10 + if ($Timeout -lt 10) { $Timeout = 10 } + do { + Write-Progress -Activity "Waiting for completed status" -Status "Current: $($local:Status)" -PercentComplete (($local:TimeElapsed / $Timeout) * 100) + try { $local:Status = (Invoke-RestMethod -Method Get -Headers @{'Accept'='application/json'} -Uri "https://$($local:PollAddress)/api/setup" ` + -SkipCertificateCheck -timeout $Timeout).status } + catch { $local:Status = "unknown" } + Start-Sleep 2 + $local:TimeElapsed = (((Get-Date) - $local:StartTime).TotalSeconds) + if ($local:TimeElapsed -gt $Timeout) + { + throw "Timed out waiting for completed status, timeout was $Timeout seconds" + } + } until ($local:Status -ieq "completed" -or $local:Status -ieq "booting") + Write-Progress -Activity "Waiting for completed status" -Status "Current: $($local:Status)" -PercentComplete 100 +} + +<# +.SYNOPSIS +Log into a Safeguard SPS appliance in this Powershell session for the purposes +of using the SPS Web API. + +.DESCRIPTION +This utility can help you securely create a login session with a Safeguard SPS +appliance and save it as a global variable. + +The password may be passed in as a SecureString. By default, this +script will securely prompt for the password. + +.PARAMETER Appliance +IP address or hostname of a Safeguard SPS appliance. + +.PARAMETER Insecure +Ignore verification of Safeguard SPS appliance SSL certificate--will be ignored for entire session. + +.PARAMETER LocalLogin +Enable authentication from the local database. + +.PARAMETER Username +The username to authenticate as. + +.PARAMETER Password +SecureString containing the password. + +.INPUTS +None. + +.OUTPUTS +None (with session variable filled out for calling Sps Web API). + + +.EXAMPLE +Connect-SafeguardSps 10.5.32.54 admin -Insecure + +Login Successful. + +.EXAMPLE +Connect-SafeguardSps sps1.mycompany.corp admin + +Login Successful. +#> +function Connect-SafeguardSps +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Appliance, + [Parameter(Mandatory=$false)] + [string]$Username, + [Parameter(Mandatory=$false)] + [SecureString]$Password, + [Parameter(Mandatory=$false)] + [switch]$Insecure, + [Parameter(Mandatory=$false)] + [switch]$LocalLogin, + [Parameter(Mandatory=$false)] + [string]$CertificateFile, + [Parameter(Mandatory=$false)] + [string]$Thumbprint + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + if($CertificateFile){ $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -CertificateFile $CertificateFile -Insecure:$Insecure)} + elseif($Thumbprint){ $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -Thumbprint $Thumbprint -Insecure:$Insecure)} + else + { + if (-not $Password) {$Password = (Read-Host "Password" -AsSecureString) } + $local:HttpSession = (Connect-Sps -SessionMaster $Appliance -SessionUsername $Username -SessionPassword $Password -Insecure:$Insecure -LocalLogin:$LocalLogin) + } + + + Set-Variable -Name "SafeguardSpsSession" -Scope Global -Value @{ + "Appliance" = $Appliance; + "Insecure" = $Insecure; + "Session" = $local:HttpSession + } + Write-Host "Login Successful." +} + +<# +.SYNOPSIS +Log out of a Safeguard SPS appliance when finished using the SPS Web API. + +.DESCRIPTION +This utility will remove the session variable +that was created by the Connect-SafeguardSps cmdlet. + +.INPUTS +None. + +.OUTPUTS +None. + +.EXAMPLE +Disconnect-SafeguardSps + +Log out Successful. + +#> +function Disconnect-SafeguardSps +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + if (-not $SafeguardSpsSession) + { + Write-Host "Not logged in." + } + else + { + Write-Host "Session variable removed." + Set-Variable -Name "SafeguardSpsSession" -Scope Global -Value $null + } +} + +<# +.SYNOPSIS +Call a method in the Safeguard SPS Web API. + +.DESCRIPTION +This utility is useful for calling the Safeguard SPS Web API for testing or +scripting purposes. It provides a couple benefits over using curl.exe or +Invoke-RestMethod by generating or reusing a secure session and composing +the Url, headers, parameters, and body for the request. + +This script is meant to be used with the Connect-SafeguardSps cmdlet which +will generate and store a variable in the session so that it doesn't need +to be passed to each call to the API. Call Disconnect-SafeguardSps when +finished. + +Safeguard SPS Web API is implemented as HATEOAS. To get started crawling +through the API, call Show-SafeguardSpsEndpoint. Then, you can follow to +the different API areas, such as configuration or health-status. + +.PARAMETER Appliance +IP address or hostname of a Safeguard appliance. + +.PARAMETER Method +HTTP method verb you would like to use: GET, PUT, POST, DELETE. + +.PARAMETER RelativeUrl +Relative portion of the Url you would like to call starting after /api. + +.PARAMETER Accept +Specify the Accept header (default: application/json), Use text/csv to request CSV output. + +.PARAMETER ContentType +Specify the Content-type header (default: application/json). + +.PARAMETER Body +A hash table containing an object to PUT or POST to the Url. + +.PARAMETER JsonBody +A pre-formatted JSON string to PUT or Post to the URl. If -Body is also specified, this is ignored. +It can sometimes be difficult to get arrays of objects to behave properly with hashtables in Powershell. + +.PARAMETER Parameters +A hash table containing the HTTP query parameters to add to the Url. + +.PARAMETER JsonOutput +A switch to return data as pretty JSON string. + +.PARAMETER BodyOutput +A switch to just return the body as a PowerShell object. + +.INPUTS +None. + +.OUTPUTS +JSON response from Safeguard Web API. + +.EXAMPLE +Invoke-SafeguardSpsMethod GET starling/join + +.EXAMPLE +Invoke-SafeguardSpsMethod GET / -JsonOutput + +.EXAMPLE +Open-SafeguardSpsTransaction +$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) +$body.admin_address = "admin@mycompany.corp" +Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body +Close-SafeguardSpsTransaction +#> +function Invoke-SafeguardSpsMethod +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$Method, + [Parameter(Mandatory=$true,Position=1)] + [string]$RelativeUrl, + [Parameter(Mandatory=$false)] + [string]$Accept = "application/json", + [Parameter(Mandatory=$false)] + [string]$ContentType = "application/json", + [Parameter(Mandatory=$false)] + [object]$Body, + [Parameter(Mandatory=$false)] + [string]$JsonBody, + [Parameter(Mandatory=$false)] + [HashTable]$Parameters, + [Parameter(Mandatory=$false)] + [HashTable]$ExtraHeaders, + [Parameter(Mandatory=$false)] + [switch]$JsonOutput, + [Parameter(Mandatory=$false)] + [switch]$BodyOutput, + [Parameter(Mandatory=$false)] + [string]$InFile + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + if (-not $SafeguardSpsSession) + { + throw "This cmdlet requires that you log in with the Connect-SafeguardSps cmdlet" + } + + $local:Insecure = $SafeguardSpsSession.Insecure + Write-Verbose "Insecure=$($local:Insecure)" + Import-Module -Name "$PSScriptRoot\sslhandling.psm1" -Scope Local + Edit-SslVersionSupport + if ($local:Insecure) + { + Disable-SslVerification + if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } + } + + $local:Headers = @{ + "Accept" = $Accept; + "Content-type" = $ContentType; + } + + foreach ($key in $ExtraHeaders.Keys) + { + $local:Headers[$key] = $ExtraHeaders[$key] + } + + Write-Verbose "---Request---" + Write-Verbose "Headers=$(ConvertTo-Json -InputObject $local:Headers)" + + try + { + $arguments = @{ + Method = $Method; + RelativeUrl = $RelativeUrl; + Headers = $local:Headers; + Body = $Body; + JsonBody = $JsonBody; + Parameters = $Parameters; + InFile = $InFile; + } + if ($JsonOutput) + { + (Invoke-SpsInternal @arguments) | ConvertTo-Json -Depth 100 + } + elseif ($BodyOutput) + { + $local:Response = (Invoke-SpsInternal @arguments) + if ($local:Response.body) + { + $local:Response.body + } + else + { + Write-Verbose "No body returned in response" + } + } + else + { + Invoke-SpsInternal @arguments + } + } + finally + { + if ($local:Insecure) + { + Enable-SslVerification + if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } + } + } +} + +<# +.SYNOPSIS +Open a transaction for making changes via the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet is used to create a transaction necessary to make changes via +the Safeguard SPS API. Recent versions of SPS will open a transaction +automatically, but this cmdlet may be used to open a transaction explicitly. + +In order to permanently save changes made via the Safeguard SPS API, you +must also call Close-SafeguardSpsTransaction or its alias +Save-SafeguardSpsTransaction. Clear-SafeguardSpsTransaction can be used to +cancel changes. + +.INPUTS +None. + +.OUTPUTS +JSON response from Safeguard Web API. + +.EXAMPLE +Open-SafeguardSpsTransaction +$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) +$body.admin_address = "admin@mycompany.corp" +Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body +Close-SafeguardSpsTransaction +#> +function Open-SafeguardSpsTransaction +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Invoke-SafeguardSpsMethod POST transaction +} + +<# +.SYNOPSIS +Close a transaction and save changes made via the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet is used to end a transaction and permanently save the changes +made via the Safeguard SPS API. This cmdlet is meant to be used with +Open-SafeguardSpsTransaction. Save-SafeguardSpsTransaction is an alias +for this cmdlet. Clear-SafeguardSpsTransaction can be used to cancel changes. + +To see the status of a transaction, use Get-SafeguardSpsTransaction. To +see only the changes that are about to be made via a transaction, use +Show-SafeguardSpsTransactionChange. + +.INPUTS +None. + +.OUTPUTS +JSON response from Safeguard Web API. + +.EXAMPLE +Open-SafeguardSpsTransaction +$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) +$body.admin_address = "admin@mycompany.corp" +Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body +Close-SafeguardSpsTransaction +#> +function Close-SafeguardSpsTransaction +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Invoke-SafeguardSpsMethod PUT transaction -Body @{ status = "commit" } +} +New-Alias -Name Save-SafeguardSpsTransaction -Value Close-SafeguardSpsTransaction + +<# +.SYNOPSIS +Get the status of a transaction using the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet will report the status of an SPS transaction. The status 'closed' +means no transaction is pending. The status 'open' means the transaction is +pending. Close-SafeguardSpsTransaction can be used to permanently save changes. +Clear-SafeguardSpsTransaction can be used to cancel changes. The remaining +seconds is the time before the transaction will cancel automatically and the +login session will be terminated. + +.INPUTS +None. + +.OUTPUTS +JSON response from Safeguard Web API. + +.EXAMPLE +Open-SafeguardSpsTransaction +$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) +$body.admin_address = "admin@mycompany.corp" +Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body +Get-SafeguardSpsTransaction +Clear-SafeguardSpsTransaction +#> +function Get-SafeguardSpsTransaction +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:response = (Invoke-SafeguardSpsMethod GET transaction) + $local:TransactionInfo = [ordered]@{ + Status = $local:response.body.status; + CommitMessage = $local:response.body.commit_message; + RemainingSeconds = $local:response.meta.remaining_seconds; + Changes = @() + } + if ($local:response.meta.changes) + { + $local:Changes = (Invoke-SafeguardSpsMethod GET transaction/changes).changes + if ($local:Changes) { $local:TransactionInfo.Changes = $local:Changes } + } + New-Object PSObject -Property $local:TransactionInfo +} + +<# +.SYNOPSIS +Show the pending changes in a transaction using the Safeguard SPS Web API. + +.DESCRIPTION +Transactions are required to make changes via the Safeguard SPS Web API. The +transaction must be closed or saved before changes become permanent. This cmdlet +will show what values will be permanently changed if the transaction is closed. + +.INPUTS +None. + +.OUTPUTS +JSON response from Safeguard Web API. + +.EXAMPLE +Open-SafeguardSpsTransaction +$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) +$body.admin_address = "admin@mycompany.corp" +Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body +Show-SafeguardSpsTransactionChange +#> +function Show-SafeguardSpsTransactionChange +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + (Get-SafeguardSpsTransaction).Changes | ConvertTo-Json -Depth 100 +} + +<# +.SYNOPSIS +Cancel a transaction using the Safeguard SPS Web API. + +.DESCRIPTION +Transactions are required to make changes via the Safeguard SPS Web API. The +transaction must be closed or saved before changes become permanent. This cmdlet +may be used to cancel pending changes. + +.INPUTS +None. + +.OUTPUTS +JSON response from Safeguard Web API. + +.EXAMPLE +Open-SafeguardSpsTransaction +$body = (Invoke-SafeguardSpsMethod GET configuration/management/email -BodyOutput) +$body.admin_address = "admin@mycompany.corp" +Invoke-SafeguardSpsMethod PUT configuration/management/email -Body $body +Get-SafeguardSpsTransaction +Clear-SafeguardSpsTransaction +#> +function Clear-SafeguardSpsTransaction +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Invoke-SafeguardSpsMethod DELETE transaction +} + +<# +.SYNOPSIS +Call a method in the Safeguard SPS Web API. + +.DESCRIPTION +Safeguard SPS Web API is implemented as HATEOAS. This cmdlet is helpful for +crawling through the API. You can explore the different API areas, such as +configuration or health-status. + +.PARAMETER RelativeUrl +Relative portion of the Url you would like to call starting after /api. + +.EXAMPLE +Show-SafeguardSpsEndpoint configuration + +.EXAMPLE +Show-SafeguardSpsEndpoint configuration/ssh/connections +#> +function Show-SafeguardSpsEndpoint +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false,Position=0)] + [string]$RelativeUrl + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + if (-not $RelativeUrl) { $RelativeUrl = "/" } + + $local:Response = (Invoke-SafeguardSpsMethod GET $RelativeUrl) + if ($local:Response.items) + { + $local:Response.items | Select-Object key,meta + } + else + { + $local:Response.meta.href + } +} + +<# +.SYNOPSIS +Gather join information from Safeguard SPS and open a browser to Starling to +complete the join via the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet with call the Safeguard SPS API to determine the join status, and +if not joined, it will gather the information necessary to start the join +process using the system browser. The join process requires copying and pasting +credentials and token endpoint back from the browser to complete the join. +Credentials will not be echoed to the screen. + +.PARAMETER Environment +Which Starling environment to join (default: prod) + +.EXAMPLE +Invoke-SafeguardSpsStarlingJoinBrowser +#> +function Invoke-SafeguardSpsStarlingJoinBrowser +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false,Position=0)] + [ValidateSet("dev", "devtest", "stage", "prod", IgnoreCase=$true)] + [string]$Environment = "prod" + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:Info = (Invoke-SafeguardSpsMethod GET configuration/starling).body + if ($local:Info.join_info) + { + Write-Host -ForegroundColor Yellow "Safeguard SPS is already joined to Starling" + $local:Info.join_info + Write-Host -ForegroundColor Yellow "You must unjoin before you can rejoin Starling" + } + else + { + $local:JoinBody = (Invoke-SafeguardSpsMethod GET starling/join).body + $local:InstanceName = $local:JoinBody.product_instance + $local:TimsLicense = $local:JoinBody.product_tims + switch ($Environment) + { + "dev" { $local:Suffix = "-dev"; $Environment = "dev"; break } + "devtest" { $local:Suffix = "-devtest"; $Environment = "devtest"; break } + "stage" { $local:Suffix = "-stage"; $Environment = "stage"; break } + "prod" { $local:Suffix = ""; $Environment = "prod"; break } + } + $local:JoinUrl = "https://account$($local:Suffix).cloud.oneidentity.com/join/Safeguard/$($local:InstanceName)/$($local:TimsLicense)" + + Import-Module -Name "$PSScriptRoot\ps-utilities.psm1" -Scope Local + + Write-Host -ForegroundColor Yellow "This command will use an external browser to join Safeguard SPS ($($local:InstanceName)) to Starling ($Environment)." + Write-host "You will be required to copy and paste interactively from the browser to answer prompts for join information." + $local:Confirmed = (Get-Confirmation "Join to Starling" "Are you sure you want to use an external browser to join to Starling?" ` + "Show the browser." "Cancels this operation.") + + if ($local:Confirmed) + { + Start-Process $local:JoinUrl + + Write-Host "Following the successful join in the browser, provide the following:" + $local:Creds = (Read-Host "Credential String" -MaskInput) + $local:Endpoint = (Read-Host "Token Endpoint") + $local:Body = [ordered]@{ + environment = $Environment; + token_endpoint = $local:Endpoint; + credential_string = $local:Creds; + } + $local:JoinBody | Add-Member -NotePropertyMembers $local:Body -TypeName PSCustomObject + + Invoke-SafeguardSpsMethod POST "starling/join" -Body $local:JoinBody + + Write-Host -ForegroundColor Yellow "You may close the external browser." + } + } +} + +<# +.SYNOPSIS +Remove the Starling join via the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet with call the Safeguard SPS API to remove a Starling join. You +cannot unjoin if SRA is enabled. + +.EXAMPLE +Remove-SafeguardSpsStarlingJoin +#> +function Remove-SafeguardSpsStarlingJoin +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Invoke-SafeguardSpsMethod DELETE starling/join +} + +<# +.SYNOPSIS +Enable Safeguard Remote Access in Starling via the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet will enable Safeguard Remote Access in Starling if this Safeguard SPS +is joined to Starling. + +.EXAMPLE +Enable-SafeguardSpsStarlingJoin +#> +function Enable-SafeguardSpsRemoteAccess +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:Info = (Invoke-SafeguardSpsMethod GET configuration/starling).Body + if ($local:Info.remote_access.enabled) + { + Write-Warning "Safeguard Remote Access is already enabled" + } + else + { + $local:Info.remote_access.enabled = $true + Open-SafeguardSpsTransaction + Invoke-SafeguardSpsMethod PUT configuration/starling -Body $local:Info + Save-SafeguardSpsTransaction + } +} +New-Alias -Name Enable-SafeguardSpsSra -Value Enable-SafeguardSpsRemoteAccess + +<# +.SYNOPSIS +Disable Safeguard Remote Access in Starling via the Safeguard SPS Web API. + +.DESCRIPTION +This cmdlet will disable Safeguard Remote Access in Starling if this Safeguard SPS +is joined to Starling. + +.EXAMPLE +Disable-SafeguardSpsRemoteAccess +#> +function Disable-SafeguardSpsRemoteAccess +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $local:Info = (Invoke-SafeguardSpsMethod GET configuration/starling).Body + if ($local:Info.remote_access.enabled) + { + $local:Info.remote_access.enabled = $false + Open-SafeguardSpsTransaction + Invoke-SafeguardSpsMethod PUT configuration/starling -Body $local:Info + Save-SafeguardSpsTransaction + } + else + { + Write-Warning "Safeguard Remote Access is already disabled" + } +} +New-Alias -Name Disable-SafeguardSpsSra -Value Disable-SafeguardSpsRemoteAccess + +<# +Get Safeguard SPS appliance information via the Web API. + +.DESCRIPTION +This cmdlet will display basic information about Safeguard SPS. + +.EXAMPLE +Get-SafeguardSpsInfo +#> +function Get-SafeguardSpsInfo +{ + [CmdletBinding()] + Param( + [parameter(Mandatory, Position = 0)] + [string] + $FilePath + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + (Invoke-SafeguardSpsMethod GET info).body +} + +<# +.SYNOPSIS +Uploads a new firmware to SPS. + +.DESCRIPTION +This command takes a path to an SPS firmware and uploads it to an open firmware slot. + +.EXAMPLE +Import-SafeguardSpsFirmware -FilePath +#> +function Import-SafeguardSpsFirmware +{ + [CmdletBinding()] + Param( + [parameter(Mandatory, Position = 0)] + [string] + $FilePath + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Invoke-SafeguardSpsMethod POST upload/firmware -InFile $FilePath -ContentType 'application/x-iso9660-image' + +} + +<# +.SYNOPSIS +Get Safeguard SPS appliance version via the Web API. + +.DESCRIPTION +This cmdlet will display the version of Safeguard SPS. + +.EXAMPLE +Get-SafeguardSpsVersion + +.EXAMPLE +Get-SafeguardSpsVersion -AltSyntax +#> +function Get-SafeguardSpsVersion +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false)] + [switch]$AltSyntax + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + if ($AltSyntax) + { + (Get-SafeguardSpsInfo).version + } + else + { + (Get-SafeguardSpsInfo).firmware_version + } +} + +<# +.SYNOPSIS +Returns the SPS firmware slot information. + +.DESCRIPTION +Returns the SPS firmware slot information. + +.EXAMPLE +Get-SafeguardSpsFirmwareSlot +#> +function Get-SafeguardSpsFirmwareSlot +{ + [CmdletBinding()] + Param( + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + Invoke-SafeguardSpsMethod GET firmware/slots +} + +<# +.SYNOPSIS +Tests a firmware slot. + +.DESCRIPTION +This command tests that the firmware slot contains valid firmware that can be installed and returns a boolean result. + +.EXAMPLE +Test-SafeguardSpsFirmware -Slot 3 +#> +function Test-SafeguardSpsFirmware +{ + [CmdletBinding()] + Param( + [parameter(Mandatory)] + [int]$Slot + ) + + $Body = @{ + slot_id = $Slot + } + + $summary = (Invoke-SafeguardSpsMethod POST firmware/test -Body $Body).body.test_summary + Write-Verbose $summary + return $summary.StartsWith("Upgrade is allowed;") +} + +<# +.SYNOPSIS +Starts a firmware upgrade. + +.DESCRIPTION +This command upgrades SPS with the firmware installed into the indicated slot. + +.EXAMPLE +Install-SafeguardSpsFirmware -Slot 3 -Message "Upgrading SPS firmware..." +#> +function Install-SafeguardSpsFirmware +{ + [CmdletBinding()] + Param( + [parameter(Mandatory)] + [int]$Slot, + [parameter(Mandatory)] + [string]$Message + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + if(-not $Message) + { + $Message = "Upgrading SPS firmware..." + } + $Body = @{ + slot_id = $Slot + message = $Message + } + + Invoke-SafeguardSpsMethod POST firmware/upgrade -Body $Body +} + +<# +.SYNOPSIS +Install-SafeguardSpsUpgrade + +.DESCRIPTION +This command automates the steps for uploading and installing an SPS firmware upgrade. + +.EXAMPLE +Install-SafeguardSpsPatch -FilePath +#> +function Install-SafeguardSpsUpgrade +{ + [CmdletBinding()] + Param( + [parameter(Mandatory, Position = 0)] + [string] + $FilePath, + [parameter(Mandatory, Position = 1)] + [string] + $TargetVersion + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $activity = "Installing SPS upgrade" + Write-Progress -Activity $activity -Status 'Importing firmware' -PercentComplete 15 + Import-SafeguardSpsFirmware $FilePath + $slots = (Get-SafeguardSpsFirmwareSlot).items.body + for($i = 0; $i -lt $slots.count; $i++) + { + if($slots[$i].version -ieq $TargetVersion) + { + Write-Progress -Activity $activity -Status "Testing firmware in slot $i" -PercentComplete 65 + if( Test-SafeguardSpsFirmware -Slot $i ) + { + Write-Progress -Activity $activity -Status "Installing $TargetVersion from slot $i" -PercentComplete 75 + Install-SafeguardSpsFirmware -Slot $i -Message "Upgrading SPS firmware to $TargetVersion" + Write-Progress -Activity $activity -Status "Finished" -PercentComplete 100 + Start-Sleep 1 + return + } + else + { + throw "Firmware at slot $i failed upgrade test. For details run: Test-SafeguardSpsFirmware -Slot $i" + } + } + } + throw "Firmware with version $TargetVersion could not be found in any firmware slot." +} From c98636ca7d945f88fd003eaa0319f55cabdd4abc Mon Sep 17 00:00:00 2001 From: evetovicsm <5862838+evetovicsm@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:47:29 +0200 Subject: [PATCH 05/10] Update sessionapi.psm1 Added back the function Get-SafeguardSpsSupportBundle which was accidentaly removed --- src/sessionapi.psm1 | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index ac0fa4e..2e30fdc 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -1411,3 +1411,64 @@ function Install-SafeguardSpsUpgrade } throw "Firmware with version $TargetVersion could not be found in any firmware slot." } + +<# +.SYNOPSIS +Get-SafeguardSpsSupportBundle + +.DESCRIPTION +This command downloads an SPS support bundle. + +.PARAMETER OutFile +The output file name. If this is omitted, a unique name will be generated. + +.EXAMPLE +Get-SafeguardSpsSupportBundle +#> +function Get-SafeguardSpsSupportBundle +{ + [CmdletBinding()] + Param( + [parameter(Mandatory = $false, Position = 0)] + [string] $OutFile + ) + + if (-not $PSBoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" } + if (-not $PSBoundParameters.ContainsKey("Verbose")) { $VerbosePreference = $PSCmdlet.GetVariableValue("VerbosePreference") } + + $pct = 5 + $activity = 'Get SPS Support Bundle' + Write-Progress -Activity $activity -Status 'Generating support bundle' -PercentComplete $pct + $response = Invoke-SafeguardSpsMethod POST troubleshooting/support-bundle + $jobId = $response.key + + $maxTime = (Get-Date).AddMinutes(10) + $pct += 15 + while((Get-Date) -lt $maxTime) { + $status = Invoke-SafeguardSpsMethod GET "troubleshooting/support-bundle/$($jobId)" + if($status.body.status -ieq "finished") { + break; + } + start-sleep -Seconds 10 + $pct += 1 + Write-Progress -Activity $activity -Status 'Waiting for support bundle generation to complete' -PercentComplete $pct + } + + if ((Get-Date) -gt $maxTime) { + throw "Timed out waiting for support bundle generation." + } + + $pct = 80 + Write-Progress -Activity $activity -Status 'Downloading support bundle' -PercentComplete $pct + if(-not $OutFile) { + $OutFile = "sps-$($safeguardspssession.Appliance)-$(get-date -f yyyy-MM-dd-HH-mm-ss).tar.gz" + } + + Invoke-SafeguardSpsMethod GET "troubleshooting/support-bundle/$($jobId)/download" -OutFile $OutFile + Write-Progress -Activity $activity -Status 'Deleting support bundle from SPS' -PercentComplete 90 + + $null = Invoke-SafeguardSpsMethod DELETE "troubleshooting/support-bundle/$($jobId)" + Write-Progress -Activity $activity -Status 'Complete' -PercentComplete 100 + + Write-Host -ForegroundColor Green "Saved SPS support bundle to: $OutFile" +} From e265cb38f83be28dc99503f5d0ff45e7c77de5fd Mon Sep 17 00:00:00 2001 From: Jeff Harkavy Date: Wed, 6 Sep 2023 11:24:10 -0400 Subject: [PATCH 06/10] 7.4 release --- pipeline-templates/global-variables.yml | 2 +- src/safeguard-ps.psd1 | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pipeline-templates/global-variables.yml b/pipeline-templates/global-variables.yml index b60945b..351876b 100644 --- a/pipeline-templates/global-variables.yml +++ b/pipeline-templates/global-variables.yml @@ -2,6 +2,6 @@ variables: - name: version value: "7.4" - name: isPrerelease - value: ${{ true }} + value: ${{ false }} - name: shouldPublishDocker value: $[ eq( variables.isPrerelease, false ) ] diff --git a/src/safeguard-ps.psd1 b/src/safeguard-ps.psd1 index 8b51002..de6d12a 100644 --- a/src/safeguard-ps.psd1 +++ b/src/safeguard-ps.psd1 @@ -349,7 +349,13 @@ PrivateData = @{ ReleaseNotes = @" safeguard-ps Release Notes: -- bug fixes +- X-TokenLifetimeRemaining header may return a string array in newer versions of powershell. ps New-Timespan just wants a string. +- fix string.split call to force the correct .NET overload +- Update Read.Me with -Browser notes for PKCE. +- Update safeguard-ps to use PKCE +- Add the new set a2a credential cmdlets to the public commands. +- Add cmdlets to set passwords and sshkeys through the A2A service +- Allow calling A2A endpoints without a body "@ } # End of PSData hashtable From 03056bd0092eb8d80d98bbb0984dda27c3dd82d1 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Tue, 2 Jan 2024 22:21:32 -0700 Subject: [PATCH 07/10] Mark this as obsolete for modern .NET --- src/sg-utilities.psm1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sg-utilities.psm1 b/src/sg-utilities.psm1 index 0e760e2..af3a015 100644 --- a/src/sg-utilities.psm1 +++ b/src/sg-utilities.psm1 @@ -43,6 +43,9 @@ namespace Ex } public SafeguardMethodException(string message, Exception innerException) : base(message, innerException) {} +#if !NETFRAMEWORK + [Obsolete(DiagnosticId = "SYSLIB0051")] +#endif protected SafeguardMethodException (SerializationInfo info, StreamingContext context) : base(info, context) {} From 83bc06d8e25e776b2314f718b4c3d30a19fcc775 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Mon, 8 Jan 2024 19:34:18 -0700 Subject: [PATCH 08/10] Better message and no diag id --- src/sg-utilities.psm1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sg-utilities.psm1 b/src/sg-utilities.psm1 index af3a015..e901cdf 100644 --- a/src/sg-utilities.psm1 +++ b/src/sg-utilities.psm1 @@ -43,9 +43,7 @@ namespace Ex } public SafeguardMethodException(string message, Exception innerException) : base(message, innerException) {} -#if !NETFRAMEWORK - [Obsolete(DiagnosticId = "SYSLIB0051")] -#endif + [Obsolete] protected SafeguardMethodException (SerializationInfo info, StreamingContext context) : base(info, context) {} @@ -170,7 +168,7 @@ namespace Ex )) } } - if ($local:ThrownException.Status -eq "TrustFailure") + if ($local:ThrownException.Status -eq "TrustFailure" -or $local:ThrownException.Message.StartsWith("The SSL connection could not be established")) { Write-Host -ForegroundColor Magenta "To ignore SSL/TLS trust failure use the -Insecure parameter to bypass server certificate validation." } From ec5075c776de14c2f19bff97a8d325c2697e5d33 Mon Sep 17 00:00:00 2001 From: petrsnd Date: Tue, 16 Jan 2024 15:20:54 -0700 Subject: [PATCH 09/10] Don't pass null to Invoke-RestMethod for OutFile/InFile --- src/safeguard-ps.psm1 | 62 +++++++++++++++++++++++++------------------ src/sessionapi.psm1 | 10 +++---- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/safeguard-ps.psm1 b/src/safeguard-ps.psm1 index d57c30b..ab87878 100644 --- a/src/safeguard-ps.psm1 +++ b/src/safeguard-ps.psm1 @@ -618,31 +618,31 @@ function Invoke-WithoutBody $local:Url = (New-SafeguardUrl $Appliance $Service $Version $RelativeUrl -Parameters $Parameters) Write-Verbose "Url=$($local:Url)" Write-Verbose "Parameters=$(ConvertTo-Json -InputObject $Parameters)" + $arguments = @{ + Method = $Method; + Headers = $Headers; + Uri = $local:Url; + TimeoutSec = $Timeout + } if ($InFile) { - if ($LongRunningTask) - { - $local:Response = (Invoke-WebRequest -Method $Method -Headers $Headers -Uri $local:Url ` - -InFile $InFile -OutFile $OutFile -TimeoutSec $Timeout) - Wait-LongRunningTask $local:Response $Headers $Timeout - } - else - { - Invoke-RestMethod -Method $Method -Headers $Headers -Uri $local:Url -InFile $InFile -OutFile $OutFile -TimeoutSec $Timeout - } + Write-Verbose "InFile=$InFile" + $arguments = $arguments + @{ InFile = $InFile } + } + if ($OutFile) + { + Write-Verbose "OutFile=$OutFile" + $arguments = $arguments + @{ OutFile = $OutFile } + } + + if ($LongRunningTask) + { + $local:Response = (Invoke-WebRequest @arguments) + Wait-LongRunningTask $local:Response $Headers $Timeout } else { - if ($LongRunningTask) - { - $local:Response = $(Invoke-RestMethod -Method $Method -Headers $Headers -Uri $local:Url ` - -InFile $InFile -OutFile $OutFile -TimeoutSec $Timeout) - Wait-LongRunningTask $local:Response $Headers $Timeout - } - else - { - Invoke-RestMethod -Method $Method -Headers $Headers -Uri $local:Url -OutFile $OutFile -TimeoutSec $Timeout - } + Invoke-RestMethod @arguments } } function Invoke-WithBody @@ -688,18 +688,28 @@ function Invoke-WithBody Write-Verbose "Parameters=$(ConvertTo-Json -InputObject $Parameters)" Write-Verbose "---Request Body---" Write-Verbose "$($local:BodyInternal)" + $arguments = @{ + Method = $Method; + Headers = $Headers; + Uri = $local:Url; + Body = ([System.Text.Encoding]::UTF8.GetBytes($local:BodyInternal)); + TimeoutSec = $Timeout + } + if ($OutFile) + { + Write-Verbose "OutFile=$OutFile" + $arguments = $arguments + @{ OutFile = $OutFile } + } + + if ($LongRunningTask) { - $local:Response = (Invoke-WebRequest -Method $Method -Headers $Headers -Uri $local:Url ` - -Body ([System.Text.Encoding]::UTF8.GetBytes($local:BodyInternal)) ` - -OutFile $OutFile -TimeoutSec $Timeout) + $local:Response = (Invoke-WebRequest @arguments) Wait-LongRunningTask $local:Response $Headers $Timeout } else { - Invoke-RestMethod -Method $Method -Headers $Headers -Uri $local:Url ` - -Body ([System.Text.Encoding]::UTF8.GetBytes($local:BodyInternal)) ` - -OutFile $OutFile -TimeoutSec $Timeout + Invoke-RestMethod @arguments } } diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index c7d7242..f85e12c 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -138,7 +138,7 @@ function Invoke-SpsWithoutBody Write-Verbose "InFile=$InFile" $arguments = $arguments + @{ InFile = $InFile } } - if($OutFile) + if ($OutFile) { Write-Verbose "OutFile=$OutFile" $arguments = $arguments + @{ OutFile = $OutFile } @@ -1427,7 +1427,7 @@ function Install-SafeguardSpsUpgrade Write-Verbose "Waiting for SPS to restart..." for($i = 0; $i -lt 20; $i++) { - try + try { $currentVersion = Get-SafeguardSpsVersion if($currentVersion -eq $TargetVersion) @@ -1442,7 +1442,7 @@ function Install-SafeguardSpsUpgrade } throw "Timed out waiting for SPS to reach version $TargetVersion" } - else + else { throw "Firmware at slot $i failed upgrade test. For details run: Test-SafeguardSpsFirmware -Slot $i" } @@ -1462,7 +1462,7 @@ This command downloads an SPS support bundle. The output file name. If this is omitted, a unique name will be generated. .EXAMPLE -Get-SafeguardSpsSupportBundle +Get-SafeguardSpsSupportBundle #> function Get-SafeguardSpsSupportBundle { @@ -1508,7 +1508,7 @@ function Get-SafeguardSpsSupportBundle $null = Invoke-SafeguardSpsMethod DELETE "troubleshooting/support-bundle/$($jobId)" Write-Progress -Activity $activity -Status 'Complete' -PercentComplete 100 - + Write-Host -ForegroundColor Green "Saved SPS support bundle to: $OutFile" } From e6aa3b47d7742a61a4e92911f0080134a69e38af Mon Sep 17 00:00:00 2001 From: evetovicsm <5862838+evetovicsm@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:53:08 +0100 Subject: [PATCH 10/10] Removed debug line write-host --- src/sessionapi.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sessionapi.psm1 b/src/sessionapi.psm1 index 2e30fdc..cba6ae0 100644 --- a/src/sessionapi.psm1 +++ b/src/sessionapi.psm1 @@ -30,7 +30,7 @@ function Connect-Sps Disable-SslVerification if ($global:PSDefaultParameterValues) { $PSDefaultParameterValues = $global:PSDefaultParameterValues.Clone() } } - write-host $Thumbrint + try {