This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Full object replace for the PowerShell connector

When integrating with a system via the PowerShell connector, is there an option to configure "Object Replace" where the entire object is sent to configured custom commands rather than just the properties that have been modified?

  • How about marking all properties as mandatory? In that case every property will be sent when I am remembering it correctly.
  • Hi Markus,

    I have tested by adding the IsMandatory="true" attribute to the property definition, as well as setting the parameter as mandatory in the PowerShell function that it calls (configured with the ModBy) but neither/both don't seem to make a difference.

    Obviously if I set it as a mandatory parameter it causes an exception to be thrown due to the value not being present on the function call but in both scenarios it seems that only properties that have been modified are available. I have seen similar situations with the Native DB connector as well whereby only those properties that have been modified as part of the current event are present.


    Thanks
  • Hi Craig,

    i searched again and found a different approach to your problem. The following is the answer to a very similar question for the AdHoc-Update.

    ---------

    The sync engine itself just sends only the modifications to the connector. You can use the "ForceSyncOf" JobRunParameter to force the engine send a modification anyway. But I'd use a different approach...

    The PowerShell connector was developed during the exchange connector implementation and was meant to deal with systems, that actually have a PowerShell module. Usually, native commandlets do NOT require every possible parameter to be set. Imagine you'd had to set each parameter of Set-Mailbox in Exchange for every call.

    The "problem" is, that the PowerShell connector is also used for connecting systems, that do not really have dedicated PowerShell module/snapin. I often see people consuming web services with the Powershell connector. That is perfectly fine, but then, you need to write your CustomCommandlets in a way, a "out of the box" cmdlet would look like. So my approach would be, to have an "Set-" commandlet that internally loads the object to be modified from the system, and construct the webservice call by using the values just loaded modified by the parameters that were actually set.

    Pseudo Sample (with comments)

    function Set-User
    {
        param (
            [parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
            [ValidateNotNullOrEmpty()]
            [String]$Identity,

            [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
            [String]$Firstname,
            
            [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
            [String]$LastName,
            
            [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
            [String]$Description
        )
        
        # 1. Load User to get current values
        # i.e. $usr = Get-User -Identity $Identity
        
        # We use a custom object for demo purposes here
        $currentValues = @{Identity = "Jon.Doe"; FirstName = "Jon"; LastName = "Doe"; Description = "A description"}
        $usr = New-Object -TypeName PSObject -Property $currentValues
        
        # 2. Constuct parameters for the actual update commandlet (using parameter splatting https://technet.microsoft.com/en-us/library/gg675931.aspx )
        #    = Create a dictionary that has all the parameters for commandlet to be called
        
        $parms = @{"Identity" = $Identity}
        
        # was Firstname set? (easy but long version)
        # use $PSBoundParameters dictionary to check, if parameter was passed
        If($PSBoundParameters.ContainsKey('Firstname'))
        {
            # Use Firstname from parameter
            $parms.Add("Firstname",$Firstname)
        }
        else
        {
            # Use Firstname from existing object
            $parms.Add("Firstname",$usr.Firstname)
        }

        # were Lastname/Description set
        # To get the if/then into a one-liner, use an index trick
        $parms.Add("LastName", @{$true = $LastName ; $false = $usr.LastName}[$PSBoundParameters.ContainsKey('LastName')])
        $parms.Add("Description", @{$true = $Description ; $false = $usr.Description}[$PSBoundParameters.ContainsKey('Description')])
        
        #output parameters (just to debug)
        $parms
        
        #call "update" commandlet with constructed parameters
        #Call-Service @parms
    }


    Pseudo Sample (shortened)

    function Set-User
    {
        param (
            [parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
            [ValidateNotNullOrEmpty()]
            [String]$Identity,

            [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
            [String]$Firstname,
            
            [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
            [String]$LastName,
            
            [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
            [String]$Description
        )
        
        $usr = Get-User -Identity $Identity
        $parms = @{"Identity" = $Identity}
        $parms.Add("Firstname", @{$true = $Firstname ; $false = $usr.Firstname}[$PSBoundParameters.ContainsKey('Firstname')])
        $parms.Add("LastName", @{$true = $LastName ; $false = $usr.LastName}[$PSBoundParameters.ContainsKey('LastName')])
        $parms.Add("Description", @{$true = $Description ; $false = $usr.Description}[$PSBoundParameters.ContainsKey('Description')])
        
        Call-Service @parms
    }

    Hope that helps

  • Thanks Markus,

    I expected that to be the answer to the problem. In some situations where OneIM is completely authoritative it might make more sense to read back to the OneIM DB ( save expensive WAN network calls for example) but the premise would be the same.

    Is there a chance that an Object Replace type configuration might become available? Whilst it might be possible to emulate an object replace using the ForceSyncOf process parameter (or forward or backwards lookups) it could get messy (with parameters or processes) on generic tables such as UNSAccountB. It would certainly be nicer to have a configuration check box in the generic connectors to enable this type of update.

    Would it be a better approach to use a more standard Web Services integration approach and forgo the use of the PowerShell (and target system sync) all together? Obviously the use of one of the generic connectors affords a lot of benefits in terms of sync processing, logging, attribute mapping etc but there are a lot of web service (and other API’s) that are written for object replace rather than discrete updates.

    Thanks