Powershell V2 has some great new features, in particular Add-Type and Remoting features are likely to be quite popular and work together without much issue. That said, there are edge cases which illustrate how the types returned from remoting calls. The following script demonstrates the issue
$csCode = @"
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo {
public static class D
{
public static int Add(int a, int b)
{
return a + b;
}
public static int AddArray(int[] ints)
{
return ints.Sum();
}
public static int AddEnumerable(IEnumerable<object> ints)
{
return ints.Cast<int>().Sum();
}
public static int AddEnumerable(IEnumerable<int> ints)
{
return ints.Sum();
}
}
}
"@
Add-Type -TypeDefinition $csCode -Language CSharpVersion3
$oneRemote = Invoke-Command -ComputerName localhost -ScriptBlock { return 1 }
$listRemote = Invoke-Command -ComputerName localhost -ScriptBlock { return (1,2,3) }
$one = &{return 1}
if ($one -eq $oneRemote)
{
Write-Host "1 == 1"
}
$v = [Demo.D]::Add($one,$oneRemote)
Write-output "One + OneRemote = $v" ; $v=$null
$v = [Demo.D]::AddArray(($one,$oneRemote))
Write-output "One + OneRemote via array = $v" ; $v=$null
$v = [Demo.D]::AddArray($listRemote)
Write-output "One + OneRemote via remote array = $v" ; $v=$null
$v = [Demo.D]::AddEnumerable((1,2,3,4))
Write-output "One + OneRemote via local IEnumerable = $v" ; $v=$null
$v = [Demo.D]::AddEnumerable($listRemote)
Write-output "One + OneRemote via remote IEnumerable = $v"; $v=$null
$oneRemote | Get-Member
The output from the above is
1 == 1
One + OneRemote = 2
One + OneRemote via array = 2
One + OneRemote via remote array = 6
One + OneRemote via local IEnumerable = 10 # so far as expected
Exception calling "AddEnumerable" with "1" argument(s): "Specified cast is not valid."
At typeDemo.ps1:49 char:29
+ $v = [Demo.D]::AddEnumerable <<<< ($listRemote)
TypeName: System.Int32
Name MemberType Definition
---- ---------- ----------
CompareTo Method System.Int32 CompareTo(Object value)
Equals Method System.Boolean Equals(Object obj), System.Boolean Equals(Int32 obj)
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
GetTypeCode Method System.TypeCode GetTypeCode()
ToString Method System.String ToString()
PSComputerName NoteProperty System.String PSComputerName=localhost
PSShowComputerName NoteProperty System.Boolean PSShowComputerName=True
RunspaceId NoteProperty System.Guid RunspaceId=e0dc5c05-c87d-41ad-afe0-16bc1b711f08
What’s happening under the covers is that the PowerShell reporting infrastructure is returning a PSObject. By inspecting the type via Get-Member you can see that it has some extra NoteProperties. To PowerShell and .Net methods that expect integers and arrays of integers, the object looks and behaves like it should. But if your Add-Types use a more LINQ style approach, which expects an IEnumerable<T>, the PowerShell type system doesn’t properly convert the adapted type to its native underlying type and runtime exceptions are the result.
There are some interesting sessions at the 2009 EntDevCon.
Three of particular interest to me are are
1. “Coral8 Engine Integrated with Microsoft Windows HPC Server 2008” at 11 on Tuesday.
I had a chance to see some of the early bits, and for anyone interesting in streaming data with high computations needs, this promises to be well worth your time. In a future post I’ll talk about how this technology can be used.
Additionally, some co-workers at Lab49 will be presenting on Wednesday:
2. Marc Jacobs and Citi on “Agile Development using Low-Fidelity Prototypes, Expression Blend and SketchFlow:A Case Study”
3. Daniel Simon on “Patterns and practices:composite development for WPF and Silverlight using Composite Application Guidance (a.k.a. Prism 2.0)”
And if I have time, I might have a few hours at the Lab49 booth, stop by to say hi.