I have a compiled Cmdlet
that works with Hashtable
s. I would like to write a [pscustomobject]
of the hashtable to the pipeline. In a PowerShell script block that would be accomplished using the following cast:
[pscustomobject]$hashtable
I would like to accomplish the same from a compiled Cmdlet
. The natural implementation would be
using System.Collections;
using System.Management.Automation;
[Cmdlet(VerbsData.Out,"PsCustomObject")]
public class OutPsCustomObjectCommand : PSCmdlet {
[Parameter(Mandatory = true)]
public Hashtable Hashtable { get; set; }
protected override void ProcessRecord() {
WriteObject(new PSCustomObject(Hashtable));
}
}
however, PSCustomObject
has no public constructor.
I thought new PSObject()
might be equivalent, but WriteObject(new PSObject(Hashtable))
differs enough from [pscustomobject]$hashtable
that they aren't even shown the same in the console:
PS\> Out-PsCustomObject -Hashtable @{ a='aye' }
Name Value
---- -----
a aye
PS\> [pscustomobject]@{ a = 'aye' }
a
-
aye
How can I output a PSCustomObject
from a compiled Cmdlet
?
I have a compiled Cmdlet
that works with Hashtable
s. I would like to write a [pscustomobject]
of the hashtable to the pipeline. In a PowerShell script block that would be accomplished using the following cast:
[pscustomobject]$hashtable
I would like to accomplish the same from a compiled Cmdlet
. The natural implementation would be
using System.Collections;
using System.Management.Automation;
[Cmdlet(VerbsData.Out,"PsCustomObject")]
public class OutPsCustomObjectCommand : PSCmdlet {
[Parameter(Mandatory = true)]
public Hashtable Hashtable { get; set; }
protected override void ProcessRecord() {
WriteObject(new PSCustomObject(Hashtable));
}
}
however, PSCustomObject
has no public constructor.
I thought new PSObject()
might be equivalent, but WriteObject(new PSObject(Hashtable))
differs enough from [pscustomobject]$hashtable
that they aren't even shown the same in the console:
PS\> Out-PsCustomObject -Hashtable @{ a='aye' }
Name Value
---- -----
a aye
PS\> [pscustomobject]@{ a = 'aye' }
a
-
aye
How can I output a PSCustomObject
from a compiled Cmdlet
?
- 1 Just added additional info using a new method to the answer – Santiago Squarzon Commented 2 days ago
1 Answer
Reset to default 3You're kinda close, first you need to create a PSObject
and then, for each DictionaryEntry
on the hash table, you need to add a new PSNoteProperty
to said object and lastly output it.
NOTE: The following does not ensure ordering on the PSCustomObject
properties, what [pscustomobject]@{ .... }
achieves preserving the order of the hash table key / value pairs is all done via AST parsing at runtime. Cannot be achieved via already created hash table.
If you needed to preserve the order then you could change the parameter to:
public IDictionary IDictionary { get; set; }
And pass-in an OrderedDictionary
, like so:
Out-PsCustomObject ([ordered]@{ foo = 'bar'; baz = 'hello' })
Also worth noting, what the [ordered]
accelerator does has the same AST parsing used in [pscustomobject]
to preserve ordering via hash table literal (@{ ... }
) instantiation.
using System.Collections;
using System.Management.Automation;
[Cmdlet(VerbsData.Out, "PsCustomObject")]
public class OutPsCustomObjectCommand : PSCmdlet
{
[Parameter(Mandatory = true, Position = 0)]
public Hashtable Hashtable { get; set; }
protected override void ProcessRecord()
{
PSObject output = new();
foreach (DictionaryEntry kv in Hashtable)
{
output.Properties.Add(new PSNoteProperty(
LanguagePrimitives.ConvertTo<string>(kv.Key), kv.Value));
}
WriteObject(output);
}
}
EDIT
After further inspecting the PowerShell source (see Mshexpression.cs#L353-L371
), there is a perhaps shorter way to create a pscustomobject
from a hash table or any other IDictionary
type using LanguagePrimitives.ConvertPSObjectToType
, however, the notes mentioned before still remain, this does not ensure property ordering.
using System.Collections;
using System.Management.Automation;
[Cmdlet(VerbsData.Out, "PsCustomObject")]
public class OutPsCustomObjectCommand : PSCmdlet
{
[Parameter(Mandatory = true, Position = 0)]
public IDictionary IDictionary { get; set; }
protected override void ProcessRecord() =>
WriteObject(LanguagePrimitives.ConvertPSObjectToType(
valueToConvert: PSObject.AsPSObject(IDictionary),
resultType: typeof(PSObject),
recursion: false,
formatProvider: null,
ignoreUnknownMembers: true));
}