Public/Metaverse/Get-JIMMetaverseObjectConnection.ps1
|
# Copyright (c) Tetron Limited. All rights reserved. # Licensed under the Tetron Commercial License. See LICENSE file in the project root. function Get-JIMMetaverseObjectConnection { <# .SYNOPSIS Explains why a Metaverse Object is connected where it is, and why it is not connected elsewhere. .DESCRIPTION Returns one object per Connected System Object joined to the Metaverse Object: how it was joined (method, Synchronisation Rule, date and Activity) and the scoping of every relevant enabled Synchronisation Rule, evaluated now against current values. With -IncludeNotConnected, also returns one object per enabled export Synchronisation Rule whose Connected System holds no object joined to this one, with the reason (NotInScope, ProvisioningDisabled, RuleMisconfigured or NotYetProvisioned), a one-line hint, what would change it, and a plain-text summary to paste into a ticket. The words are generated by JIM and are the ones the portal's Connections tab shows. Every object has the same top-level properties, so connections and not-connected entries can be listed, filtered and sorted together. Values of credential attributes are withheld. .PARAMETER Id The ID of the Metaverse Object. .PARAMETER ConnectedSystemName Returns only the entries for the Connected System with this name, matched exactly but ignoring case. Nothing matching is an error. .PARAMETER IncludeNotConnected Also explains each enabled export Synchronisation Rule whose Connected System holds no object joined to this one. .OUTPUTS One object per entry: each joined Connected System Object and, with -IncludeNotConnected, each export Synchronisation Rule that has not connected. Every entry has the same properties, so the two can be listed, filtered and sorted together. Values of credential attributes are withheld. JIM.MetaverseObjectConnectionEntry MetaverseObjectId (guid): The unique identifier of the Metaverse Object. MetaverseObjectName (string): The Metaverse Object's display name. ConnectedSystem (string): The Connected System's name. ConnectedSystemId (int): The unique identifier of the Connected System. Connected (bool): $true for a joined Connected System Object, $false for an export Synchronisation Rule that has not connected. Object (string): The joined Connected System Object's identifier as the portal's Connections tab shows it: its Secondary External ID (for an LDAP Connected System, its distinguished name) where it has one, otherwise its External ID, falling back to the value a queued Pending Export will assign; empty when not connected. ConnectedSystemObjectId (guid): The unique identifier of the joined Connected System Object; empty when not connected. ExternalId (string): The joined object's External ID; empty when it has none yet or when not connected. SecondaryExternalId (string): The joined object's Secondary External ID; empty when its Connected System has none, it has no value yet, or when not connected. PendingExternalId (string): The External ID a queued Pending Export will give the joined object, where it has none yet; empty otherwise. PendingSecondaryExternalId (string): The Secondary External ID a queued Pending Export will give the joined object, where it has none yet; empty otherwise. ObjectType (string): The Connected System Object Type's name. Role (string): Source, Target, Source and Target or None, from the enabled Synchronisation Rules for that Connected System and Object Type; always Target when not connected. State (string): For a connection, its state, such as InSync or UpdatePending; when not connected, why: NotInScope, ProvisioningDisabled, RuleMisconfigured or NotYetProvisioned. SyncRule (string): The export Synchronisation Rule that has not connected; empty for a connection. Join (object): For a connection, how it was joined: JoinType, Method, DateJoined, SyncRuleId, SyncRuleName, Source, Description, ActivityId and RunProfileExecutionItemId. Hint (string): When not connected, a one-line hint at what would change it. BulletsTitle (string): When not connected, the heading for Bullets. Bullets (string[]): When not connected, what would change it, a line each. Summary (string): When not connected, a plain-text summary to paste into a ticket. Scoping (object[]): One explanation per relevant Synchronisation Rule, evaluated now against current values: SyncRuleName, Direction, Outcome, Hint, Groups and Criteria, each criterion with Path, Met, Outcome, AttributeName, ComparisonType, Expected, Actual, ValueCount, Description and ActualDescription; an expression criterion adds Expression, ExpressionInputs (each attribute it read, with Accessor, Values, ValueCount and Masked) and, when it could not be evaluated, FailureReason. Conflicts (object[]): For a connection, the export Synchronisation Rules that cannot connect because it holds the slot. EvaluatedAt (datetime): When JIM evaluated the explanations (UTC). .EXAMPLE Get-JIMMetaverseObjectConnection -Id "12345678-1234-1234-1234-123456789abc" -IncludeNotConnected | Format-Table ConnectedSystem, Connected, State, Hint Lists where the Metaverse Object is connected, and why it is not connected elsewhere. .EXAMPLE (Get-JIMMetaverseObjectConnection -Id $mvoId -IncludeNotConnected -ConnectedSystemName "Finance App").Summary Prints the plain-text explanation of why the Metaverse Object is not in Finance App, ready to paste into a ticket. .EXAMPLE Get-JIMMetaverseObjectConnection -Id $mvoId -IncludeNotConnected | ForEach-Object { $_.Scoping } | ForEach-Object { $_.Criteria } | Where-Object { -not $_.Met } | Format-Table Path, Description, ActualDescription Lists every scoping criterion the Metaverse Object currently fails, across all its rules. .EXAMPLE Get-JIMMetaverseObject -AttributeName "Account Name" -AttributeValue jsmith | Get-JIMMetaverseObjectConnection | Format-Table ConnectedSystem, Object, @{ Name = 'Joined'; Expression = { $_.Join.Description } } Pipes a Metaverse Object into the cmdlet to see how each of its connections was joined. .LINK Get-JIMMetaverseObject .LINK Get-JIMMetaverseObjectProvenance .LINK Get-JIMSyncRule #> [CmdletBinding()] [OutputType('JIM.MetaverseObjectConnectionEntry')] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Guid]$Id, [ValidateNotNullOrEmpty()] [string]$ConnectedSystemName, [switch]$IncludeNotConnected ) 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 } $endpoint = "/api/v1/metaverse/objects/$Id/connections" if ($IncludeNotConnected) { $endpoint += '?includeNotConnected=true' } Write-Verbose "Getting connection explanations for Metaverse Object $Id" $response = Invoke-JIMApi -Endpoint $endpoint if (-not $response) { # Invoke-JIMApi already wrote the error (e.g. Metaverse Object not found). return } $entries = [System.Collections.Generic.List[object]]::new() foreach ($connection in $response.Connections) { $role = if ($connection.IsSource -and $connection.IsTarget) { 'Source and Target' } elseif ($connection.IsSource) { 'Source' } elseif ($connection.IsTarget) { 'Target' } else { 'None' } $entries.Add([PSCustomObject]@{ MetaverseObjectId = $response.MetaverseObjectId MetaverseObjectName = $response.DisplayName ConnectedSystem = $connection.ConnectedSystemName ConnectedSystemId = $connection.ConnectedSystemId Connected = $true Object = @($connection.SecondaryExternalId, $connection.PendingSecondaryExternalId, $connection.ExternalId, $connection.PendingExternalId) | Where-Object { $_ } | Select-Object -First 1 ConnectedSystemObjectId = $connection.ConnectedSystemObjectId ExternalId = $connection.ExternalId SecondaryExternalId = $connection.SecondaryExternalId PendingExternalId = $connection.PendingExternalId PendingSecondaryExternalId = $connection.PendingSecondaryExternalId ObjectType = $connection.ObjectTypeName Role = $role State = $connection.State SyncRule = $null Join = $connection.Join Hint = $null BulletsTitle = $null Bullets = @() Summary = $null Scoping = @($connection.Scoping) Conflicts = @($connection.Conflicts) EvaluatedAt = $response.EvaluatedAt }) } foreach ($entry in $response.NotConnected) { $entries.Add([PSCustomObject]@{ MetaverseObjectId = $response.MetaverseObjectId MetaverseObjectName = $response.DisplayName ConnectedSystem = $entry.ConnectedSystemName ConnectedSystemId = $entry.ConnectedSystemId Connected = $false Object = $null ConnectedSystemObjectId = $null ExternalId = $null SecondaryExternalId = $null PendingExternalId = $null PendingSecondaryExternalId = $null ObjectType = $entry.ObjectTypeName Role = 'Target' State = $entry.Reason SyncRule = $entry.SyncRuleName Join = $null Hint = $entry.Hint BulletsTitle = $entry.BulletsTitle Bullets = @($entry.Bullets | ForEach-Object { $_.Text }) Summary = $entry.Summary Scoping = @($entry.Scoping) Conflicts = @() EvaluatedAt = $response.EvaluatedAt }) } if ($PSBoundParameters.ContainsKey('ConnectedSystemName')) { $matched = @($entries | Where-Object { $_.ConnectedSystem -eq $ConnectedSystemName }) if ($matched.Count -eq 0) { $hint = if ($IncludeNotConnected) { '' } else { ' Add -IncludeNotConnected to include Connected Systems it is not connected to.' } Write-Error "No connection to a Connected System named '$ConnectedSystemName' was found for Metaverse Object $Id.$hint" return } return $matched } $entries } } |