modules/ISC.SailPointSdk.psm1
|
#Requires -Version 5.1 Set-StrictMode -Version Latest $script:DefaultSailpointConfigPath = Join-Path (Join-Path $HOME '.sailpoint') 'config.yaml' $script:MicrosoftLicensingCsvUrl = 'https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv' function Get-SailpointConfigYamlPath { param([string]$Path) if ($Path) { return $Path } return $script:DefaultSailpointConfigPath } function ConvertFrom-SailpointSimpleYaml { <# .SYNOPSIS Minimal reader for ~/.sailpoint/config.yaml environment catalog (URLs only). #> param([Parameter(Mandatory)][string]$Content) $active = $null $environments = [ordered]@{} $currentEnv = $null $inEnvironments = $false foreach ($raw in ($Content -split "`r?`n")) { $line = $raw if ($line -match '^\s*#' -or [string]::IsNullOrWhiteSpace($line)) { continue } if ($line -match '^activeenvironment:\s*(.+)\s*$') { $active = $Matches[1].Trim().Trim('"').Trim("'") $inEnvironments = $false $currentEnv = $null continue } if ($line -match '^environments:\s*$') { $inEnvironments = $true $currentEnv = $null continue } if ($inEnvironments -and $line -match '^ {2,4}([^:\s][^:]*):\s*$') { $currentEnv = $Matches[1].Trim() if (-not $environments.Contains($currentEnv)) { $environments[$currentEnv] = [ordered]@{ Name = $currentEnv BaseUrl = $null TenantUrl = $null AuthType = $null } } continue } if ($inEnvironments -and $currentEnv -and $line -match '^ {4,8}([A-Za-z0-9_]+):\s*(.*)\s*$') { $key = $Matches[1].Trim().ToLowerInvariant() $value = $Matches[2].Trim().Trim('"').Trim("'") switch ($key) { 'baseurl' { $environments[$currentEnv].BaseUrl = $value } 'tenanturl' { $environments[$currentEnv].TenantUrl = $value } 'authtype' { $environments[$currentEnv].AuthType = $value } } continue } if ($line -match '^[A-Za-z]' -and $line -notmatch '^environments:') { $inEnvironments = $false $currentEnv = $null } } return [pscustomobject]@{ ActiveEnvironment = $active Environments = @($environments.Values) } } function Get-SailpointCliEnvironments { param([string]$ConfigPath) $path = Get-SailpointConfigYamlPath -Path $ConfigPath if (-not (Test-Path -LiteralPath $path)) { return [pscustomobject]@{ Path = $path ActiveEnvironment = $null Environments = @() Exists = $false } } $parsed = ConvertFrom-SailpointSimpleYaml -Content (Get-Content -LiteralPath $path -Raw -Encoding UTF8) return [pscustomobject]@{ Path = $path ActiveEnvironment = $parsed.ActiveEnvironment Environments = @($parsed.Environments) Exists = $true } } function Save-SailpointCliEnvironmentUrls { param( [Parameter(Mandatory)][string]$Name, [Parameter(Mandatory)][string]$BaseUrl, [Parameter(Mandatory)][string]$TenantUrl, [string]$ConfigPath, [switch]$SetActive ) $path = Get-SailpointConfigYamlPath -Path $ConfigPath $directory = Split-Path -Parent $path if ($directory -and -not (Test-Path -LiteralPath $directory)) { New-Item -ItemType Directory -Path $directory -Force | Out-Null } $catalog = Get-SailpointCliEnvironments -ConfigPath $path $envs = [System.Collections.Generic.List[object]]::new() foreach ($existing in @($catalog.Environments)) { if ($existing.Name -ne $Name) { $envs.Add($existing) } } $envs.Add([pscustomobject]@{ Name = $Name BaseUrl = $BaseUrl.TrimEnd('/') TenantUrl = $TenantUrl.TrimEnd('/') AuthType = 'pat' }) $active = if ($SetActive -or -not $catalog.ActiveEnvironment) { $Name } else { $catalog.ActiveEnvironment } $sb = [System.Text.StringBuilder]::new() [void]$sb.AppendLine("activeenvironment: $active") [void]$sb.AppendLine('authtype: pat') [void]$sb.AppendLine('environments:') foreach ($env in ($envs | Sort-Object Name)) { [void]$sb.AppendLine(" $($env.Name):") [void]$sb.AppendLine(" authtype: pat") [void]$sb.AppendLine(" baseurl: $($env.BaseUrl)") [void]$sb.AppendLine(" tenanturl: $($env.TenantUrl)") } Set-Content -LiteralPath $path -Value $sb.ToString() -Encoding UTF8 return $path } function Get-SailpointSdkConfigFromFile { param([Parameter(Mandatory)][string]$Path) if (-not (Test-Path -LiteralPath $Path)) { throw "config.json was not found at $Path" } $json = Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json $baseUrl = if ($json.BaseURL) { [string]$json.BaseURL } elseif ($json.BaseUrl) { [string]$json.BaseUrl } else { $null } $clientId = if ($json.ClientId) { [string]$json.ClientId } else { $null } $clientSecret = if ($json.ClientSecret) { [string]$json.ClientSecret } else { $null } if ([string]::IsNullOrWhiteSpace($baseUrl) -or [string]::IsNullOrWhiteSpace($clientId) -or [string]::IsNullOrWhiteSpace($clientSecret)) { throw "config.json at $Path must include BaseURL, ClientId, and ClientSecret." } return [pscustomobject]@{ Source = 'config.json' Path = $Path BaseUrl = $baseUrl.TrimEnd('/') ClientId = $clientId ClientSecret = $clientSecret } } function Get-SailpointSdkConfigFromEnvironment { if ($env:SAIL_BASE_URL -and $env:SAIL_CLIENT_ID -and $env:SAIL_CLIENT_SECRET) { return [pscustomobject]@{ Source = 'environment' Path = $null BaseUrl = $env:SAIL_BASE_URL.TrimEnd('/') ClientId = $env:SAIL_CLIENT_ID ClientSecret = $env:SAIL_CLIENT_SECRET } } return $null } function Set-SailpointProcessCredentials { param( [Parameter(Mandatory)][string]$BaseUrl, [Parameter(Mandatory)][string]$ClientId, [Parameter(Mandatory)][string]$ClientSecret ) $env:SAIL_BASE_URL = $BaseUrl.TrimEnd('/') $env:SAIL_CLIENT_ID = $ClientId $env:SAIL_CLIENT_SECRET = $ClientSecret } function Resolve-SailpointSdkCredentials { param( [string]$ConfigPath, [string]$PreferredBaseUrl ) $fromEnv = Get-SailpointSdkConfigFromEnvironment if ($fromEnv) { if ($PreferredBaseUrl -and ($fromEnv.BaseUrl.TrimEnd('/') -ne $PreferredBaseUrl.TrimEnd('/'))) { $message = "SAIL_* environment credentials target $($fromEnv.BaseUrl); preferred env API URL is $PreferredBaseUrl." if (Get-Command Write-Info -ErrorAction SilentlyContinue) { Write-Info $message } else { Write-Host " $message" -ForegroundColor DarkGray } } return $fromEnv } $candidates = [System.Collections.Generic.List[string]]::new() if ($ConfigPath) { $candidates.Add($ConfigPath) } $candidates.Add((Join-Path (Get-Location) 'config.json')) foreach ($path in $candidates) { if ($path -and (Test-Path -LiteralPath $path)) { return Get-SailpointSdkConfigFromFile -Path $path } } return $null } function Ensure-SailPointSdkModule { Install-PowerShellGalleryModuleSet -ModuleNames @('PSSailpoint') -PromptTitle 'SailPoint PowerShell SDK (PSSailpoint) is required' Import-PowerShellGalleryModuleSet -ModuleNames @('PSSailpoint') } function Initialize-SailPointSdkSession { param( [Parameter(Mandatory)]$Credentials, [switch]$Experimental ) Ensure-SailPointSdkModule Set-SailpointProcessCredentials -BaseUrl $Credentials.BaseUrl -ClientId $Credentials.ClientId -ClientSecret $Credentials.ClientSecret if (Get-Command Set-DefaultConfiguration -ErrorAction SilentlyContinue) { $params = @{ BaseUrl = $Credentials.BaseUrl ClientId = $Credentials.ClientId ClientSecret = $Credentials.ClientSecret } if ($Experimental) { $params['Experimental'] = $true } Set-DefaultConfiguration @params } $null = Get-DefaultConfiguration } function Invoke-SailPointSdkPagedList { param( [Parameter(Mandatory)][scriptblock]$Fetcher, [int]$PageSize = 250 ) $offset = 0 $all = [System.Collections.Generic.List[object]]::new() while ($true) { $page = @( & $Fetcher @{ Offset = $offset Limit = $PageSize } ) if ($page.Count -eq 0) { break } foreach ($item in $page) { $all.Add($item) } if ($page.Count -lt $PageSize) { break } $offset += $PageSize } return , $all.ToArray() } function Test-SailPointSdkConnection { if (-not (Get-Command Get-SourcesV1 -ErrorAction SilentlyContinue)) { throw 'PSSailpoint cmdlets were not imported. Install-Module PSSailpoint -Scope CurrentUser and retry.' } $null = @(Get-SourcesV1 -Limit 1 -ErrorAction Stop) return $true } function Get-MicrosoftLicensingCsvUrl { return $script:MicrosoftLicensingCsvUrl } Export-ModuleMember -Function @( 'Get-SailpointConfigYamlPath' 'ConvertFrom-SailpointSimpleYaml' 'Get-SailpointCliEnvironments' 'Save-SailpointCliEnvironmentUrls' 'Get-SailpointSdkConfigFromFile' 'Get-SailpointSdkConfigFromEnvironment' 'Set-SailpointProcessCredentials' 'Resolve-SailpointSdkCredentials' 'Ensure-SailPointSdkModule' 'Initialize-SailPointSdkSession' 'Invoke-SailPointSdkPagedList' 'Test-SailPointSdkConnection' 'Get-MicrosoftLicensingCsvUrl' ) |