2017-01-11 1 views
2

Ich habe ein interessantes Verhalten bei Import-PSSession festgestellt. Ich versuche, eine PSSession zu einem Exchange 2013-Server einzurichten und alle Cmdlets zu importieren. Dies funktioniert gut, wenn sie manuell lief:Import-PSSession Fehler beim Aufruf einer Funktion

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$remoteexchserver/PowerShell/ -Authentication Kerberos -ErrorAction Stop 
Import-PSSession $Session -ErrorAction Stop -AllowClobber -DisableNameChecking 

Allerdings, wenn ich es in einer Funktion mit optionalen Parametern laufen wie:

FUNCTION Test-Function { 
    [CmdletBinding()] 
    Param(
     [Parameter(Mandatory=$false)] 
     [ValidateScript({Test-Path $_ -PathType Container})] 
     [string]$SomePath 
    ) 
    begin { 
      $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$remoteexchserver/PowerShell/ -Authentication Kerberos -ErrorAction Stop 
      Import-PSSession $Session -ErrorAction Stop -AllowClobber -DisableNameChecking 
    } 
    ... 

ich den Fehler:

Import-PSSession : Cannot bind argument to parameter 'Path' because it is an empty string 

wenn die Lauf Funktion, ohne einen Wert für $ SomePath anzugeben. Funktioniert einwandfrei, wenn ein gültiger Wert angegeben wird. Dies scheint die gleiche Sache zu sein berichtet here. Ich konnte jedoch keine Problemumgehungen finden, abgesehen von den optionalen Parametern.

Antwort

2

ich war in der Lage, um es zu arbeiten, indem sie den Parameter zu entfernen, wenn es nicht vorhanden ist, wie so:

FUNCTION Test-Function { 
    [CmdletBinding()] 
    Param(
     [Parameter(Mandatory=$false)] 
     [ValidateScript({Test-Path $_ -PathType Container})] 
     [string]$SomePath 
    ) 
    begin { 
      if (!$SomePath) { 
       Remove-Variable SomePath 
      } 
      $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$remoteexchserver/PowerShell/ -Authentication Kerberos -ErrorAction Stop 
      Import-PSSession $Session -ErrorAction Stop -AllowClobber -DisableNameChecking 
    } 
} 

Ein besseres Beispiel sein könnte:

FUNCTION Test-Function { 
    [CmdletBinding()] 
    Param(
     [Parameter(Mandatory=$false)] 
     [ValidateScript({Test-Path $_ -PathType Container})] 
     [string]$SomePath 
    ) 
    begin { 
      $remoteexchserver = 'prdex10ny06' 
      if (-not $PSBoundParameters.ContainsKey('SomePath')) { 
       Remove-Variable SomePath 
      } 
      $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$remoteexchserver/PowerShell/ -Authentication Kerberos -ErrorAction Stop 
      Import-PSSession $Session -ErrorAction Stop -AllowClobber -DisableNameChecking 
    } 
} 

Der Unterschied ist subtil.

Die erste wird die Variable zu entfernen, wenn es (zum Beispiel, wenn es zugeführt wurde, und die Validierung passierte aber immer noch zu evals $false) zu $false in irgendeiner Weise dazu gezwungen werden kann, während der zweite wird es nur entfernt werden, wenn es nicht ist überhaupt geliefert. Sie müssen sich entscheiden, welches besser geeignet ist.


Was, warum dies geschieht, bin ich nicht sicher(siehe unten), aber genauer auf dem Fehler sucht, ist es klar, dass der Validierungsskript gegen den Wert der betrieben wird Parameter, auch wenn es nicht gebunden ist. Der Fehler kommt von Test-Path.

$_ endet wird Null und so Test-Path wirft den Fehler. Ein Teil von dem, was Import-PSSession macht, ist das Ausführen der Validierung, unterscheidet jedoch nicht zwischen Parametern, die gebunden und nicht gebunden waren.


Ich habe dieses Verhalten mit mehr Tests bestätigt. Auch wenn Sie sicherstellen, dass die Validierung Attribut ohne Fehler ausgeführt wird, wird immer noch das Ergebnis verwendet werden:

[ValidateScript({ 
     if ($_) { 
      Test-Path $_ -PathType Container 
     } 
    })] 

Dies wird den Fehler zurück:

Import-PSSession : The attribute cannot be added because variable SomePath with value would no longer be valid. 
At line:21 char:13 
+    Import-PSSession $Session -ErrorAction Stop -AllowClobbe ... 
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    + CategoryInfo   : MetadataError: (:) [Import-PSSession], ValidationMetadataException 
    + FullyQualifiedErrorId : ValidateSetFailure,Microsoft.PowerShell.Commands.ImportPSSessionCommand 

Anstatt also habe ich es so weit geändert :

FUNCTION Test-Function { 
    [CmdletBinding()] 
    Param(
     [Parameter(Mandatory=$false)] 
     [ValidateScript({ 
      if ($_) { 
       Test-Path $_ -PathType Container 
      } else { 
       $true 
      } 
     })] 
     [string]$SomePath 
    ) 
    begin { 
      $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$remoteexchserver/PowerShell/ -Authentication Kerberos -ErrorAction Stop 
      Import-PSSession $Session -ErrorAction Stop -AllowClobber -DisableNameChecking 
    } 
} 

Das setzt das Validierungsattribut zurück. Wenn der Parameter nicht gebunden ist, wird der Aufruf Test-Function ihn nicht ausführen, so dass else { $true } keine Rolle spielt. Aber sobald Import-PSSession es läuft, wird es den Test-Path Teil überspringen.

Das Problem ist, dass wenn Sie Test-Function -SomePath "" aufrufen die Validierung wird von Test-Function Aufruf ausgeführt werden, und es wird nicht fehlschlagen, was nicht was Sie wollen. Sie müssten die Pfadvalidierung zurück in die Funktion verschieben.

dachte ich, ich würde versuchen, auch [ValidateNotNullOrEmpty()] Zugabe, der dies auf Test-Function ‚s Aufruf fangen, aber dann wird Import-PSSession auch, dass laufen, und Sie werden auf den Fehler wieder ich oben erwähnt, wenn der Parameter nicht gebunden ist .

Also an dieser Stelle denke ich, die Variable zu entfernen, während die Validierung beibehalten, als ob Sie Import-PSSession nicht aufrufen würden, ist die einfachste Lösung.


Found It

Es sieht aus, als ob es das gleiche Problem ist, dass, wenn .GetNewClosure() auf einem Skript, as laid out in this answer mit geschieht.

Mit Blick auf den Code für .GetNewClosure() ruft es a method on modules called .CaptureLocals() which is defined here. Hier können Sie sehen, dass es einfach alle verschiedenen Eigenschaften einschließlich der Attribute kopiert.

Ich bin nicht sicher, dass die "fix" kann an dieser Stelle angewendet werden, weil es das Richtige tut. Es kopiert Variablen; es weiß nichts über Parameter. Ob der Parameter gebunden ist oder nicht, ist kein Teil der Variablen.

Also, ich denke, die Reparatur sollte überall dort angewendet werden, wo Parameter als lokale Variablen definiert sind, so dass nicht gebundene Parameter nicht definiert sind. Das würde implizit das beheben und aufgrund der wenigen Minuten, die ich darüber nachgedacht habe, keine anderen Nebenwirkungen haben (aber wer weiß).

Ich weiß nicht, wo dieser Code ist .. (noch?).

+0

Wie kommt der Fehler von 'Import-PSSession'? – sodawillow

+0

@sodawillow Ich weiß nicht, ich bin derzeit auf [den Quellcode für 'Import-PSSession'] (https://github.com/PowerShell/PowerShell/blob/0e8c809ffb36f8b1ad65d80c7570ac5e40614205/src/Microsoft.PowerShell.Commands .Utility/commands/utility/ImplicitRemotingCommands.cs) aber es ist ziemlich lang. Es springt nicht direkt auf mich los und ich glaube nicht, dass ich Zeit habe, alles durchzuarbeiten, aber ich vermute, dass es auf die Art und Weise ankommt, wie die Parameter im Ausführungskontext zu finden sind. – briantist

+1

@sodawillow übrigens habe ich noch mehr getestet, siehe meine Bearbeitung. – briantist

Verwandte Themen