如何从 PowerShell 调用复杂的 COM 方法?

Posted

技术标签:

【中文标题】如何从 PowerShell 调用复杂的 COM 方法?【英文标题】:How to call a complex COM method from PowerShell? 【发布时间】:2011-07-29 12:38:32 【问题描述】:

是否可以使用命名参数从 PowerShell 调用 COM 方法?我正在使用的 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 )

这些参数中的大多数是可选的,其中一些是互斥的。在使用 win32com 模块的 Visual Basic 或 Python 中,您可以使用命名参数仅指定您需要的选项子集。例如(在 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" @

【讨论】:

哇。谢谢。明天我会测试一下。 不错!这是在 GitHub 上还是什么的?我很想窃取你的代码并引用一个实际的 repo。 ;)【参考方案2】:

使用 Invoke-NamedParameter 函数对我不起作用。我在这里找到了一个有趣的解决方案https://community.idera.com/database-tools/powershell/ask_the_experts/f/powershell_for_windows-12/6361/excel-spreadsheet-export,它确实对我有用。

        $excel = New-Object -ComObject excel.application
        $objMissingValue = [System.Reflection.Missing]::Value
        $Workbook = $excel.Workbooks.Open($datafile,$objMissingValue,$False,$objMissingValue,$objMissingValue,$objMissingValue,$true,$objMissingValue)

我没有使用的任何参数都添加了缺失值。

【讨论】:

以上是关于如何从 PowerShell 调用复杂的 COM 方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何从其他powershell脚本调用powershell脚本并且脚本是在powershell对象而不是文件中分配的

如何在 powershell 中调用 devenv.com? [复制]

如何使用 Powershell 进行复杂查询 MongoDB

如何从 C# 文件调试“调用”Powershell (ps1)

从 Powershell 调用的 DLL 使用相对于 Powershell 安装目录的路径。如何将其设置为其他内容?

如何仅将 SQLPlus 错误保存到文件(从 powershell 调用)