Public/Start-LMSessionSyncServer.ps1
<# .SYNOPSIS This function starts a session synchronization server for Logic Monitor. .DESCRIPTION The Start-LMSessionSyncServer function starts a Pode server that is used to synchronize sessions for Logic Monitor. It uses a secret vault to store session details. If the vault does not exist, it creates one. The function also provides options to enable request logging and error logging. .PARAMETER EnableRequestLogging A switch to control whether request logging is enabled. .PARAMETER EnableErrorLogging A switch to control whether error logging is enabled. .EXAMPLE Start-LMSessionSyncServer -EnableRequestLogging -EnableErrorLogging This command starts the session synchronization server with request logging and error logging enabled. .INPUTS None. You cannot pipe objects to Start-LMSessionSyncServer. .OUTPUTS The function does not return any output. It writes messages to the host to indicate the status of the server and the secret vault. .NOTES The function throws an error if it fails to unlock the secret vault with the provided credentials. #> Function Start-LMSessionSyncServer { Param( [Switch]$EnableRequestLogging, [Switch]$EnableErrorLogging ) Begin { #Ensure we have a vault to use for storing session details $VaultName = "Logic.Monitor" Try { Get-SecretVault -Name $VaultName -ErrorAction Stop | Out-Null Write-Host "Existing vault $VaultName already exists, skipping creation" -ForegroundColor Yellow } Catch { If($_.Exception.Message -like "*Vault $VaultName does not exist in registry*") { Write-Host "Credential vault for cached accounts does not currently exist, creating credential vault: $VaultName" -ForegroundColor Yellow Register-SecretVault -Name $VaultName -ModuleName Microsoft.PowerShell.SecretStore Get-SecretStoreConfiguration | Out-Null } } } Process{ #Assuming we got here we can start our session server Start-PodeServer { #Ensure we have a vault to use for storing session details $VaultName = "Logic.Monitor" $VaultKeyPrefix = "LMSessionSync" #Capture creds so we can use them Try{ Unlock-SecretVault -Name $VaultName -Password $(Read-Host "Enter vault credentials" -AsSecureString -OutVariable VaultCred) -ErrorAction Stop Set-PodeState -Name 'VaultUnlock' -Value $VaultCred | Out-Null } Catch { Write-Error "Unable to start SessionSync server without valid vault unlock credentials: $_" Return } #Rotate APIKey in vault $ApiKey = (1..64| ForEach-Object {[byte](Get-Random -Max 256)} | ForEach-Object ToString X2) -join '' Set-Secret -Name $VaultKeyPrefix-RESTAPIKey -Vault $VaultName -Secret $ApiKey -Metadata @{Modified="$(Get-Date)";Portal="SessionSync-ApiKey"} #Sete our web server state Set-PodeState -Name 'VaultName' -Value $VaultName | Out-Null Set-PodeState -Name 'VaultKeyPrefix' -Value $VaultKeyPrefix | Out-Null Set-PodeState -Name 'VaultApiKey' -Value $ApiKey | Out-Null Add-PodeEndpoint -Address 127.0.0.1 -Port 8072 -Protocol Http If($EnableRequestLogging){New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging} If($EnableErrorLogging){New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging} # setup apiKey authentication to validate a user New-PodeAuthScheme -ApiKey | Add-PodeAuth -Name 'Auth' -Sessionless -ScriptBlock { param($key) #Grab current key $ApiKey = Get-PodeState -Name 'VaultApiKey' #Check if user is authenticated if ($key.toString() -eq $ApiKey.toString()) { return @{ User = @{'ID' ='1'} } } # authentication failed return $null } # check the request on this route against the authentication Add-PodeRoute -Method Get -Path '/api/v1/portal/:AccountName' -Authentication 'Auth' -ScriptBlock { #Store Session Info in Secret Vault $VaultName = Get-PodeState -Name 'VaultName' $VaultKeyPrefix = Get-PodeState -Name 'VaultKeyPrefix' $VaultUnlock = Get-PodeState -Name 'VaultUnlock' Unlock-SecretVault -Name $VaultName -Password $VaultUnlock #Get Session details in vault, return response data $AccountName = $WebEvent.Parameters['AccountName'] Try{ $SecretData = Get-Secret -Name $VaultKeyPrefix-$AccountName -Vault $VaultName -AsPlainText -ErrorAction Stop Write-PodeJsonResponse -Value $SecretData } Catch{ Write-PodeTextResponse -Value "Unexpected error: $($_.Exception.Message)" -StatusCode 500 #Set-PodeResponseStatus -Code 500 -Exception "Unexpected error: $($_.Exception.Message)" -NoErrorPage } } # this route will not be validated against the authentication Add-PodeRoute -Method Post -Path '/api/v1/portal/:AccountName' -ScriptBlock { #Store Session Info in Secret Vault $VaultName = Get-PodeState -Name 'VaultName' $VaultKeyPrefix = Get-PodeState -Name 'VaultKeyPrefix' $VaultUnlock = Get-PodeState -Name 'VaultUnlock' #Convert request data into JSON and unlock vault $SecretData = $($WebEvent.Data | ConvertTo-Json) Unlock-SecretVault -Name $VaultName -Password $VaultUnlock #Add/Update Session details in vault, return response data $AccountName = $WebEvent.Parameters['AccountName'] Try{ Set-Secret -Name $VaultKeyPrefix-$AccountName -Vault $VaultName -Secret $SecretData -Metadata @{Modified="$(Get-Date)";Type="SessionSync";Portal=$AccountName} Write-PodeJsonResponse -Value $SecretData } Catch{ Write-PodeTextResponse -Value "Unexpected error: $($_.Exception.Message)" -StatusCode 500 #Set-PodeResponseStatus -Code 500 -Exception "Unexpected error: $($_.Exception.Message)" -NoErrorPage } } Register-PodeEvent -Type Terminate -Name 'CleanupSessions' -ScriptBlock { $VaultName = Get-PodeState -Name 'VaultName' $VaultKeyPrefix = Get-PodeState -Name 'VaultKeyPrefix' $VaultUnlock = Get-PodeState -Name 'VaultUnlock' Unlock-SecretVault -Name $VaultName -Password $VaultUnlock $Sessions = Get-SecretInfo -Vault $VaultName | Where-Object {$_.Name -like "*$VaultKeyPrefix*"} Foreach ($Session in $Sessions){ Try{ Remove-Secret -Vault $VaultName -Name $Session.Name -ErrorAction Stop Write-Host "Successfully cleared session details for $($Session.Metadata["Portal"])." -ForegroundColor Green } Catch{ Write-Error "Unable to clear session details for $($Session.Metadata["Portal"]): $_" } } Disconnect-LMAccount } } } End{} } |