internal/functions/sync/Get-SyncDataOperation.ps1
|
function Get-SyncDataOperation { <# .SYNOPSIS Disable user's license .DESCRIPTION Disable user's Office 365 subscription .PARAMETER ReferenceObjectList UserPrincipalName, Mail or Id of the user attribute populated in tenant/directory. .PARAMETER DiferenceObjectList Office 365 product GUID is identified using a GUID of subscribedSku. .PARAMETER MatchProperty Friendly name Office 365 product of subscribedSku. .PARAMETER DiferenceObjectUniqueKeyName Friendly name Office 365 product of subscribedSku. .PARAMETER EnableException This parameters disables user-friendly warnings and enables the throwing of exceptions. This is less user frien dly, but allows catching exceptions in calling scripts. .PARAMETER WhatIf Enables the function to simulate what it will do instead of actually executing. .PARAMETER Confirm Prompts for confirmation before the command makes a change. -Confirm:$false suppresses that prompt. Left unbound, the decision belongs to this command's ConfirmImpact and the session ConfirmPreference, which is the PowerShell default behaviour. .EXAMPLE PS C:\> Get-SyncDataOperation -ReferenceObjectList $referenceMemberList -DiferenceObjectList $differenceMemberList -MatchProperty Id -DiferenceObjectUniqueKeyName Id Get sync operation #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'The rule fires on the nested New-Result factory, which builds a result object and changes nothing. The outer function is a Get that computes a diff in memory.')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPositionalParameters', '', Justification = 'Compare-Hashtable and New-Result are function-local helpers called positionally within the same screenful of code; naming their two arguments adds noise, not safety.')] [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, PositionalBinding = $false, HelpUri = 'http://www.microsoft.com/', ConfirmImpact = 'Medium')] [Alias()] [OutputType([String])] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, Position = 0, ParameterSetName = 'Default')] [AllowNull()] [Alias("Rol")] [Array] $ReferenceObjectList, [Parameter(Mandatory = $true, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, Position = 1, ParameterSetName = 'Default')] [AllowNull()] [Alias("Dol")] [Array] $DiferenceObjectList, [Parameter(Mandatory = $true, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, Position = 3, ParameterSetName = 'Default')] [ValidateNotNullOrEmpty()] [String] $MatchProperty, [Parameter(Mandatory = $true, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, ValueFromRemainingArguments = $false, Position = 4, ParameterSetName = 'Default')] [AllowNull()] [ValidateNotNullOrEmpty()] [String] $DiferenceObjectUniqueKeyName ) Begin { function ConvertTo-HashtableFromPsCustomObject { param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [object[]]$psCustomObject ); process { foreach ($myPsObject in $psCustomObject) { $output = @{}; $myPsObject | Get-Member -MemberType *Property | ForEach-Object { $output.($_.name) = $myPsObject.($_.name); } $output; } } } function Compare-Hashtable { <# .SYNOPSIS Compare two Hashtable and returns an array of differences. .DESCRIPTION The Compare-Hashtable function computes differences between two Hashtables. Results are returned as an array of objects with the properties: "key" (the name of the key that caused a difference), "side" (one of "<=", "!=" or "=>"), "lvalue" an "rvalue" (resp. the left and right value associated with the key). .PARAMETER left The left hand side Hashtable to compare. .PARAMETER right The right hand side Hashtable to compare. .EXAMPLE Returns a difference for ("3 <="), c (3 "!=" 4) and e ("=>" 5). Compare-Hashtable @{ a = 1; b = 2; c = 3 } @{ b = 2; c = 4; e = 5} .EXAMPLE Returns a difference for a ("3 <="), c (3 "!=" 4), e ("=>" 5) and g (6 "<="). $left = @{ a = 1; b = 2; c = 3; f = $Null; g = 6 } $right = @{ b = 2; c = 4; e = 5; f = $Null; g = $Null } Compare-Hashtable $left $right #> [CmdletBinding()] param ([Parameter(Mandatory = $true)] [Hashtable]$Left, [Parameter(Mandatory = $true)] [Hashtable]$Right ) function New-Result($Key, $LValue, $Side, $RValue) { New-Object -Type PSObject -Property @{ key = $Key lvalue = $LValue rvalue = $RValue side = $Side } } [Object[]]$Results = $Left.Keys | ForEach-Object { if ($Left.ContainsKey($_) -and !$Right.ContainsKey($_)) { New-Result $_ $Left[$_] "<=" $Null } else { $LValue, $RValue = $Left[$_], $Right[$_] if ($LValue -ne $RValue) { New-Result $_ $LValue "!=" $RValue } } } $Results += $Right.Keys | ForEach-Object { if (!$Left.ContainsKey($_) -and $Right.ContainsKey($_)) { New-Result $_ $Null "=>" $Right[$_] } } $Results } $compareList = Compare-Object -ReferenceObject @($ReferenceObjectList | Select-Object) -DifferenceObject @($DiferenceObjectList | Select-Object) -Property $MatchProperty -IncludeEqual } Process { if ($pscmdlet.ShouldProcess("Target", "Operation")) { [System.Collections.ArrayList]$changeList = [System.Collections.ArrayList]::new() foreach ($compareItem in $compareList) { switch ($compareItem.SideIndicator) { '==' { $differenceObject = ($DiferenceObjectList.Where({ $_.$($MatchProperty) -eq $compareItem.$($MatchProperty) })[0]) | ConvertTo-HashtableFromPsCustomObject $referenceObject = ($ReferenceObjectList.Where({ $_.$($MatchProperty) -eq $compareItem.$($MatchProperty) })[0]) | ConvertTo-HashtableFromPsCustomObject $compareProperties = Compare-Hashtable $referenceObject $differenceObject # Compare-Hashtable emits NOTHING when the two sides are identical, # and identical is the ordinary case here - every member that is # already in both groups lands in this branch. Reaching straight # for .GetType() on that result turned "nothing to do" into # "You cannot call a method on a null-valued expression", so the # branch could only survive as long as it was unreachable. [System.Collections.ArrayList]$comparePropertyList = [System.Collections.ArrayList]::new() foreach ($compareProperty in @($compareProperties)) { if ($null -ne $compareProperty) { [void]$comparePropertyList.Add($compareProperty) } } $propertyHash = @{} foreach ($property in $comparePropertyList) { if ($property.side -eq '!=') { [void]($propertyHash.Add($property.Key, $property.lvalue)) } } if ($propertyHash.Count -gt 0) { $changeObject = [pscustomobject]@{ Crud = 'Update' IdentityValue = $differenceObject.$($DiferenceObjectUniqueKeyName) IdentityName = $DiferenceObjectUniqueKeyName Fields = $propertyHash } [void]($changeList.Add($changeObject)) } } '<=' { $referenceObject = ($ReferenceObjectList.Where({ $_.$($MatchProperty) -eq $compareItem.$($MatchProperty) })[0]) | ConvertTo-HashtableFromPsCustomObject $propertyHash = @{} $changeObject = [pscustomobject]@{ Crud = 'Create' IdentityValue = "-1" IdentityName = $DiferenceObjectUniqueKeyName Fields = $referenceObject } [void]($changeList.Add($changeObject)) } '=>' { $differenceObject = ($DiferenceObjectList.Where({ $_.$($MatchProperty) -eq $compareItem.$($MatchProperty) })[0]) | ConvertTo-HashtableFromPsCustomObject $changeObject = [pscustomobject]@{ Crud = 'Delete' IdentityValue = $differenceObject.$($DiferenceObjectUniqueKeyName) IdentityName = $DiferenceObjectUniqueKeyName Fields = @{} } [void]($changeList.Add($changeObject)) } Default {} } } } } End { $changeList } } |