AddNoteProperty.psm1
<#
.SYNOPSIS This function will allow you to create very complex PSCustomObject's easily. .PARAMETER InputObject The base object to add the properties or property to. .PARAMETER Properties String array of properties to add to the object. Each Element in the array is added as a sub-object, until the last one, which adds the value property. .PARAMETER Value The object value to add for the value property of the very last element in Properties. .PARAMETER ArrayProperty The name of the property in the chain that is an array. The first element in the item for the array must be marked with -IsNew. Note: Arrays can only be ADDED to. If you wish to edit an item in an array then pass in the individual item into the -InputObject. .PARAMETER IsNew Switch that signifies this is the start of an an array object. Has not impact if ArrayProperty is not set .PARAMETER hasChanged OPTIONAL: If the object is changed in any way the value will be flipped to true. Will not flip back to false inside the function. Can be reset to false outside of the function. .EXAMPLE Overwrites an existing property on an object with a new value $obj = [PSCustomObject]@{ Testing = "foo"} Add-NoteProperty -InputObject $obj -Properties "Testing" -Value "bar" .EXAMPLE Adds a complex structure onto an object $obj = [PSCustomObject]@{ } Add-NoteProperty -InputObject $obj -Properties "Person", "Name", "First" -Value "Tim" Add-NoteProperty -InputObject $obj -Properties "Person", "Name", "Last" -Value "Cartwright" Add-NoteProperty -InputObject $obj -Properties "Person", "Age" -Value "Old" Add-NoteProperty -InputObject $obj -Properties "Person", "Phones", "Home" -Value "281-867-5309" Add-NoteProperty -InputObject $obj -Properties "Person", "Phones", "Mobile" -Value "713-867-5309" Add-NoteProperty -InputObject $obj -Properties "Person", "Address", "City" -Value "Houston" Add-NoteProperty -InputObject $obj -Properties "Person", "Address", "State" -Value "Texas" Add-NoteProperty -InputObject $obj -Properties "Person", "Address", "Zip" -Value "8675309" $obj | ConvertTo-JSON .EXAMPLE Keeps track of whether or not the function made any changes to the object. Useful to determine you are changing a pre-existing object, and need to know whether to save it or not. [bool]$changed = $false $obj = [PSCustomObject]@{ } Add-NoteProperty -InputObject $obj -Properties "Testing" -Value "foo" -hasChanged ([ref]$changed) #test has changed Add-NoteProperty -InputObject $obj -Properties "Testing" -Value "bar" -hasChanged ([ref]$changed) #test property that pre-exist Add-NoteProperty -InputObject $obj -Properties "Testing" -Value "bar" -hasChanged ([ref]$changed) #test haschanged not flipping back on nil change $obj | ConvertTo-JSON .NOTES original code from here: https://stackoverflow.com/a/57183818/1988507 rewritten to allow very complex object creation original author: https://stackoverflow.com/users/5650875/j-peter #> function Add-NoteProperty { param( [Parameter(Mandatory=$true, ValuefromPipeline=$True)] [object]$InputObject, [Parameter(Mandatory=$true)] [string[]]$Properties, [Parameter(Mandatory=$true)] [object]$Value, [string]$ArrayProperty, [switch]$IsNew, [ref]$hasChanged ) begin { #only test for changes if they passed in haschanged, and its false. once true, ignore. if ($hasChanged -and !$hasChanged.Value) { $InputObjectClone = $InputObject | ConvertTo-Json -Compress } } process { $obj = $InputObject # loop all but the very last property $propNames = New-Object System.Collections.ArrayList foreach ($p in ($Properties | Select-Object -SkipLast 1)) { $propNames.Add($p) | Out-Null } for($x = 0; $x -lt $propNames.Count; $x++) { $propName = $propNames[$x] $isArray = [bool]($ArrayProperty -and $ArrayProperty -ieq $propName) $ParentIsArray = $false if ($x -gt 0) { $ParentIsArray = [bool]($ArrayProperty -and $ArrayProperty -ieq $propNames[($x - 1)]) } if ($ParentIsArray) { if ($IsNew.IsPresent) { $tmpObj = (New-Object PSCustomObject) } else { $tmpObj = $obj | Select-Object -Last 1 } if (!($tmpObj | Get-Member -MemberType NoteProperty -Name $propName)) { $tmpObj | Add-Member NoteProperty -Name $propName -Value (New-Object PSCustomObject) } $obj.Add($tmpObj) | Out-Null $obj = $tmpObj } else { if (!($obj | Get-Member -MemberType NoteProperty -Name $propName)) { if ($isArray) { $obj | Add-Member NoteProperty -Name $propName -Value (New-Object System.Collections.ArrayList) $obj = $obj.$propName } else { $obj | Add-Member NoteProperty -Name $propName -Value (New-Object PSCustomObject) $obj = $obj.$propName } } else { $obj = $obj.$propName } } } # add the very last property using the $value, or update it if it already exists $propName = ($Properties | Select-Object -Last 1) $propertyIsArray = [bool]($ArrayProperty -and $ArrayProperty -ieq $propName) $ParentIsArray = [bool]($ArrayProperty -and $ArrayProperty -ieq $Properties[-2]) if ($propertyIsArray) { if ($IsNew.IsPresent) { $tmpObj = New-Object System.Collections.ArrayList $tmpObj.Add($Value) | Out-Null if (!($obj | Get-Member -MemberType NoteProperty -Name $propName)) { $obj | Add-Member NoteProperty -Name $propName -Value $tmpObj } } else { $obj.$propName.Add($Value) | Out-Null } } elseif ($ParentIsArray) { if ($IsNew.IsPresent) { $tmpObj = (New-Object PSCustomObject) $obj.Add($tmpObj) | Out-Null } else { $tmpObj = $obj | Select-Object -Last 1 } if (!($tmpObj | Get-Member -MemberType NoteProperty -Name $propName)) { $tmpObj | Add-Member NoteProperty -Name $propName -Value $Value } } else { if (!($obj | Get-Member -MemberType NoteProperty -Name $propName)) { $obj | Add-Member NoteProperty -Name $propName -Value $Value } else { $obj."$propName" = $value } } } end { if ($hasChanged -and !$hasChanged.Value) { $hasChanged.Value = [bool]($InputObjectClone -ine ($InputObject | ConvertTo-Json -Compress)) } } } |