Powershell Connector: Force multiple fields to be passed to a function

I am creating a custom PowerShell connector.  Within Identity Manager, we have the departments arranged in a hierarchy.  Level 1 departments is divisions in the target system, and level 2 departments are departments in the target system.  The target system stores the department and divisions through separate endpoints.  I initially created two PowerShell schemas for Division and Department but could not filter successfully to do what I want so looking at an alternative.

I am now trying another approach, is having a wrapper function that calls the respective backend function as required.  To do this, I am wanting Identity Manager to pass through the treelevel parameter on each call.  This is where I am failing.

My XML file is this:

<?xml version="1.0" encoding="utf-8"?>
<PowershellConnectorDefinition Id="XyzConnector" Description="Xyz connector" Version="1.0">
    <PluginAssemblies/>
    <ConnectionParameters>
        <ConnectionParameter Name="Module"   Description="Module"/>
        <ConnectionParameter Name="JsonFile" Description="Data file"/>
    </ConnectionParameters>
    <Initialization>
        <PredefinedCommands>
            <Command Name="Connect-Xyz"/>
            <Command Name="Disconnect-Xyz"/>
			<Command Name="Get-XyzDeptDivisions" />
			<Command Name="Get-XyzDeptDivision" />
			<Command Name="New-XyzDeptDivision" />
			<Command Name="Set-XyzDeptDivision" />
			<Command Name="Remove-XyzDeptDivision" />
         </PredefinedCommands>
        <CustomCommands>
            <CustomCommand Name="Import-ConnectorModule">
                <![CDATA[
                    param($Module)
                    Import-Module -Force $Module
                ]]>
            </CustomCommand>
            <CustomCommand Name="Connect-TargetSystem">
                <![CDATA[
                    param($JsonFile)
                    Connect-Xyz $JsonFile
                ]]>
            </CustomCommand>
            <CustomCommand Name="Disconnect-TargetSystem">
                <![CDATA[
                    Disconnect-Xyz
                ]]>
            </CustomCommand>
        </CustomCommands>
        <EnvironmentInitialization>
            <Connect>
                <CommandSequence>
                    <Item Command="Import-ConnectorModule" Order="1">
                        <SetParameter Param="Module" Source="ConnectionParameter" Value="Module"/>
                    </Item>
                    <Item Command="Connect-TargetSystem" Order="2">
                        <SetParameter Param="JsonFile" Source="ConnectionParameter" Value="JsonFile"/>
                    </Item>
                </CommandSequence>
            </Connect>
            <Disconnect>
                <CommandSequence>
                    <Item Command="Disconnect-TargetSystem" Order="1"/>
                </CommandSequence>
            </Disconnect>
        </EnvironmentInitialization>
    </Initialization>
    <Schema>
		<Class Name="XYZDeptDivisions">
				<Properties>
					<Property Name="ID" DataType="String" IsUniqueKey="true" IsMandatory="true" AccessConstraint="ReadOnly">							
						<ReturnBindings>
							<Bind CommandResultOf="Get-XyzDeptDivisions" Path="id" />
							<Bind CommandResultOf="Get-XyzDeptDivision" Path="id" />	
							<Bind CommandResultOf="New-XyzDeptDivision" Path="id" />							
						</ReturnBindings>
						<CommandMappings>
							<Map ToCommand="Get-XyzDeptDivision" 		 Parameter="id"/>
							<Map ToCommand="New-XyzDeptDivision"         Parameter="id"/>
							<Map ToCommand="Set-XyzDeptDivision"         Parameter="id"/>
							<Map ToCommand="Remove-XyzDeptDivision"      Parameter="id"/>
						</CommandMappings>							
					</Property>				
					<Property Name="Name" DataType="String" AccessConstraint="None">
						<ReturnBindings>
							<Bind CommandResultOf="Get-XyzDeptDivisions" Path="Name" />
							<Bind CommandResultOf="Get-XyzDeptDivision" Path="Name" />
						</ReturnBindings>
						<CommandMappings>
							<Map ToCommand="New-XyzDeptDivision"  Parameter="Name"/>
							<Map ToCommand="Set-XyzDeptDivision"  Parameter="Name"/>
						</CommandMappings>	
						<ModifiedBy>
							<ModBy Command="Set-XyzDeptDivision"/>
						</ModifiedBy>						
					</Property>			
					<Property Name="TreeLevel" DataType="Int" IsMandatory="true" AccessConstraint="None">
						<ReturnBindings>
							<Bind CommandResultOf="Get-XyzDeptDivisions" Path="treelevel" />
							<Bind CommandResultOf="Get-XyzDeptDivision" Path="treelevel" />
						</ReturnBindings>
						<CommandMappings>
							<Map ToCommand="Get-XyzDeptDivision" 		 Parameter="treelevel"/>
							<Map ToCommand="New-XyzDeptDivision"         Parameter="treelevel"/>
							<Map ToCommand="Set-XyzDeptDivision"         Parameter="treelevel"/>
							<Map ToCommand="Remove-XyzDeptDivision"      Parameter="treelevel"/>
						</CommandMappings>							
					</Property>					
				</Properties>
				<ReadConfiguration>
					<ListingCommand Command="Get-XyzDeptDivisions"/>
					<CommandSequence>
						<Item Command="Get-XyzDeptDivision" Order="1"/>
					</CommandSequence>
				</ReadConfiguration>
				<MethodConfiguration>
					<Method Name="Insert">
						<CommandSequence>
							<Item Command="New-XyzDeptDivision" Order="1"/>
						</CommandSequence>
					</Method>
					<Method Name="Update">
						<CommandSequence>
							<Item Command="Set-XyzDeptDivision" Order="1" Condition="ModificationExists">
								<SetParameter Param="con" Source="GlobalVariable" Value="con"/>
							</Item>
						</CommandSequence>
					</Method>
					<Method Name="Delete">
						<CommandSequence>
							<Item Command="Remove-XyzDeptDivision" Order="1"/>
						</CommandSequence>
					</Method>
				</MethodConfiguration>
			</Class>			
    </Schema>
