2011-04-04 8 views
23

Est-il possible d'appeler une méthode COM à partir de PowerShell en utilisant des paramètres nommés? La méthode d'objet COM Je travaille avec a des dizaines de paramètres:Comment appeler une méthode COM complexe à partir 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 plupart de ces paramètres sont facultatifs et certains d'entre eux sont mutuellement exclusifs. En Visual Basic ou Python utilisant le module win32com, vous pouvez utiliser des paramètres nommés pour spécifier uniquement le sous-ensemble d'options dont vous avez besoin. Par exemple (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) 

Je ne peux pas comprendre comment appeler cet objet de PowerShell de la même manière.

+1

Félicitations pour avoir trouvé une question très difficile. J'ai une solution de dernier recours. Mais d'abord j'irai trouver un placard pour m'encercler et m'endormir. – JasonMArcher

Répondre

30

Ce problème m'a intéressé, donc j'ai fait de vraies recherches et j'ai trouvé une solution (bien que je n'ai testé que sur des cas simples)!

Concept

La solution clé utilise [System.Type]::InvokeMember qui vous permet de passer des noms de paramètres dans l'une de ses surcharges.

Voici le concept de base.

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

Solution

Voici une solution réutilisable pour appeler des méthodes avec des paramètres nommés. Cela devrait fonctionner sur n'importe quel objet, pas seulement sur les objets COM. J'ai fait une hashtable comme l'un des paramètres de sorte que la spécification des paramètres nommés sera plus naturelle et, espérons-le, moins sujette aux erreurs. Vous pouvez également appeler une méthode sans noms de paramètres si vous voulez en utilisant le paramètre -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 
      ) 
     } 
    } 
} 

Exemples

Appel de méthode avec les paramètres nommés.

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

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

appel d'une méthode qui ne prend aucun paramètre (vous pouvez aussi utiliser -argument avec $ null).

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

C'est une solution géniale. – klumsy

+0

Wow. Merci. Je vais donner un test demain. – David

+0

Beau travail, Jason. – x0n

Questions connexes