Preventing PowerShell from wrapping value types in PSObjects

891 Views Asked by At

I have a .NET API that uses a lot of delegates. My API has a couple methods similar to the following:

public static class MyClass
{
    public static void DoSomethingWithString(Func<object> myFunc)
    {
        string myStringValue = myFunc().ToString();
        Console.WriteLine(myStringValue);
    }

    public static void DoSomethingWithDouble(Func<object> myFunc)
    {
        object unparsedValue = myFunc();
        double parsedValue = Convert.ToDouble(unparsedValue);
        Console.WriteLine(parsedValue);
    }
}

Now in PowerShell I have the following:

[MyClass]::DoSomethingWithString({ "Hello" }); # No error here
[MyClass]::DoSomethingWithDouble({ 123.4 });   # InvalidCastException - can't convert a PSObject to double

The problem is that my PowerShell scriptblock is returning a PSObject instead of the actual double value. My .NET API doesn't know anything about PowerShell, and I don't want to add a reference to PowerShell DLLs just so I can add special handling for this particular scenario.

Is there a way to get my scriptblocks to return actual value types rather than PSObjects? Or is there a PowerShell-agnostic way for my .NET library to handle PSObjects?

1

There are 1 best solutions below

0
On

PowerShell will wrap things in PSObject as it sees fit, there's no clean way to avoid that when accepting arbitrary script blocks. With some discipline, you can write script blocks that unwrap the PSObject, for example the following might work fine:

[MyClass]::DoSomethingWithDouble({ (123.4).PSObject.BaseObject })

If possible, a better option is to have your api take a delegate with a more specific return type.

public static void DoSomethingWithDouble(Func<double> myFunc)

In this case, PowerShell will convert the return value to the type expected by the delegate. When the return type is PSObject, PowerShell knows PSObject trivially converts to object so it doesn't unwrap, but if the return type is pretty much anything else, PowerShell is forced to do the conversion by unwrapping the PSObject.

For completeness, another option if you're using PowerShell V3 is to use the C# keyword dynamic, something like:

public static void DoSomethingWithDouble(Func<object> myFunc)
{
    dynamic unparsedValue = myFunc();
    double parsedValue = (double)(unparsedValue);
    Console.WriteLine(parsedValue);
}

When unparsedValue is a PSObject, PowerShell will perform the conversion from to double on the second line even though you don't reference any PowerShell assemblies in your C# code.

Note these last two options may not fit well with your real API, but they are options that are worth understanding.