</PowershellConnectorDefinition>

What I am wanting is for the TreeLevel and ID to passed through to every transaction.

An example of the PowerShell function that is called is thus:

function Set-XyzDeptDivision($id, $Name, $treelevel) {
    $Log.Info("Set-DeptDivision id=$id treelevel=$treelevel Name=$Name")
    $Log.Debug("  * parameters = {0}" -f ($PSBoundParameters | ConvertTo-Json -Compress))
	switch ($treelevel) {
		# Division
		$cDivisionLevel { 
			$res = Set-XyzDivision -id $id -Division_Name $Name
		}
		$cDepartmentLevel {
			$res = Set-XyzDepartment -id $id -Department_Name $Name
		}
		default {
			$log.Debug("Why are we even here - we should never get here!")
		}
		
	}
	
}

As can be seen, depending upon the value of tree level will determine what function will perform the work.

Looking at the log file I get this:

2024-01-12 15:54:46.8529 WARN (SystemConnector Posh-03EBEE Job 4d29d931-ee60-4e09-9a91-0845e4455b00) : Returned PSObject was $null or result was empty. If calling a custom cmdlet consider throwing an exception instead of returning $null. 
2024-01-12 15:54:46.8529 INFO (XyzConnectorLog  Job 4d29d931-ee60-4e09-9a91-0845e4455b00) : Set-DeptDivision id=9b13ad76-102e-4c4b-bcdd-10bfcc8aaf04 treelevel= Name=98765 - Security Division 
2024-01-12 15:54:46.8675 INFO (XyzConnectorLog  Job 4d29d931-ee60-4e09-9a91-0845e4455b00) : Get-DeptDivision id=9b13ad76-102e-4c4b-bcdd-10bfcc8aaf04  treelevel=

This is one using version 9.

Within mappings in Identity Manager I have treelevel from the department table mapped to the PowerShell schema. 

Is this possible, or what am I missing?

Parents
  • My previous reply has been removed by the automatic forum moderation, because of an included url?

    I think you are running into the following issue.
    The sync engine transfers ONLY the changed properties.
    If you turn on the logging you can see that the sync engine always perform a related Get-CustomObject before the Set-CustomObject
    and removes all the unchanged properties even the ones that you defined as mandatory in the XML definition file.
    This behaviour is non-configurable. For more the details search for this title in the forum
    "Powershell connector and ForceSyncOf parameter"

    As a work-around you have 2-options
    1 - Mark the mandatory properties as IsMandatory="true" and IsUniqueKey="true", there are no side-effects I'm aware of by doing this.
    2 - Warp the Get-CustomObject inside the Set-CustomObject and set the mandatory properties.

Reply
  • My previous reply has been removed by the automatic forum moderation, because of an included url?

    I think you are running into the following issue.
    The sync engine transfers ONLY the changed properties.
    If you turn on the logging you can see that the sync engine always perform a related Get-CustomObject before the Set-CustomObject
    and removes all the unchanged properties even the ones that you defined as mandatory in the XML definition file.
    This behaviour is non-configurable. For more the details search for this title in the forum
    "Powershell connector and ForceSyncOf parameter"

    As a work-around you have 2-options
    1 - Mark the mandatory properties as IsMandatory="true" and IsUniqueKey="true", there are no side-effects I'm aware of by doing this.
    2 - Warp the Get-CustomObject inside the Set-CustomObject and set the mandatory properties.

Children
No Data