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?

Parents
  • 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

Reply
  • 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

Children
No Data