Public/Set-ECProperty.ps1
<#
.SYNOPSIS Adds or updates a property on pipeline objects, with optional overwrite controls and type enforcement. .DESCRIPTION Set-ECProperty ensures an object has a given NoteProperty. If it doesn't exist, it is added; if it exists, it may be updated depending on flags: - -NoOverwrite : never change an existing value - -OnlyIfNull : update only when the current value is $null - -DontEnforceType : skip type checks when updating existing properties Supports -WhatIf / -Confirm via ShouldProcess. Returns the SAME input instance for pipeline chaining. .PARAMETER Object Input object (ValueFromPipeline) that will receive or update the property. .PARAMETER Name Property name to add or update (case-insensitive). If the name differs only by case, no duplicate is created. .PARAMETER Value Value to assign when adding or updating the property. .PARAMETER NoOverwrite If specified, do not overwrite an existing value. .PARAMETER OnlyIfNull If specified, only overwrite when the existing value is $null. New properties are still added. .PARAMETER DontEnforceType If specified, skip type enforcement when updating an existing property. By default, updating a property throws if the new value's type differs from the existing property's value type. .INPUTS psobject .OUTPUTS psobject .EXAMPLE # Add, then update $obj = [pscustomobject]@{ Name='Jane' } $obj | Set-ECProperty -Name Title -Value Engineer | Out-Null $obj | Set-ECProperty -Name Title -Value Manager | Out-Null .EXAMPLE # Respect -OnlyIfNull $obj = [pscustomobject]@{ Title = $null } $obj | Set-ECProperty -Name Title -Value Engineer -OnlyIfNull .EXAMPLE # Preview changes with -WhatIf $obj | Set-ECProperty -Name Title -Value Director -WhatIf .LINK about_CommonParameters #> function Set-ECProperty { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [Parameter(Mandatory, ValueFromPipeline)] [psobject]$Object, [Parameter(Mandatory)] [string]$Name, [Parameter(Mandatory)] $Value, [switch]$NoOverwrite, [switch]$OnlyIfNull, [switch]$DontEnforceType ) process { if ($null -eq $Object) { throw "Object cannot be null." } $prop = $Object.PSObject.Properties[$Name] $target = "{0}::{1}" -f $Object.GetType().FullName, $Name if ($null -eq $prop) { # Add new NoteProperty if ($PSCmdlet.ShouldProcess($target, "Add property '$Name'")) { Add-Member -InputObject $Object -MemberType NoteProperty -Name $Name -Value $Value | Out-Null } return $Object } if (-not $prop.IsSettable) { throw "Property '$Name' is read-only on type [$($Object.GetType().FullName)]." } # Type enforcement (null-safe) if (-not $DontEnforceType -and $null -ne $Value -and $prop.TypeNameOfValue -ne $Value.GetType().FullName) { throw "Type mismatch: property '$Name' is of type [$($prop.TypeNameOfValue)], value is [$($Value.GetType().FullName)]." } # Decide whether to update if ($NoOverwrite) { return $Object } if ($OnlyIfNull -and $null -ne $Object.$Name) { return $Object } if ($PSCmdlet.ShouldProcess($target, "Set property '$Name'")) { $Object.$Name = $Value } return $Object } } |