Как вызвать сложный метод COM из PowerShell?

Можно ли вызвать COM-метод из PowerShell, используя именованные параметры? Метод COM-объекта, с которым я работаю, имеет десятки параметров:

object.GridData( DataFile, xCol, yCol, zCol, ExclusionFilter, DupMethod, xDupTol,
    yDupTol, NumCols, NumRows, xMin, xMax, yMin, yMax, Algorithm, ShowReport,
    SearchEnable, SearchNumSectors, SearchRad1, SearchRad2, SearchAngle, 
    SearchMinData, SearchDataPerSect, SearchMaxEmpty, FaultFileName, BreakFileName, 
    AnisotropyRatio, AnisotropyAngle,  IDPower, IDSmoothing, KrigType, KrigDriftType, 
    KrigStdDevGrid, KrigVariogram, MCMaxResidual, MCMaxIterations, MCInternalTension, 
    MCBoundaryTension, MCRelaxationFactor, ShepSmoothFactor, ShepQuadraticNeighbors, 
    ShepWeightingNeighbors, ShepRange1, ShepRange2, RegrMaxXOrder, RegrMaxYOrder, 
    RegrMaxTotalOrder, RBBasisType, RBRSquared, OutGrid,  OutFmt, SearchMaxData, 
    KrigStdDevFormat, DataMetric, LocalPolyOrder, LocalPolyPower, TriangleFileName )

Большинство этих параметров являются необязательными, а некоторые из них являются взаимоисключающими. В Visual Basic или Python с использованием модуля win32com вы можете использовать именованные параметры, чтобы указать только подмножество необходимых вам параметров. Например (в Python):

Surfer.GridData(DataFile=InFile,
                xCol=Options.xCol,
                yCol=Options.yCol,
                zCol=Options.zCol,
                DupMethod=win32com.client.constants.srfDupMedZ,
                xDupTol=Options.GridSpacing,
                yDupTol=Options.GridSpacing,
                NumCols=NumCols,
                NumRows=NumRows,
                xMin=xMin,
                xMax=xMax,
                yMin=yMin,
                yMax=yMax,
                Algorithm=win32com.client.constants.srfMovingAverage,
                ShowReport=False,
                SearchEnable=True,
                SearchRad1=Options.SearchRadius,
                SearchRad2=Options.SearchRadius,
                SearchMinData=5,
                OutGrid=OutGrid)

Я не могу понять, как вызвать этот объект из PowerShell таким же образом.

Ответ 1

Эта проблема интересовала меня, поэтому я действительно немного поработал, и я нашел решение (хотя я тестировал только в некоторых простых случаях)!

Концепция

Ключевое решение использует [System.Type]::InvokeMember, который позволяет передавать имена параметров в одной из своих перегрузок.

Вот базовая концепция.

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

Решение

Вот многоразовое решение для вызова методов с именованными параметрами. Это должно работать на любом объекте, а не только на COM-объектах. Я сделал хэш-таблицу в качестве одного из параметров, так что указание названных параметров будет более естественным и, надеюсь, меньше подвержено ошибкам. Вы также можете вызвать метод без имени параметра, если хотите, используя параметр -Argument

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
            )
        }
    }
}

<сильные > Примеры

Вызов метода с именованными параметрами.

$shell = New-Object -ComObject Shell.Application
Invoke-NamedParameter $Shell "Explore" @{"vDir"="$pwd"}

## the syntax for more than one would be @{"First"="foo";"Second"="bar"}

Вызов метода, который не принимает параметров (вы также можете использовать -Argument с $null).

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