Store an integer in a custom object with powershell

Viewed 2317

I like to use constructs like the following in powershell. They make following what is happening 6 months later a lot easier.

$processConfig = New-Object -TypeName psobject
$processConfig | Add-Member -MemberType NoteProperty -Name StartDate -Value ($startofweek)
$processConfig | Add-Member -MemberType NoteProperty -Name StartDateStr -Value (Get-Date $processConfig.StartDate -Format "yyyyMMdd HH:mm:ss")
$processConfig | Add-Member -MemberType NoteProperty -Name EndDate -Value ($endofweek)
$processConfig | Add-Member -MemberType NoteProperty -Name EndDateStr -Value (Get-Date     $processConfig.EndDate -Format "yyyyMMdd HH:mm:ss")
$processConfig | Add-Member -MemberType NoteProperty -Name TargetDir -Value  "C:\Scripts\out\"

$dbConfig = New-Object -TypeName psobject
$dbConfig | Add-Member -MemberType NoteProperty -Name Server -Value "server.address"
#etc

However, I cannot for the life of me figure out how to store a plain int as a property. I've tried a few different things.

Requires a MemberType

$processConfig | Add-Member -TypeName System.Int32 -Name TrimLeadingLines -Value 3

Then why is Property a suggested value for the argument?

$processConfig | Add-Member -MemberType Property -TypeName System.Int32 -Name TrimLeadingLines -Value 3

Add-Member : Cannot add a member with type "Property". Specify a different type for the MemberTypes parameter.
At C:\Scripts\kh_tca_export_ftps.ps1:80 char:18
+ ... essConfig | Add-Member -MemberType Property -TypeName System.Int32 -N ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Add-Member], InvalidOperationException
    + FullyQualifiedErrorId : CannotAddMemberType,Microsoft.PowerShell.Commands.AddMemberCommand

Thinking sideways, but a bit dodgy

$processConfig | Add-Member -MemberType ScriptProperty -TypeName System.Int32 -Name TrimLeadingLines -Value { return 3 }

I do not want to store a string representation I then need to cast. Yes i can use a $var. Is there a simple straightforward way to store an Integer/Int32 in Powershell Custom Object?

2 Answers

I have always done [int]3 as per below. Works well when I need to store an int in an object.

$processConfig | Add-Member -MemberType NoteProperty -Name TrimLeadingLines -Value $([int]3)

This returns an Int32 as the property type.

PS C:\> $processConfig.TrimLeadingLines.GetType()

IsPublic IsSerial Name  BaseType        
-------- -------- ----  --------        
True     True     Int32 System.ValueType

tl;dr

-Value 3 implicitly creates an [int] property - no extra effort required:

$processConfig | Add-Member -MemberType NoteProperty -Name TrimLeadingLines -Value 3

  • Whatever data type the -Value argument has becomes the new property's data type.

    • A numeric literal such as 3, which fits into the [int] (System.Int32) type's range, is implicitly [int] typed, so no further action is needed for creating an [int]-typed NoteProperty.

    • To coerce to a different type, use an expression with a cast; e.g., -Value ([long] 3)

  • The -TypeName argument does not control a newly added property's data type; instead, it assigns an - arbitrary, self-chosen - type name to the input object, as reflected in the object's .pstypenames array afterwards (as the first element) and as also reflected when you pipe the object to Get-Member afterwards.

    • Such self-assigned type names are part of PowerShell's ETS (Extended Type System) - see about_Types.ps1xml

why is Property a suggested value for the [-MemberType] argument?

The data type of the mandatory -MemberType parameter is [System.Management.Automation.PSMemberTypes], an enumeration type that is used not just by Add-Member, but also by other cmdlets, such as Get-Member, where preexisting members are targeted by type.

  • In the context of Add-Member's -MemberType parameter, enumeration value Property is not a valid option, because it refers to a .NET type's innate properties, and those cannot be added to.

  • With Add-Member you can only decorate existing .NET type instances, and are therefore limited to a subset of the enumeration values in [System.Management.Automation.PSMemberTypes].
    Notable ones are:

    • NoteProperty (property with static value)
    • ScriptProperty (a calculated property whose value is determined by a script block's output)
    • ScriptMethod (a method whose return value is determined by a script block's output)
    • CodeProperty / CodeMethod (a property / method whose (return) value is determined by a .NET type's static method).

Tab completion for Add-Member's -MemberType parameter has no way of knowing what particular subset of the [System.Management.Automation.PSMemberTypes]enumeration values Add-Member is restricted to, because that information isn't in the parameter declaration; however, the documentation does list the subset explicitly.

Related