2011-04-04 16 views
23

¿Es posible llamar a un método COM desde PowerShell utilizando parámetros con nombre? El método de objeto COM estoy trabajando con tiene docenas de parámetros:¿Cómo llamar a un método COM complejo de PowerShell?

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) 

La mayor parte de esos parámetros son opcionales y algunos de ellos son mutuamente excluyentes. En Visual Basic o Python utilizando el módulo win32com, puede usar parámetros con nombre para especificar solo el subconjunto de opciones que necesita. Por ejemplo (en 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) 

no puedo encontrar la manera de llamar a este objeto desde PowerShell de la misma manera.

+1

Felicitaciones por encontrar una pregunta muy difícil. Tengo una solución de último recurso. Pero primero iré a buscar un armario para acurrucarme y llorar para dormir. – JasonMArcher

Respuesta

30

Este problema me interesó, así que hice una verdadera excavación y encontré una solución (¡aunque solo he probado en algunos casos simples)!

Concepto

La solución clave es usar [System.Type]::InvokeMember que le permite pasar los nombres de parámetros en una de sus sobrecargas.

Aquí está el concepto básico.

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

Solución

Aquí es una solución reutilizable para llamar a los métodos con parámetros con nombre. Esto debería funcionar en cualquier objeto, no solo en los objetos COM. Hice una tabla hash como uno de los parámetros para que especificar los parámetros nombrados sea más natural y, con suerte, menos propenso a errores. También puede llamar a un método sin nombres de parámetros si lo desea mediante el parámetro -argumento

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

Ejemplos

llamar a un método con parámetros con nombre.

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

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

Llamando a un método que no requiere parámetros (también puede usar -Argumento con $ null).

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

Esta es una solución increíble. – klumsy

+0

Wow. Gracias. Voy a hacer una prueba mañana. – David

+0

Buen trabajo, Jason. – x0n

Cuestiones relacionadas