IdentityCommand.DiscoveryMgmt.psm1
|
function ConvertTo-DMFilterString { <# .SYNOPSIS Assembles a Discovery Management filter expression. .DESCRIPTION Formats field/value pairs into the filter expression accepted by the Discovery Management service. Each pair becomes an equality clause, and clauses are joined with AND. type eq SomeType AND recurrenceType eq SomeRecurrence 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. Clauses are ordered by field name. The expression is not url encoded - ConvertTo-QueryString encodes the query string as a whole. .PARAMETER Filter Hashtable of field names and the values to compare them against. .EXAMPLE ConvertTo-DMFilterString -Filter @{ type = 'SomeType' } Outputs: type eq SomeType .EXAMPLE ConvertTo-DMFilterString -Filter @{ type = 'SomeType'; lastInstanceStatus = 'Some Status' } Outputs: lastInstanceStatus eq "Some Status" AND type eq SomeType .OUTPUTS String #> [CmdletBinding()] [OutputType([string])] param( [parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true )] [AllowEmptyCollection()] [hashtable]$Filter ) process { $Clauses = foreach ($Field in ($Filter.Keys | Sort-Object)) { ConvertTo-FilterClause -Field $Field -Operator eq -Value $Filter[$Field] } if (@($Clauses).Count -gt 0) { $Clauses -join ' AND ' } } } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Add-DMDiscoveryScanDefinition { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$name, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet( 'WIN_NIX_LIST', 'WIN_NIX_DOMAIN', 'POSTGRESQL', 'MYSQL', 'ORACLE', 'SQL_SERVER', 'INVENTORY_WIN_NIX_LIST' )] [string]$type, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [hashtable]$properties, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('AWS', 'AZURE', 'ON_PREM')] [string]$locationType, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [hashtable[]]$credentials, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$networkId, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string[]]$tags, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('IMMEDIATE', 'SCHEDULED', 'RECURRING')] [string]$recurrenceType, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [hashtable]$recurrenceData, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('ACTIVE', 'INACTIVE')] [string]$State ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-definitions" #Get bound parameters to include in request $BoundParameters = $PSBoundParameters | Get-Parameter if ($BoundParameters.ContainsKey('State')) { #PowerShell hashtables are case-insensitive, so "State" & "state" are the same key. #The value must be removed before being re-added, otherwise the API's expected #lowercase "state" property name is never actually applied to the stored key. $StateValue = $BoundParameters['State'] $BoundParameters.Remove('State') $BoundParameters['state'] = $StateValue } #Create Request Body $Body = $BoundParameters | ConvertTo-Json -Depth 10 if ($PSCmdlet.ShouldProcess($name, 'Add Scan Definition')) { #Send request to web service Invoke-IDRestMethod -Uri $URI -Method POST -Body $Body } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Add-DMDiscoveryScanResource { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('WIN_NIX_LIST', 'SQL_SERVER', 'ORACLE', 'MYSQL', 'POSTGRESQL', 'INVENTORY_WIN_NIX_LIST')] [string]$type, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$name, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [hashtable]$content, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('AWS', 'AZURE')] [string]$locationType ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/discovery-scans/resources" #Get bound parameters to include in request $BoundParameters = $PSBoundParameters | Get-Parameter #Ensure a single machine list entry is not collapsed to a JSON object instead of an array if ($BoundParameters['content'].ContainsKey('machineList')) { $BoundParameters['content']['machineList'] = $BoundParameters['content']['machineList'] -as [array] } #Create Request Body $Body = $BoundParameters | ConvertTo-Json -Depth 10 if ($PSCmdlet.ShouldProcess($name, 'Add Discovery Scan Resource')) { #Send request to web service Invoke-IDRestMethod -Uri $URI -Method POST -Body $Body } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Get-DMDiscoveryScan { [CmdletBinding()] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$id ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-instances/$id" #Send request to web service $result = Invoke-IDRestMethod -Uri $URI -Method GET if ($null -ne $Result) { $Result } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Get-DMDiscoveryScanDefinition { [CmdletBinding(DefaultParameterSetName = 'GetAllScanDefinitions')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'byID' )] [string]$id, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [string]$search, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [ValidateSet( 'creationTime', 'updateTime', 'name', 'type', 'recurrenceType', 'lastInstanceStatus', 'lastInstanceCreationTime' )] [string]$sort, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [ValidateSet('asc', 'desc')] [string]$sortDirection, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [string]$type, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [string]$recurrenceType, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [string]$lastInstanceStatus, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [bool]$extendedDetails, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'GetAllScanDefinitions' )] [ValidateSet( 'ACTIVE', 'INACTIVE' )] [string]$State ) begin { #Parameter to include as filter value in url $Parameters = [Collections.Generic.List[String]]@('lastInstanceStatus', 'recurrenceType', 'type') } process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-definitions" switch ($PSCmdlet.ParameterSetName) { 'byID' { $URI = "$URI/$id" break } 'GetAllScanDefinitions' { #Sort properties which are only valid when extendedDetails is requested $ExtendedOnlySortProperties = @('lastInstanceStatus', 'lastInstanceCreationTime') if ($PSBoundParameters.ContainsKey('sort') -and ($ExtendedOnlySortProperties -contains $sort) -and ($extendedDetails -ne $true)) { throw "Sort property '$sort' is only valid when -extendedDetails is set to `$true" } if ($PSBoundParameters.ContainsKey('sort') -or $PSBoundParameters.ContainsKey('sortDirection')) { if ($PSBoundParameters.ContainsKey('sort')) { $sortProperty = $sort } else { $sortProperty = 'creationTime' #default sort property } if ($PSBoundParameters.ContainsKey('sortDirection')) { $direction = $sortDirection } else { $direction = 'asc' #default sort direction } #Append sort direction to sort property for correct query string creation $PSBoundParameters['sort'] = "$sortProperty $direction" } #Get Parameters to include in request $boundParameters = $PSBoundParameters | Get-Parameter -ParametersToRemove ($Parameters + 'sortDirection') $filterParameters = $PSBoundParameters | Get-Parameter -ParametersToKeep $Parameters $FilterString = ConvertTo-DMFilterString -Filter $filterParameters # Append filter string if present if ($null -ne $FilterString) { $boundParameters['filter'] = $FilterString } #Create Query String, escaped for inclusion in request URL $queryString = $boundParameters | ConvertTo-QueryString if ($null -ne $queryString) { #Build URL from base URL $URI = "$URI`?$queryString" } } } #Send request to web service $result = Invoke-IDRestMethod -Uri $URI -Method GET if ($null -ne $Result) { switch ( $PSCmdlet.ParameterSetName ) { 'byID' { #Single ruleset returned $Output = $result break } 'GetAllScanDefinitions' { #Multiple rulesets returned $Output = $result.Items break } } $Output } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Get-DMDiscoveryScanLog { [CmdletBinding()] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$id ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-instances/$id/logs/url/" #Send request to web service $result = Invoke-IDRestMethod -Uri $URI -Method GET if ($null -ne $Result) { $Result } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Get-DMDiscoveryScanResource { [CmdletBinding()] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$id ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/discovery-scans/resources/$id" #Send request to web service $result = Invoke-IDRestMethod -Uri $URI -Method GET if ($null -ne $Result) { $Result } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function New-DMDiscoveryScanResourceCloudObject { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'AWS')] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AWS' )] [string]$account, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AWS' )] [string[]]$vpcs, [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AZURE' )] [string]$subscription_id, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AZURE' )] [string[]]$resource_groups, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AZURE' )] [string[]]$vnet_ids, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AWS' )] [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AZURE' )] [string[]]$regions, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AWS' )] [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true, ParameterSetName = 'AZURE' )] [string[]]$cloud_tags ) process { #Get bound parameters to include in the returned object $boundParameters = $PSBoundParameters | Get-Parameter if ($PSCmdlet.ParameterSetName -eq 'AWS') { $ShouldProcessTarget = $account } else { $ShouldProcessTarget = $subscription_id } if ($PSCmdlet.ShouldProcess($ShouldProcessTarget, 'Create Discovery Scan Resource Cloud Object')) { $boundParameters } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function New-DMDiscoveryScanResourceMachineObject { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$Address, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$Username, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$Database, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [int]$Port, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$Domain, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string[]]$Tags, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$Instances ) process { #Get bound parameters to include in the returned object $boundParameters = $PSBoundParameters | Get-Parameter if ($PSCmdlet.ShouldProcess($Address, 'Create Discovery Scan Resource Machine Object')) { $boundParameters } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Remove-DMDiscoveryScanDefinition { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$id ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-definitions/$id" if ($PSCmdlet.ShouldProcess($id, 'Remove Scan Definition')) { #Send Delete request to web service Invoke-IDRestMethod -Uri $URI -Method DELETE } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Set-DMDiscoveryScanDefinition { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$id, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$name, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet( 'WIN_NIX_LIST', 'WIN_NIX_DOMAIN', 'POSTGRESQL', 'MYSQL', 'ORACLE', 'SQL_SERVER', 'INVENTORY_WIN_NIX_LIST' )] [string]$type, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [hashtable]$properties, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('AWS', 'AZURE', 'ON_PREM')] [string]$locationType, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [hashtable[]]$credentials, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string]$networkId, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [string[]]$tags, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('IMMEDIATE', 'SCHEDULED', 'RECURRING')] [string]$recurrenceType, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [hashtable]$recurrenceData, [parameter( Mandatory = $false, ValueFromPipelinebyPropertyName = $true )] [ValidateSet('ACTIVE', 'INACTIVE')] [string]$State ) begin { #Properties which can be sent in a PUT request, and which can be backfilled from the #current scan definition when not specified, so they are not cleared by the request #Named distinctly from the -properties parameter: PowerShell variable names are #case-insensitive, so a variable named $Properties here would be the same variable as #the -properties parameter and would silently overwrite its bound value $MergeableProperties = [Collections.Generic.List[String]]@('name', 'type', 'properties', 'locationType', 'credentials', 'networkId', 'tags', 'recurrenceType', 'recurrenceData', 'state') } process { #Get bound parameters to include in request $BoundParameters = $PSBoundParameters | Get-Parameter -ParametersToRemove id #Get current scan definition property values $ExistingScanDefinition = Get-DMDiscoveryScanDefinition -id $id if ($null -ne $ExistingScanDefinition) { #For any property not included in the request, but present on the existing scan definition, #add the existing property value to the request unchanged, so it is not cleared by the PUT request. #Values are copied as-is, without flattening, since properties/credentials/recurrenceData are #nested objects/arrays whose shape already matches what the API expects in the request body. $MergeableProperties | ForEach-Object { if ((-not $BoundParameters.ContainsKey($PSItem)) -and ($null -ne $ExistingScanDefinition.$PSItem)) { $BoundParameters[$PSItem] = $ExistingScanDefinition.$PSItem } } } if ($BoundParameters.ContainsKey('State')) { #PowerShell hashtables are case-insensitive, so "State" & "state" are the same key. #The value must be removed before being re-added, otherwise the API's expected #lowercase "state" property name is never actually applied to the stored key. $StateValue = $BoundParameters['State'] $BoundParameters.Remove('State') $BoundParameters['state'] = $StateValue } #Ensure array properties are not collapsed to a single value 'tags', 'credentials' | ForEach-Object { if ($BoundParameters.ContainsKey($PSItem)) { $BoundParameters[$PSItem] = $BoundParameters[$PSItem] -as [array] } } #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-definitions/$id" #Create Request Body $Body = $BoundParameters | ConvertTo-Json -Depth 10 if ($PSCmdlet.ShouldProcess($id, 'Update Scan Definition')) { #Send request to web service Invoke-IDRestMethod -Uri $URI -Method PUT -Body $Body } } end {} } # .ExternalHelp IdentityCommand.DiscoveryMgmt-help.xml function Start-DMDiscoveryScan { [CmdletBinding(SupportsShouldProcess)] param( [parameter( Mandatory = $true, ValueFromPipelinebyPropertyName = $true )] [string]$id ) process { #Create URL for Request $URI = "$(Resolve-RequestUrl)/api/scan-instances" $Body = $PSBoundParameters | Get-Parameter | ConvertTo-Json if ($PSCmdlet.ShouldProcess($id, 'Start Discovery Scan')) { #Send Delete request to web service Invoke-IDRestMethod -Uri $URI -Method POST -Body $Body } } end {} } #Copy IdentityCommand's private helpers into this module: this module's functions call them. #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)}")) } # Script scope session object for session data $ISPSSSession = [ordered]@{ tenant_url = $null User = $null TenantId = $null SessionId = $null Subdomain = $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 #Platform discovery key of the service, used to resolve the service URL from the IdentityCommand session New-Variable -Name ServiceKey -Value 'dms' -Scope Script -Force |