Is it possible to initialize a .NET type with properties? Is it possible to initialize a .NET type with properties? powershell powershell

Is it possible to initialize a .NET type with properties?


Maximilian Burszley provided the crucial pointer in a comment on the question:

PowerShell's construction-by-cast-from-hashtable technique only works if the target type (also) has a constructor that is:

  • public
  • and parameter-less

The error message you're seeing implies that [Microsoft.HyperV.PowerShell.HardDiskDrive] does not have such a constructor (see bottom section for how to inspect constructors).

Assuming that a type with such a constructor has public properties that are settable, you can cast from a hashtable whose entries match any subset of these properties, where each entry's key must be the name of such a property and its value a type-compatible one (either already of the same type as the property or convertible to it).
PowerShell instantiates the type using the parameter-less constructor first, and then sets the public properties specified in the hashtable.

Here's a (somewhat contrived) example:

$obj = [System.Exception] @{  # just [Exception] works too, because 'System.' is implied  HResult = 0x8000400  Source = 'SomeModule'}

The above is the equivalent of:

$obj = New-Object System.Exception; $obj.HResult = 0x8000400; $obj.Source = 'SomeModule'

Because of the need for a parameter-less constructor, the hashtable technique is currently primarily useful for DTO-like "property bags".

If all public constructors of a given type do have parameters, the hashtable technique won't work, and you must call a constructor in order to instantiate the type - either via the static ::new method (PSv5+) or via the New-Object cmdlet; e.g., to call the (int year, int month, int day) overload of the [System.DateTime] constructor:

New-Object DateTime -ArgumentList 2018, 12, 1 # '-ArgumentList' is optional[DateTime]::new(2018, 12, 1)  # PSv5+ equivalent

For calling a single-parameter constructor, a cast may alternative be used - see next section.

However, an enhancement is coming to PowerShell Core Tip of the hat to TessellatingHeckler.that will allow use of the hashtable technique even with constructors that have parameters, as long as the set of hashtable entries matches a given constructor overload's parameters.


Generally, apart from the hashtable case discussed above, casts ([<target-type>] <operand>) and also implicit conversions work in the following scenarios, in order of consideration:

This information was gleaned from PowerShell Core's source code here.

(a) If the target type is decorated with a TypeConverterAttribute attribute that specifies a custom TypeConverter or PSTypeConverter class that supports conversion from the operand type.
Alternatively, these custom converter classes may be associated with types via PowerShell's ETS (extended type system), via Update-TypeData -TypeConverter)

(b) If the target type supports a static ::Parse() method for constructing an instance from a string:

[DateTime] '2018-12-01'# The above matches `::Parse()` overload `static datetime Parse(string s)`# However, given that there's also an overload that accepts a # System.IFormatProvider argument, PowerShell uses that in order# to use *culture-invariant* parsing.# Thus, the above is the equivalent of:[DateTime]::Parse('2018-12-01', [cultureinfo]::InvariantCulture)

More information about PowerShell's use of the invariant culture can be found in this answer.

(c) If the target type has a public constructor with a single parameter that the operand is type-identical or -compatible with:

[Exception] 'Something failed'# The above matches constructor `Exception(string message)` and is the # equivalent of:New-Object Exception -ArgumentList 'Something failed'[Exception]::new('Something failed')

(d) If the target type defines an implicit or explicit conversion operator for the operand's type.

(e) If the operand type implements the IConvertible interface for constructing an equivalent instance of the target type (which is limited to the CLR runtime types (built-in types)).


In PSv5+, it is easy to examine the constructors of a given (loaded) type: call the static ::new method, without parentheses, which lists the method overloads (signatures) of all publicly available constructors; using the example of type [System.Random]:

PS> [Random]::newOverloadDefinitions-------------------System.Random new()System.Random new(int Seed)

The presence of a new() overload - no parameters - is evidence of a parameter-less public constructor.

If there's no output at all, the implication is that the type doesn't have any public constructors.