How to call a complex COM method from PowerShell? How to call a complex COM method from PowerShell? powershell powershell

How to call a complex COM method from PowerShell?


This problem did interest me, so I did some real digging and I have found a solution (though I have only tested on some simple cases)!

Concept

The key solution is using [System.Type]::InvokeMember which allows you to pass parameter names in one of its overloads.

Here is the basic concept.

$Object.GetType().InvokeMember($Method, [System.Reflection.BindingFlags]::InvokeMethod,    $null,  ## Binder    $Object,  ## Target    ([Object[]]$Args),  ## Args    $null,  ## Modifiers    $null,  ## Culture    ([String[]]$NamedParameters)  ## NamedParameters)

Solution

Here is a reusable solution for calling methods with named parameters. This should work on any object, not just COM objects. I made a hashtable as one of the parameters so that specifying the named parameters will be more natural and hopefully less error prone. You can also call a method without parameter names if you want by using the -Argument parameter

Function Invoke-NamedParameter {    [CmdletBinding(DefaultParameterSetName = "Named")]    param(        [Parameter(ParameterSetName = "Named", Position = 0, Mandatory = $true)]        [Parameter(ParameterSetName = "Positional", Position = 0, Mandatory = $true)]        [ValidateNotNull()]        [System.Object]$Object        ,        [Parameter(ParameterSetName = "Named", Position = 1, Mandatory = $true)]        [Parameter(ParameterSetName = "Positional", Position = 1, Mandatory = $true)]        [ValidateNotNullOrEmpty()]        [String]$Method        ,        [Parameter(ParameterSetName = "Named", Position = 2, Mandatory = $true)]        [ValidateNotNull()]        [Hashtable]$Parameter        ,        [Parameter(ParameterSetName = "Positional")]        [Object[]]$Argument    )    end {  ## Just being explicit that this does not support pipelines        if ($PSCmdlet.ParameterSetName -eq "Named") {            ## Invoke method with parameter names            ## Note: It is ok to use a hashtable here because the keys (parameter names) and values (args)            ## will be output in the same order.  We don't need to worry about the order so long as            ## all parameters have names            $Object.GetType().InvokeMember($Method, [System.Reflection.BindingFlags]::InvokeMethod,                $null,  ## Binder                $Object,  ## Target                ([Object[]]($Parameter.Values)),  ## Args                $null,  ## Modifiers                $null,  ## Culture                ([String[]]($Parameter.Keys))  ## NamedParameters            )        } else {            ## Invoke method without parameter names            $Object.GetType().InvokeMember($Method, [System.Reflection.BindingFlags]::InvokeMethod,                $null,  ## Binder                $Object,  ## Target                $Argument,  ## Args                $null,  ## Modifiers                $null,  ## Culture                $null  ## NamedParameters            )        }    }}

Examples

Calling a method with named parameters.

$shell = New-Object -ComObject Shell.ApplicationInvoke-NamedParameter $Shell "Explore" @{"vDir"="$pwd"}## the syntax for more than one would be @{"First"="foo";"Second"="bar"}

Calling a method that takes no parameters (you can also use -Argument with $null).

$shell = New-Object -ComObject Shell.ApplicationInvoke-NamedParameter $Shell "MinimizeAll" @{}