Public/ScopingCriteria/New-JIMScopingCriterion.ps1
|
# Copyright (c) Tetron Limited. All rights reserved. # Licensed under the Tetron Commercial License. See LICENSE file in the project root. function New-JIMScopingCriterion { <# .SYNOPSIS Adds a criterion to a scoping criteria group. .DESCRIPTION Adds a criterion to a scoping criteria group: one attribute compared with one value. Name a Metaverse attribute for an export Synchronisation Rule and a Connected System attribute for an import one, and give the value in the parameter for the attribute's data type; HasValue and HasNoValue take no value. To compare a value computed from the object instead, give -Expression and the type to compare it as in -CompareAs. .PARAMETER SyncRuleId The ID of the Synchronisation Rule. .PARAMETER GroupId The ID of the group to add the criterion to. .PARAMETER MetaverseAttributeId The ID of the Metaverse attribute to test. An export Synchronisation Rule's criteria test Metaverse attributes. .PARAMETER MetaverseAttributeName The name of the Metaverse attribute to test, instead of its ID. .PARAMETER ConnectedSystemAttributeId The ID of the Connected System attribute to test. An import Synchronisation Rule's criteria test Connected System attributes. .PARAMETER ConnectedSystemAttributeName The name of the Connected System attribute to test, instead of its ID. .PARAMETER Expression An expression whose computed value the criterion compares, in place of an attribute. It reads the object the Synchronisation Rule scopes: cs["name"] on an import rule, mv["Name"] on an export rule. Use it to compare a value reshaped first, such as Lower(Trim(cs["department"])). Requires -CompareAs. .PARAMETER CompareAs The type the expression's computed value is compared as, which decides the comparisons and the value parameter that apply, as an attribute's own type does. A value the expression computes that cannot be read as this type stops that object with an error rather than deciding its scope. .PARAMETER ComparisonType How the attribute is compared with the value. The Not forms are met when the attribute holds a value and none matches; the others when any value does. HasValue and HasNoValue test whether the attribute holds a value at all and take no value. MatchesPattern and NotMatchesPattern take a .NET regular expression in -StringValue, for Text attributes. .PARAMETER StringValue The value to compare a Text attribute with, or the regular expression for MatchesPattern and NotMatchesPattern. .PARAMETER IntValue The value to compare a Number attribute with. .PARAMETER LongValue The value to compare a LongNumber attribute with. .PARAMETER DecimalValue The value to compare a Decimal attribute with. For a high-precision value, use the d suffix (123.456789012345678d) or a quoted string: a bare number is read as a double first, and can lose precision. .PARAMETER DateTimeValue The date and time to compare a DateTime attribute with, when -ValueMode is Absolute. .PARAMETER BoolValue The value to compare a Boolean attribute with. .PARAMETER GuidValue The value to compare a Guid attribute with. .PARAMETER CaseSensitive Whether a Text comparison respects case: $false ignores it. Case-sensitive when omitted. .PARAMETER ValueMode For a DateTime attribute: Absolute compares with -DateTimeValue, and Relative with a date worked out from now each time the rule is evaluated, set by -RelativeCount, -RelativeUnit and -RelativeDirection. Relative cannot be used with -DateTimeValue. Absolute when omitted. .PARAMETER RelativeCount How many units from now the date is, zero or more. Used with -ValueMode Relative. .PARAMETER RelativeUnit The unit -RelativeCount counts. Used with -ValueMode Relative. .PARAMETER RelativeDirection Whether the date is in the past (Ago) or the future (FromNow). Used with -ValueMode Relative. .PARAMETER SaveAnyway Saves even though the change stops configuration test cases passing. Without it, or -AcceptNewResult, such a change is refused, nothing is saved, and the error names each case. Configuration History records the cases saved past, by name. .PARAMETER AcceptNewResult Takes what the configuration now gives as what each configuration test case that stopped passing expects, rewriting those cases, and saves. A case whose new result cannot be expected (it needs review, could not run, or its Scope cannot be determined) still refuses the change unless -SaveAnyway is given too. .PARAMETER PassThru Returns the criterion created. .OUTPUTS With -PassThru, the criterion created; otherwise nothing. JIM.ScopingCriterion SyncRuleId (int): The ID of the Synchronisation Rule the criterion belongs to. GroupId (int): The ID of the group the criterion is in. With SyncRuleId and Id, it lets the criterion be piped to Set-JIMScopingCriterion and Remove-JIMScopingCriterion. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -MetaverseAttributeName 'Department' -ComparisonType Equals -StringValue 'IT' Creates a criterion for an export Synchronisation Rule that filters for Department = 'IT'. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -ConnectedSystemAttributeName 'ou' -ComparisonType Equals -StringValue 'Finance' Creates a criterion for an import Synchronisation Rule that filters for ou = 'Finance'. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -MetaverseAttributeId 15 -ComparisonType StartsWith -StringValue 'Emp' -PassThru Creates a criterion using attribute ID 15 that matches values starting with 'Emp'. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -MetaverseAttributeName 'Active' -ComparisonType Equals -BoolValue $true Creates a criterion that filters for Active = true. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -ConnectedSystemAttributeName 'employeeType' -ComparisonType HasValue Creates a criterion for an import Synchronisation Rule that keeps only objects holding an employeeType. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -ConnectedSystemAttributeName 'mail' -ComparisonType MatchesPattern -StringValue '^[a-z.]+@example\.org$' -CaseSensitive $false Creates a criterion that keeps only objects with a mail address in the example.org domain, ignoring case. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -Expression 'Lower(Trim(cs["department"]))' -CompareAs Text -ComparisonType StartsWith -StringValue 'fin' Creates a criterion for an import Synchronisation Rule that keeps objects whose department starts with 'fin', however it is cased or padded. .EXAMPLE New-JIMScopingCriterion -SyncRuleId 5 -GroupId 10 -Expression 'ParseDate(cs["startDate"], "dd/MM/yyyy")' -CompareAs DateTime -ComparisonType LessThanOrEquals -ValueMode Relative -RelativeCount 14 -RelativeUnit Days -RelativeDirection FromNow Creates a criterion that brings people into scope 14 days before a start date held as text. The cmdlet warns that every Temporal Scope Reconciliation then evaluates every object of the type. .LINK Get-JIMScopingCriteria Remove-JIMScopingCriterion New-JIMScopingCriteriaGroup #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByMvId')] [OutputType('JIM.ScopingCriterion')] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [int]$SyncRuleId, [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [int]$GroupId, [Parameter(Mandatory, ParameterSetName = 'ByMvId')] [int]$MetaverseAttributeId, [Parameter(Mandatory, ParameterSetName = 'ByMvName')] [string]$MetaverseAttributeName, [Parameter(Mandatory, ParameterSetName = 'ByCsId')] [int]$ConnectedSystemAttributeId, [Parameter(Mandatory, ParameterSetName = 'ByCsName')] [string]$ConnectedSystemAttributeName, [Parameter(Mandatory, ParameterSetName = 'ByExpression')] [ValidateNotNullOrEmpty()] [string]$Expression, [Parameter(Mandatory, ParameterSetName = 'ByExpression')] [ValidateSet('Text', 'Number', 'LongNumber', 'Decimal', 'DateTime', 'Boolean', 'Guid')] [string]$CompareAs, [Parameter(Mandatory)] [ValidateSet('Equals', 'NotEquals', 'StartsWith', 'NotStartsWith', 'EndsWith', 'NotEndsWith', 'Contains', 'NotContains', 'LessThan', 'LessThanOrEquals', 'GreaterThan', 'GreaterThanOrEquals', 'HasValue', 'HasNoValue', 'MatchesPattern', 'NotMatchesPattern')] [string]$ComparisonType, [Parameter()] [string]$StringValue, [Parameter()] [int]$IntValue, [Parameter()] [long]$LongValue, [Parameter()] [decimal]$DecimalValue, [Parameter()] [datetime]$DateTimeValue, [Parameter()] [bool]$BoolValue, [Parameter()] [guid]$GuidValue, [Parameter()] [bool]$CaseSensitive, [Parameter()] [ValidateSet('Absolute', 'Relative')] [string]$ValueMode, [Parameter()] [int]$RelativeCount, [Parameter()] [ValidateSet('Hours', 'Days', 'Weeks', 'Months', 'Years')] [string]$RelativeUnit, [Parameter()] [ValidateSet('Ago', 'FromNow')] [string]$RelativeDirection, [switch]$SaveAnyway, [switch]$AcceptNewResult, [switch]$PassThru ) process { if (-not $script:JIMConnection) { Write-Error "You are not connected to JIM. Run Connect-JIM -Url <your JIM URL> to authenticate, then try again." return } $body = @{ comparisonType = $ComparisonType } # Handle Metaverse attribute (for export Synchronisation Rules) if ($PSCmdlet.ParameterSetName -eq 'ByMvId') { $body.metaverseAttributeId = $MetaverseAttributeId $attrDisplay = "MV Attribute ID $MetaverseAttributeId" } elseif ($PSCmdlet.ParameterSetName -eq 'ByMvName') { try { $attribute = Resolve-JIMMetaverseAttribute -Name $MetaverseAttributeName } catch { Write-Error $_ return } $body.metaverseAttributeId = $attribute.id $attrDisplay = "MV Attribute '$MetaverseAttributeName'" Write-Verbose "Resolved '$MetaverseAttributeName' to attribute ID $($attribute.id)" } # Handle Connected System attribute (for import Synchronisation Rules) elseif ($PSCmdlet.ParameterSetName -eq 'ByCsId') { $body.connectedSystemAttributeId = $ConnectedSystemAttributeId $attrDisplay = "CS Attribute ID $ConnectedSystemAttributeId" } elseif ($PSCmdlet.ParameterSetName -eq 'ByCsName') { # Get the Synchronisation Rule to find the connected system and object type Write-Verbose "Looking up Synchronisation Rule $SyncRuleId to find Connected System attribute" $syncRule = Invoke-JIMApi -Endpoint "/api/v1/synchronisation/sync-rules/$SyncRuleId" if (-not $syncRule) { Write-Error "Synchronisation Rule $SyncRuleId not found." return } if ($syncRule.direction -ne 'Import') { Write-Error "Connected System attributes can only be used with import Synchronisation Rules. This Synchronisation Rule is an export rule." return } # Get the object type attributes $connectedSystemId = $syncRule.connectedSystemId $objectTypeId = $syncRule.connectedSystemObjectTypeId Write-Verbose "Looking up Connected System $connectedSystemId object type $objectTypeId attributes" $objectTypes = Invoke-JIMApi -Endpoint "/api/v1/synchronisation/connected-systems/$connectedSystemId/object-types" $objectType = $objectTypes | Where-Object { $_.id -eq $objectTypeId } | Select-Object -First 1 if (-not $objectType) { Write-Error "Could not find object type $objectTypeId on Connected System $connectedSystemId." return } $attribute = $objectType.attributes | Where-Object { $_.name -eq $ConnectedSystemAttributeName } | Select-Object -First 1 if (-not $attribute) { Write-Error "Connected System attribute '$ConnectedSystemAttributeName' not found on object type '$($objectType.name)'." return } $body.connectedSystemAttributeId = $attribute.id $attrDisplay = "CS Attribute '$ConnectedSystemAttributeName'" Write-Verbose "Resolved '$ConnectedSystemAttributeName' to attribute ID $($attribute.id)" } if ($PSCmdlet.ParameterSetName -eq 'ByExpression') { $body.expression = $Expression $body.compareAs = $CompareAs $attrDisplay = "expression $Expression" } # Add the value based on what was provided if ($PSBoundParameters.ContainsKey('StringValue')) { $body.stringValue = $StringValue } if ($PSBoundParameters.ContainsKey('IntValue')) { $body.intValue = $IntValue } if ($PSBoundParameters.ContainsKey('LongValue')) { $body.longValue = $LongValue } if ($PSBoundParameters.ContainsKey('DecimalValue')) { $body.decimalValue = $DecimalValue } if ($PSBoundParameters.ContainsKey('DateTimeValue')) { $body.dateTimeValue = $DateTimeValue.ToString('o') } if ($PSBoundParameters.ContainsKey('BoolValue')) { $body.boolValue = $BoolValue } if ($PSBoundParameters.ContainsKey('GuidValue')) { $body.guidValue = $GuidValue.ToString() } if ($PSBoundParameters.ContainsKey('CaseSensitive')) { $body.caseSensitive = $CaseSensitive } # Relative date handling (DateTime attributes only; validated server-side too). $relativeRequested = ($PSBoundParameters.ContainsKey('ValueMode') -and $ValueMode -eq 'Relative') -or $PSBoundParameters.ContainsKey('RelativeCount') -or $PSBoundParameters.ContainsKey('RelativeUnit') -or $PSBoundParameters.ContainsKey('RelativeDirection') if ($relativeRequested) { if ($PSBoundParameters.ContainsKey('DateTimeValue')) { Write-Error "Provide either -DateTimeValue (absolute) or the relative parameters, not both." return } if (-not ($PSBoundParameters.ContainsKey('RelativeCount') -and $PSBoundParameters.ContainsKey('RelativeUnit') -and $PSBoundParameters.ContainsKey('RelativeDirection'))) { Write-Error "Relative criteria require -RelativeCount, -RelativeUnit and -RelativeDirection." return } $body.valueMode = 'Relative' $body.relativeCount = $RelativeCount $body.relativeUnit = $RelativeUnit $body.relativeDirection = $RelativeDirection } if ($PSCmdlet.ShouldProcess("Scoping Criteria Group $GroupId", "Add Criterion ($attrDisplay $ComparisonType)")) { Write-Verbose "Creating criterion in group $GroupId for Synchronisation Rule $SyncRuleId" try { # The save gate (#2055 Phase 4b): what to do if the change stops configuration test cases passing. if ($SaveAnyway) { $body.saveAnyway = $true } if ($AcceptNewResult) { $body.acceptNewResults = $true } $result = Invoke-JIMApi -Endpoint "/api/v1/synchronisation/sync-rules/$SyncRuleId/scoping-criteria/$GroupId/criteria" -Method 'POST' -Body $body # Something the administrator should know about the criterion as saved, such as an expression compared # against a relative date costing a full pass on every Temporal Scope Reconciliation. if ($result.notice) { Write-Warning $result.notice } Write-Verbose "Created criterion ID: $($result.id)" if ($PassThru) { $result | Add-Member -NotePropertyName 'SyncRuleId' -NotePropertyValue $SyncRuleId -Force $result | Add-Member -NotePropertyName 'GroupId' -NotePropertyValue $GroupId -PassThru -Force } } catch { Write-Error "Failed to create criterion: $_" } } } } |