IdentityCommand.SecretsHub.psm1
|
function ConvertTo-SHFilterString { <# .SYNOPSIS Assembles a Secrets Hub filter expression. .DESCRIPTION Formats filter clauses into the query language accepted by the Secrets Hub service. The dialect is deliberately simple: clauses are juxtaposed and joined with AND, there is no OR, and parentheses are not supported. name CONTAINS my AND storeName CONTAINS our Comparison is by EQ, CONTAINS, NOTCONTAINS, NEQ or GE, and values are case insensitive. A value containing whitespace is quoted, and a quote character within a quoted value is escaped with a backslash - both handled by ConvertTo-FilterClause. Callers pass raw values and never pre-quote. The expression is not url encoded - Add-QueryString encodes the query string as a whole. .PARAMETER Filter The clauses to assemble, each a hashtable with Field, Operator and Value keys. .EXAMPLE ConvertTo-SHFilterString -Filter @{ Field = 'name'; Operator = 'CONTAINS'; Value = 'my' } Outputs: name CONTAINS my .EXAMPLE ConvertTo-SHFilterString -Filter @( @{ Field = 'name'; Operator = 'CONTAINS'; Value = 'my' } @{ Field = 'storeName'; Operator = 'CONTAINS'; Value = 'our' } ) Outputs: name CONTAINS my AND storeName CONTAINS our .EXAMPLE ConvertTo-SHFilterString -Filter @{ Field = 'name'; Operator = 'EQ'; Value = 'my value' } Outputs: name EQ "my value" .OUTPUTS String #> [CmdletBinding()] [OutputType([string])] param( [parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true )] [hashtable[]]$Filter ) begin { #The documented query language lists EQ, CONTAINS and NOTCONTAINS; NEQ and GE are confirmed #additionally, both observed live against /api/secrets (vendorSubType NEQ, GE on a numeric #field) and matching that endpoint's own filter table. HAS (secret stores' behaviors field) #and LE (paired with GE on several /api/secrets fields) remain unconfirmed and excluded. $ValidOperator = @('EQ', 'CONTAINS', 'NOTCONTAINS', 'NEQ', 'GE') $Clauses = [System.Collections.Generic.List[string]]::new() } process { foreach ($Clause in $Filter) { if (-not $Clause.ContainsKey('Field')) { throw 'Each filter clause requires a Field' } if (-not $Clause.ContainsKey('Operator')) { throw "Filter clause for field '$($Clause['Field'])' requires an Operator" } if (-not $Clause.ContainsKey('Value')) { throw "Filter clause for field '$($Clause['Field'])' requires a Value" } $Operator = $Clause['Operator'] if ($Operator -notin $ValidOperator) { throw "'$Operator' is not a filter operator supported by the Secrets Hub service. Valid operators are: $($ValidOperator -join ', ')" } $Clauses.Add($(ConvertTo-FilterClause -Field $Clause['Field'] -Operator $Operator -Value $Clause['Value'])) } } end { if ($Clauses.Count -eq 0) { return } $Clauses -join ' AND ' } } function Get-SHApiHeader { <# .SYNOPSIS Returns the Accept header value for the Secrets Hub beta API surface. .DESCRIPTION Several Secrets Hub endpoints are documented as Beta and require an explicit Accept header on every call; a request without it is refused with 406 Not Acceptable. The value is held here so the commands which need it do not each carry a copy. Pass the returned value to Invoke-IDRestMethod's -Accept parameter. .EXAMPLE Invoke-IDRestMethod -Uri $URI -Method GET -Accept $(Get-SHApiHeader) .OUTPUTS String #> [CmdletBinding()] [OutputType([string])] param() 'application/x.secretshub.beta+json' } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Connect-SHTenant { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Subdomain')] param( #subdomain [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Subdomain')] [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'SubdomainCredential')] [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'SubdomainSAML')] [ValidateNotNullOrEmpty()] [Alias('subdomain')] [String]$tenant_subdomain, #tenant_url [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'URL')] [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'URLCredential')] [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'URLSAML')] [ValidateNotNullOrEmpty()] [Alias('secretshub_url')] [String]$tenant_url, #Credential used to authenticate to CyberArk Identity. Authentication is performed even if an active IdentityCommand session is found, replacing it [parameter(Mandatory = $true, ParameterSetName = 'SubdomainCredential')] [parameter(Mandatory = $true, ParameterSetName = 'URLCredential')] [ValidateNotNullOrEmpty()] [PSCredential]$Credential, #Authenticate as a service user via New-IDPlatformToken (OAuth client_credentials) instead of the interactive New-IDSession [parameter(ParameterSetName = 'SubdomainCredential')] [parameter(ParameterSetName = 'URLCredential')] [Switch]$PlatformToken, #SAML assertion used to authenticate to CyberArk Identity. Authentication is performed even if an active IdentityCommand session is found, replacing it [parameter(Mandatory = $true, ParameterSetName = 'SubdomainSAML')] [parameter(Mandatory = $true, ParameterSetName = 'URLSAML')] [ValidateNotNullOrEmpty()] [String]$SAMLResponse ) begin { $IDSession = Get-IDSession $HaveSession = $null -ne $IDSession.tenant_url $AuthRequested = $PSBoundParameters.ContainsKey('Credential') -or $PSBoundParameters.ContainsKey('SAMLResponse') if ($HaveSession -and $AuthRequested) { Write-Verbose 'Authentication parameters were supplied; authenticating and replacing the existing IdentityCommand session' } }#begin process { $UsingSubdomain = $PSCmdlet.ParameterSetName -like 'Subdomain*' #Resolve service URLs from platform discovery when a subdomain was supplied, or when #authentication is required and the CyberArk Identity URL must be discovered. $ServiceUrl = $null if ($UsingSubdomain) { $ServiceUrl = Resolve-ServiceUrl -Service secrets_hub -Subdomain $tenant_subdomain $tenant_url = $ServiceUrl.ServiceUrl } else { #Ensure URL is in expected format - remove trailing slash if provided in Url $tenant_url = $tenant_url -replace '/$', '' if ($AuthRequested) { $ServiceUrl = Resolve-ServiceUrl -Service secrets_hub -Url $tenant_url } } if ($AuthRequested -or (-not $HaveSession)) { if (-not $AuthRequested) { throw 'Authenticate with New-IDSession or New-IDPlatformToken, or supply -Credential, and try again' } $IdentityUrl = $ServiceUrl.IdentityUrl if ($PSCmdlet.ShouldProcess($IdentityUrl, 'Authenticate to CyberArk Identity')) { if ($PSCmdlet.ParameterSetName -like '*SAML') { $null = New-IDSession -tenant_url $IdentityUrl -SAMLResponse $SAMLResponse } elseif ($PlatformToken) { $null = New-IDPlatformToken -tenant_url $IdentityUrl -Credential $Credential } else { $null = New-IDSession -tenant_url $IdentityUrl -Credential $Credential } $IDSession = Get-IDSession } } #Make the CyberArk Identity Session available in the IdentityCommand.SecretsHub scope foreach ($key in $IDSession.keys) { if ($null -ne $IDSession[$key]) { $ISPSSSession[$key] = $IDSession[$key] } } #Set the Access Requests URL in the session data $ISPSSSession.tenant_url = $tenant_url }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHConfiguration { [CmdletBinding()] param() begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/configuration" #Send Request Invoke-IDRestMethod -Uri $URI -Method GET }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHModuleData { [CmdletBinding()] param() begin { }#begin process { #Calculate the time elapsed since the start of the session and include in return data if ($null -ne $ISPSSSession.StartTime) { $ISPSSSession.ElapsedTime = '{0:HH:mm:ss}' -f ([datetime]$($(Get-Date) - $($ISPSSSession.StartTime)).Ticks) } else { $ISPSSSession.ElapsedTime = $null } #Deep Copy the $ISPSSSession session object and return as IdCmd Session type. Get-SessionClone -InputObject $ISPSSSession | Add-CustomType -Type IdCmd.Session }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHSecret { [CmdletBinding(DefaultParameterSetName = 'byQuery')] param( [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [ValidateNotNullOrEmpty()] [String]$filter, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byFilterCriteria' )] [ValidateNotNullOrEmpty()] [hashtable[]]$FilterCriteria, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('EXTEND', 'REGULAR')] [String]$projection, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateRange(0, 150000)] [int]$offset, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateRange(1, 1000)] [int]$limit, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 100)] [String]$sort, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 200)] [String]$search ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secrets" $boundParameters = $PSBoundParameters | Get-Parameter -ParametersToRemove FilterCriteria if ($PSBoundParameters.ContainsKey('FilterCriteria')) { $boundParameters['filter'] = ConvertTo-SHFilterString -Filter $FilterCriteria } $URI = Add-QueryString -URI $URI -Parameter $boundParameters #Send Request $result = Invoke-IDRestMethod -Uri $URI -Method GET -Accept $(Get-SHApiHeader) if ($null -ne $result) { Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'secrets' -TotalResponseKey 'totalCount' } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHSecretsFilter { [CmdletBinding(DefaultParameterSetName = 'byStore')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$storeId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byId' )] [ValidateNotNullOrEmpty()] [String]$filterId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId/filters" if ($PSCmdlet.ParameterSetName -eq 'byId') { $URI = "$URI/$filterId" } #Send Request Invoke-IDRestMethod -Uri $URI -Method GET }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHSecretStore { [CmdletBinding(DefaultParameterSetName = 'byQuery')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byId' )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$storeId, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [ValidateLength(1, 2000)] [String]$filter, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byFilterCriteria' )] [ValidateNotNullOrEmpty()] [hashtable[]]$FilterCriteria, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byFilterCriteria' )] [ValidateRange(0, 2147483647)] [int]$offset, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byFilterCriteria' )] [ValidateRange(1, 1000)] [int]$limit, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byFilterCriteria' )] [ValidateLength(1, 100)] [String]$sort, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byFilterCriteria' )] [ValidateLength(1, 100)] [String]$search ) begin { }#begin process { if ($PSCmdlet.ParameterSetName -eq 'byId') { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId" #Send Request Invoke-IDRestMethod -Uri $URI -Method GET } else { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores" $boundParameters = $PSBoundParameters | Get-Parameter -ParametersToRemove FilterCriteria if ($PSBoundParameters.ContainsKey('FilterCriteria')) { $boundParameters['filter'] = ConvertTo-SHFilterString -Filter $FilterCriteria } $URI = Add-QueryString -URI $URI -Parameter $boundParameters #Send Request $result = Invoke-IDRestMethod -Uri $URI -Method GET if ($null -ne $result) { Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'secretStores' -TotalResponseKey 'totalCount' } } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHSyncPolicy { [CmdletBinding(DefaultParameterSetName = 'byQuery')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byId' )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$policyId, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [ValidateNotNullOrEmpty()] [String]$filter, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('EXTEND', 'REGULAR', 'METADATA')] [String]$projection, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [ValidateRange(0, 150000)] [int]$offset, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byQuery' )] [ValidateRange(1, 1000)] [int]$limit ) begin { }#begin process { if ($PSCmdlet.ParameterSetName -eq 'byId') { $URI = "$($ISPSSSession.tenant_url)/api/policies/$policyId" $URI = Add-QueryString -URI $URI -Parameter ($PSBoundParameters | Get-Parameter -ParametersToRemove policyId) #Send Request Invoke-IDRestMethod -Uri $URI -Method GET } else { $URI = "$($ISPSSSession.tenant_url)/api/policies" $URI = Add-QueryString -URI $URI -Parameter ($PSBoundParameters | Get-Parameter) #Send Request $result = Invoke-IDRestMethod -Uri $URI -Method GET if ($null -ne $result) { #The policies response reports the tenant total as count, with no separate totalCount Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'policies' -TotalResponseKey 'count' } } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Get-SHTransformation { [CmdletBinding()] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$transformationId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/transformations/$transformationId" #Send Request Invoke-IDRestMethod -Uri $URI -Method GET }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function New-SHSecretsFilter { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$storeId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 28)] [String]$safeName ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId/filters" #PAM_SAFE is the only filter type the service supports $body = [ordered]@{ type = 'PAM_SAFE'; data = @{ safeName = $safeName } } | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($safeName, 'Create Secrets Filter')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method POST -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function New-SHSecretStore { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('PAM_PCLOUD', 'PAM_SELF_HOSTED', 'AWS_ASM', 'AZURE_AKV', 'GCP_GSM', 'HASHICORP_VAULT', 'HASHICORP_VAULT_ENT')] [String]$type, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 200)] [String]$name, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [hashtable]$data, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 150)] [String]$description, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('ENABLED', 'DISABLED')] [String]$state ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores" $body = $PSBoundParameters | Get-Parameter | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($name, 'Create Secret Store')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method POST -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function New-SHSyncPolicy { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'BySafeName')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 100)] [String]$name, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 150)] [String]$description, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$sourceId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$targetId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'BySafeName' )] [ValidateLength(1, 28)] [String]$safeName, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'ByFilterId' )] [ValidateNotNullOrEmpty()] [String]$filterId, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('password_only_plain_text')] [String]$transformation ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/policies" $Policy = [ordered]@{ name = $name source = @{ id = $sourceId } target = @{ id = $targetId } } if ($PSBoundParameters.ContainsKey('description')) { $Policy['description'] = $description } $Policy['filter'] = if ($PSCmdlet.ParameterSetName -eq 'ByFilterId') { @{ id = $filterId } } else { [ordered]@{ type = 'PAM_SAFE'; data = @{ safeName = $safeName } } } if ($PSBoundParameters.ContainsKey('transformation')) { $Policy['transformation'] = @{ predefined = $transformation } } $body = $Policy | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($name, 'Create Sync Policy')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method POST -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Publish-SHSecret { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('AWS_ASM', 'GCP_GSM', 'AZURE_AKV', 'HASHICORP_VAULT', 'HASHICORP_VAULT_ENT')] [String]$sourceSecretStoreType, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('PAM_PCLOUD', 'PAM_SELF_HOSTED')] [String]$targetSecretStoreType, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$secretId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('PLAINTEXT', 'JSON', 'TEMPLATE')] [String]$secretValueType, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 28)] [String]$safeName, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [hashtable]$pamAccount ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secrets-onboarding/$sourceSecretStoreType/$targetSecretStoreType" $body = $PSBoundParameters | Get-Parameter -ParametersToRemove sourceSecretStoreType, targetSecretStoreType | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($secretId, 'Onboard Secret')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method POST -Body $body -Accept $(Get-SHApiHeader) } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Remove-SHSecret { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$secretId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secrets/$secretId" #The service requires fromTarget, and documents true as its only accepted value $URI = Add-QueryString -URI $URI -Parameter @{ fromTarget = 'true' } if ($PSCmdlet.ShouldProcess($secretId, 'Delete Secret From Target Secret Store')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method DELETE } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Remove-SHSecretsFilter { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$storeId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$filterId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId/filters/$filterId" if ($PSCmdlet.ShouldProcess($filterId, 'Delete Secrets Filter')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method DELETE } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Remove-SHSecretStore { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$storeId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId" if ($PSCmdlet.ShouldProcess($storeId, 'Delete Secret Store')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method DELETE } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Remove-SHSyncPolicy { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$policyId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/policies/$policyId" if ($PSCmdlet.ShouldProcess($policyId, 'Delete Sync Policy')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method DELETE } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Set-SHConfiguration { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateRange(1, 730)] [int]$secretValidity, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [AllowEmptyCollection()] [String[]]$gcpReplicationRegion ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/configuration" $SyncSettings = [ordered]@{ } if ($PSBoundParameters.ContainsKey('secretValidity')) { $SyncSettings['secretValidity'] = $secretValidity } if ($PSBoundParameters.ContainsKey('gcpReplicationRegion')) { #An empty list reverts regional replication to GCP's default global replication $SyncSettings['gcp'] = @{ secretReplication = @{ regions = @($gcpReplicationRegion) } } } $body = [ordered]@{ syncSettings = $SyncSettings } | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess('Secrets Hub Configuration', 'Update Configuration')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method PATCH -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Set-SHSecretStore { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$storeId, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [hashtable]$data, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 200)] [String]$name, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateLength(1, 150)] [String]$description ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId" $body = $PSBoundParameters | Get-Parameter -ParametersToRemove storeId | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($storeId, 'Update Secret Store')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method PATCH -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Set-SHSecretStoreState { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Single')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'Single' )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$storeId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'Bulk' )] [ValidateCount(1, 500)] [String[]]$secretStoreIds, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('enable', 'disable')] [String]$action ) begin { }#begin process { if ($PSCmdlet.ParameterSetName -eq 'Bulk') { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/states" $Target = "$($secretStoreIds.Count) secret stores" $body = [ordered]@{ action = $action; secretStoreIds = $secretStoreIds } | ConvertTo-Json -Depth 8 } else { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId/state" $Target = $storeId $body = [ordered]@{ action = $action } | ConvertTo-Json -Depth 8 } if ($PSCmdlet.ShouldProcess($Target, "Set Secret Store State: $action")) { #Send Request Invoke-IDRestMethod -Uri $URI -Method PUT -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Set-SHSyncPolicyState { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$policyId, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('enable', 'disable')] [String]$action ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/policies/$policyId/state" $body = [ordered]@{ action = $action } | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($policyId, "Set Sync Policy State: $action")) { #Send Request Invoke-IDRestMethod -Uri $URI -Method PUT -Body $body } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Start-SHScan { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateCount(1, 1)] [Alias('storeId')] [String[]]$secretStoresIds, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$type = 'secret-store', [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [String]$id = 'default' ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/scan-definitions/$type/$id/scan" $body = [ordered]@{ scope = @{ secretStoresIds = $secretStoresIds } } | ConvertTo-Json -Depth 8 if ($PSCmdlet.ShouldProcess($secretStoresIds -join ', ', 'Trigger Scan')) { #Send Request Invoke-IDRestMethod -Uri $URI -Method POST -Body $body -Accept $(Get-SHApiHeader) } }#process end { }#end } # .ExternalHelp IdentityCommand.SecretsHub-help.xml function Test-SHSecretStoreConnection { [CmdletBinding()] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateNotNullOrEmpty()] [Alias('id')] [String]$storeId ) begin { }#begin process { $URI = "$($ISPSSSession.tenant_url)/api/secret-stores/$storeId/status/connection" #Send Request Invoke-IDRestMethod -Uri $URI -Method GET }#process end { }#end } #Copy IdentityCommand's private helpers into this module: this module's functions call them, and #the argument completer registrations below do so at import time. #Each copy is created from the function definition, so it runs in this module's scope and uses this #module's $ISPSSSession, whether IdentityCommand loaded from source or from its combined psm1. #Resolve a single IdentityCommand module: with more than one version loaded, Get-Module returns #an array. $Module = Get-Module -Name IdentityCommand | Sort-Object Version -Descending | Select-Object -First 1 if ($null -eq $Module) { throw 'The IdentityCommand module is not loaded. Import IdentityCommand and try again.' } & $Module { Get-ChildItem -Path Function: } | Where-Object { $_.ModuleName -eq $Module.Name -and -not $Module.ExportedFunctions.ContainsKey($_.Name) } | ForEach-Object { . ([scriptblock]::Create("function $($_.Name) {$($_.Definition)}")) } #region Registration Register-ArgumentCompleter -ParameterName 'storeId' -ScriptBlock ( Get-ArgumentCompleter -RetrievalCommand 'Get-SHSecretStore' -ValueProperty 'id' -LabelProperty 'name' ) -CommandName @( 'Get-SHSecretStore' 'Get-SHSecretsFilter' 'New-SHSecretsFilter' 'Remove-SHSecretStore' 'Remove-SHSecretsFilter' 'Set-SHSecretStore' 'Set-SHSecretStoreState' 'Test-SHSecretStoreConnection' ) Register-ArgumentCompleter -ParameterName 'secretStoresIds' -ScriptBlock ( Get-ArgumentCompleter -RetrievalCommand 'Get-SHSecretStore' -ValueProperty 'id' -LabelProperty 'name' ) -CommandName 'Start-SHScan' Register-ArgumentCompleter -ParameterName 'secretStoreIds' -ScriptBlock ( Get-ArgumentCompleter -RetrievalCommand 'Get-SHSecretStore' -ValueProperty 'id' -LabelProperty 'name' ) -CommandName 'Set-SHSecretStoreState' Register-ArgumentCompleter -ParameterName 'sourceId' -ScriptBlock ( Get-ArgumentCompleter -RetrievalCommand 'Get-SHSecretStore' -ValueProperty 'id' -LabelProperty 'name' ) -CommandName 'New-SHSyncPolicy' Register-ArgumentCompleter -ParameterName 'targetId' -ScriptBlock ( Get-ArgumentCompleter -RetrievalCommand 'Get-SHSecretStore' -ValueProperty 'id' -LabelProperty 'name' ) -CommandName 'New-SHSyncPolicy' Register-ArgumentCompleter -ParameterName 'policyId' -ScriptBlock ( Get-ArgumentCompleter -RetrievalCommand 'Get-SHSyncPolicy' -ValueProperty 'id' -LabelProperty 'name' ) -CommandName @( 'Get-SHSyncPolicy' 'Remove-SHSyncPolicy' 'Set-SHSyncPolicyState' ) #endregion Registration # Script scope session object for session data $ISPSSSession = [ordered]@{ tenant_url = $null User = $null TenantId = $null SessionId = $null WebSession = $null StartTime = $null ElapsedTime = $null LastCommand = $null LastCommandTime = $null LastCommandResults = $null LastError = $null LastErrorTime = $null } | Add-CustomType -Type IdCmd.Session New-Variable -Name ISPSSSession -Value $ISPSSSession -Scope Script -Force |