8

As described in my question Create ISO image using PowerShell: how to save IStream to file?, in PowerShell I create an IStream object as follows:

$is = (New-Object -ComObject IMAPI2FS.MsftFileSystemImage).CreateResultImage().ImageStream

This object is of (PowerShell) type System.__ComObject. And somehow PowerShell knows that it is an IStream:

PS C:\> $is -is [System.Runtime.InteropServices.ComTypes.IConnectionPoint]
False
PS C:\> $is -is [System.Runtime.InteropServices.ComTypes.IStream]
True

However, a cast to this type fails:

PS C:\> [System.Runtime.InteropServices.ComTypes.IStream] $is
Cannot convert the "System.__ComObject" value of type "System.__ComObject" to type "System.Runtime.InteropServices.ComT
ypes.IStream".
At line:1 char:54
+ [System.Runtime.InteropServices.ComTypes.IStream] $is <<<<
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

How do I make this conversion work, without using C# code?

Update: Apparently this conversion cannot be made to work, as x0n's answer says.

Now, my goal is to pass this IStream COM object to some C# code (part of the same PowerShell script using Add-Type), where it would become a .NET object of type System.Runtime.InteropServices.ComTypes.IStream. Is that possible? If not, what alternatives do I have?

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141

2 Answers2

8

You can try to pass $is in a (unsafe) c# method like an objecttype and try to handle it with a VARdeclared as System.Runtime.InteropServices.ComTypes.IStream

public unsafe static class MyClass
{
    public static void MyMethod(object Stream) 
    {
       var i = Stream as System.Runtime.InteropServices.ComTypes.IStream; 

    //do something with i like i.read(...) and i.write(...)
    }
}

In powershell after the add-type:

[MyClass]::MyMethod($is)
CB.
  • 58,865
  • 9
  • 159
  • 159
  • 1
    And that works! Previously I had `MyMethod(IStream i)`, and then PowerShell does the conversion to an `IStream`, and fails. Letting .NET/CLR do the conversion instead, as you suggest, works. Bounty is coming your way. – MarnixKlooster ReinstateMonica Mar 22 '12 at 10:46
5

You can't make this work. PowerShell uses a transparent "com adapter" layer that prevents this from working, but enables late binding in script. For the majority of cases this a Good Thing, but not in yours.

x0n
  • 51,312
  • 7
  • 89
  • 111
  • 2
    Thanks! I'd appreciate an update of your answer to include a pointer to some more documentation on the feature/behavior which you're describing. Also, my goal is to use this `IStream` COM object in some C# code which is inlined in the same PowerShell script using `Add-Type`, and the C# code needs to read from the `IStream`. (I'll update this question soon.) What would be a simple way to do that? – MarnixKlooster ReinstateMonica Jan 27 '12 at 19:41
  • 1
    Check my profile - I am a 5 year powershell microsoft mvp with direct access to the powershell team. I know ;) – x0n Jan 27 '12 at 22:34