Public/Authentication/Connect-UKG.ps1
|
function Connect-UKG { <# .SYNOPSIS Connects to the UKG HR Service Delivery API. .DESCRIPTION Authenticates with the UKG HR Service Delivery API using OAuth 2.0 client credentials and establishes a session for subsequent API calls. .PARAMETER ApplicationId The application ID provided by UKG. .PARAMETER ApplicationSecret The application secret provided by UKG (as SecureString). .PARAMETER ApplicationSecretPlainText The application secret as plain text (not recommended for production). .PARAMETER ClientId The client ID for the specific tenant/company. .PARAMETER Region The region for the API endpoint (EU, US, UKG_ATL, UKG_TOR). .PARAMETER Environment The environment (Production or Staging). .PARAMETER BaseUrl Custom base URL (overrides Region/Environment). .PARAMETER TokenUrl Custom token URL (overrides Region/Environment). .EXAMPLE $secret = Read-Host -AsSecureString -Prompt "Enter secret" Connect-UKG -ApplicationId "app123" -ApplicationSecret $secret -ClientId "client456" -Region EU .EXAMPLE Connect-UKG -ApplicationId "app123" -ApplicationSecretPlainText "secret789" -ClientId "client456" -Region US -Environment Staging .OUTPUTS PSCustomObject representing the session information (without sensitive data). #> [CmdletBinding(DefaultParameterSetName = 'SecureSecret')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ApplicationId, [Parameter(Mandatory, ParameterSetName = 'SecureSecret')] [System.Security.SecureString]$ApplicationSecret, [Parameter(Mandatory, ParameterSetName = 'PlainTextSecret')] [ValidateNotNullOrEmpty()] [string]$ApplicationSecretPlainText, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ClientId, [Parameter(ParameterSetName = 'SecureSecret')] [Parameter(ParameterSetName = 'PlainTextSecret')] [ValidateSet('EU', 'US', 'UKG_ATL', 'UKG_TOR')] [string]$Region = 'EU', [Parameter(ParameterSetName = 'SecureSecret')] [Parameter(ParameterSetName = 'PlainTextSecret')] [ValidateSet('Production', 'Staging')] [string]$Environment = 'Production', [Parameter()] [string]$BaseUrl, [Parameter()] [string]$TokenUrl ) # Convert plain text secret to SecureString if provided $secureSecret = if ($PSCmdlet.ParameterSetName -eq 'PlainTextSecret') { $ss = New-Object System.Security.SecureString foreach ($char in $ApplicationSecretPlainText.ToCharArray()) { $ss.AppendChar($char) } $ss.MakeReadOnly() $ss } else { $ApplicationSecret } # Determine URLs $urlKey = "${Region}_${Environment}" $actualBaseUrl = if ($BaseUrl) { $BaseUrl.TrimEnd('/') } else { if (-not $Script:UKGBaseUrls.ContainsKey($urlKey)) { throw "Invalid region/environment combination: $urlKey. Valid combinations: $($Script:UKGBaseUrls.Keys -join ', ')" } $Script:UKGBaseUrls[$urlKey] } $actualTokenUrl = if ($TokenUrl) { $TokenUrl } else { if (-not $Script:UKGTokenUrls.ContainsKey($urlKey)) { throw "Invalid region/environment combination: $urlKey" } $Script:UKGTokenUrls[$urlKey] } Write-Verbose "Connecting to UKG API at: $actualBaseUrl" Write-Verbose "Token URL: $actualTokenUrl" # Convert SecureString to plain text for the request if ($Script:PSVersionMajor -ge 7) { $plainSecret = ConvertFrom-SecureString -SecureString $secureSecret -AsPlainText } else { $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureSecret) try { $plainSecret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } } # Request token $body = @{ grant_type = 'client_credentials' client_id = $ClientId client_secret = "${ApplicationId}:${plainSecret}" } $requestParams = @{ Uri = $actualTokenUrl Method = 'POST' Body = $body ContentType = 'application/x-www-form-urlencoded' UseBasicParsing = $true ErrorAction = 'Stop' } try { $response = Invoke-RestMethod @requestParams # Store session information $Script:UKGSession = [PSCustomObject]@{ PSTypeName = 'UKG.Session' ApplicationId = $ApplicationId ApplicationSecret = $secureSecret ClientId = $ClientId Region = $Region Environment = $Environment BaseUrl = $actualBaseUrl TokenUrl = $actualTokenUrl AccessToken = $response.access_token TokenType = $response.token_type TokenExpiry = (Get-Date).AddSeconds($response.expires_in) ConnectedAt = Get-Date } Write-Verbose "Successfully connected to UKG API" Write-Verbose "Token expires at: $($Script:UKGSession.TokenExpiry)" # Return session info (without sensitive data) return [PSCustomObject]@{ PSTypeName = 'UKG.SessionInfo' ClientId = $ClientId Region = $Region Environment = $Environment BaseUrl = $actualBaseUrl TokenExpiry = $Script:UKGSession.TokenExpiry ConnectedAt = $Script:UKGSession.ConnectedAt } } catch { $errorMessage = "Failed to connect to UKG API: " if ($_.Exception.Response) { try { $reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream()) $errorBody = $reader.ReadToEnd() $reader.Close() try { $errorJson = $errorBody | ConvertFrom-Json if ($errorJson.error_description) { $errorMessage += $errorJson.error_description } elseif ($errorJson.error) { $errorMessage += $errorJson.error } else { $errorMessage += $errorBody } } catch { $errorMessage += $errorBody } } catch { $errorMessage += $_.Exception.Message } } else { $errorMessage += $_.Exception.Message } $errorRecord = ConvertTo-UKGError -Response @{ code = 'authentication_failed'; message = $errorMessage } -StatusCode 401 $PSCmdlet.ThrowTerminatingError($errorRecord) } } function Disconnect-UKG { <# .SYNOPSIS Disconnects from the UKG HR Service Delivery API. .DESCRIPTION Clears the current session and removes stored credentials from memory. .EXAMPLE Disconnect-UKG #> [CmdletBinding()] param() if ($null -ne $Script:UKGSession) { # Clear sensitive data $Script:UKGSession = $null Write-Verbose "Disconnected from UKG API" } else { Write-Verbose "No active session to disconnect" } } function Get-UKGSession { <# .SYNOPSIS Gets information about the current UKG API session. .DESCRIPTION Returns details about the current connection including region, environment, and token expiry time. .EXAMPLE Get-UKGSession .OUTPUTS PSCustomObject with session information (without sensitive data). #> [CmdletBinding()] [OutputType([PSCustomObject])] param() if ($null -eq $Script:UKGSession) { Write-Warning "Not connected to UKG API. Use Connect-UKG to establish a connection." return $null } return [PSCustomObject]@{ PSTypeName = 'UKG.SessionInfo' ClientId = $Script:UKGSession.ClientId Region = $Script:UKGSession.Region Environment = $Script:UKGSession.Environment BaseUrl = $Script:UKGSession.BaseUrl TokenExpiry = $Script:UKGSession.TokenExpiry ConnectedAt = $Script:UKGSession.ConnectedAt IsTokenExpired = ($Script:UKGSession.TokenExpiry -lt (Get-Date)) TokenExpiresIn = if ($Script:UKGSession.TokenExpiry -gt (Get-Date)) { ($Script:UKGSession.TokenExpiry - (Get-Date)).ToString('hh\:mm\:ss') } else { 'Expired' } } } |