I needed to create custom objects with specific properties for programming against a WPF GUI, because WPF programming is simplest when it binds properties of controls to properties of an object. But I loathed the thought of writing a function to create a custom object, and having to duplicate the parameter name as a Property name in the new-object call. I also wanted to have default values for the object’s Properties.
The following solution is a template – Use it when you need a New-BlahBlahObject function. Simply add the parameters you want to the Param() block, and this function will hand you back a PSObject with the Parameters turned into Properties. As a bonus, the ParameterSetName property allows you to use this as a kind of object factory – depending on which arguments you supply, different Properties will get created, and the value of the ParameterSetName will tell you which properties are present.
You can do a lot more customization before the call to new-object in the last line of the function, by modifying the $p2 string. You can also add functions to the object before you return it, like Add, so you can “add” two of these custom objects together.
[Author’s note: If anybody know how to add a “code” widget to a Blogger Blog, please tell me so in a comment!. The following formatting is terrible… I hope word-wrap doesn’t prevent cut’n’paste from working]
function New-CustomDemoObject {
[CmdletBinding(DefaultParametersetName='All')]
Param (
[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] $Workbook = 'T1.xlsx'
,[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][switch] $isVisible
,[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][switch] $isKeepOpen
,[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string] $SortDirection = 'Ascending'
,[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string[]] $DatabaseConnectionStrings = @('connecstr1','connectstr2')
,[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] $ParameterWithDefaultArray = @('connecstr5','connectstr6')
,[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][hashtable] $CommandStringsHash = @{cmd1=@{cmdstr='a command';vo=1;so=2};cmd2=@{cmdstr='b command';vo=2;so=1}}
,[parameter(ParameterSetName='PathToDir',ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] $PathToDir = 'C:/Logs'
,[parameter(ParameterSetName='PathToZip',ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] $PathToZip = 'C:/Logs/Backups'
,[parameter(ParameterSetName='PathToZip',ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] $PathInZip = './'
,[parameter(Position=0, ValueFromRemainingArguments=$true)] $RemainingArgs
)
# Snippet that creates an object from the parameters
# Create a list of the common parameters as a RegExp match string
$cp = iex 'function gcp{[CmdletBinding()]Param()$p1=@();((gci Function:$($pscmdlet.MyInvocation.MyCommand)).Parameters).Keys|%{$p1+=$_};$p1|%{"^$_`$"}};[string]::join("|",(gcp))'
# Get a list of this function's parameters, eliminate the commonparameters, make a hash with the parameter name and type
$p1=@{};((gci Function:$($pscmdlet.MyInvocation.MyCommand)).Parameters).Keys|?{$_ -notmatch $cp}|%{$p1.$_=((gci Function:$($pscmdlet.MyInvocation.MyCommand)).Parameters).$_.ParameterType.Name}
# Iterate this function's real parameters, turn switches to bools, remove ActionPreference (and you can do whatever else you want to in this loop)
$p2=$p1.Clone();$p1.Keys|%{$key=$_;switch ($p1.$_) {'SwitchParameter' {$p2.$key='Bool';break}'ActionPreference' {$p2.Remove($key);break}}}
# Add the parameterset as a property (Tells you which parameters are present), and create a new object using the hash of argument names and values
# This version of the last line creates strongly-typed Properties, but won't handle Parameters/Properties of type arrary or hashtable
# new-object psObject -Property (&(iex $('{@{ParameterSet=[string]'+ "'$($PsCmdlet.ParameterSetName)';" +[string]::join(";",($p2.Keys|%{("{0}="-f $_+'['+$p2.$_+']'+'"$'+$_ +'"')}))+'}}')))
# This version of the last line creates untyped Properties, and does handle hashtables and arrays. see also this blog https://jamesone111.wordpress.com/2011/01/11/why-it-is-better-not-to-use-powershell-parameter-validation/
new-object psObject -Property (&(iex $('{@{ParameterSet=[string]'+"'$($PsCmdlet.ParameterSetName)';"+[string]::join(";",($p2.Keys|%{("{0}="-f $_+"`$$_")}))+'}}')))
}
$newobj1 = New-CustomDemoObject # If none of the specific ParamterSet arguments are supplied, the default ParamterSetName 'All' causes all parameters to be created on the PsObject as empty Properties
$newobj2 = New-CustomDemoObject -Workbook 'another.xlsx' -PathToDir 'D:\Logs'
$newobj3 = New-CustomDemoObject -isVisible -PathToZip 'D:\Logs\Backups'
#$newobj4 = New-CustomDemoObject -Workbook 'another.xlsx' -PathToZip 'D:\Logs\Backups' -PathToDir 'D:\Logs' # Uncomment this - you will see an error about paramterset cannot be resolved
# Type $newobj1 ( and $newobj2, and $newobj3) at the comamnd prompt to see the objects that got created
No comments:
Post a Comment