我在Import-PSSession中遇到了一些有趣的行为。我正在尝试为Exchange 2013服务器建立PSSession并导入所有cmdlet。这在手动运行时工作正常:
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$remoteexchserver/PowerShell/ -Authentication Kerberos -ErrorAction Stop
Import-PSSession $Session -ErrorAction Stop -AllowClobber -DisableNameChecking
但是,如果我在具有可选参数的函数中运行它,例如:
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
}
...
我收到错误:
Import-PSSession : Cannot bind argument to parameter 'Path' because it is an empty string
在运行函数时未指定$ SomePath的值。指定有效值时工作正常。这似乎与报道的here相同。除了不使用可选参数之外,我无法找到任何变通方法。
答案 0 :(得分:2)
我能够通过删除参数来解决它,如果它不存在,就像这样:
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
}
}
更好的例子可能是:
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
}
}
差异很微妙。
第一个将删除变量,如果它可以以任何方式强制转换为$false
(例如,如果它被提供并通过验证但仍然是$false
),而第二个只会如果它根本没有提供,请将其移除。你必须决定哪一个更合适。
至于为什么会发生这种情况,我不确定 (见下文),但仔细查看错误,它很清楚验证脚本是针对参数的值运行的,即使它没有绑定。错误来自Test-Path
。
$_
最终为空,因此Test-Path
会抛出错误。 Import-PSSession
正在做的部分工作是运行验证,但不区分绑定与未绑定的参数。
我通过更多测试证实了这种行为。即使您确保验证属性无错运行,仍会使用其结果:
[ValidateScript({
if ($_) {
Test-Path $_ -PathType Container
}
})]
这将返回错误:
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
相反,我已将其更改为:
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
}
}
这使得onus重新回到验证属性。如果参数未绑定,Test-Function
调用将无法运行,因此else { $true }
无关紧要。但是一旦Import-PSSession
运行它,它将跳过Test-Path
部分。
问题在于,如果您致电Test-Function -SomePath ""
,验证将由Test-Function
的调用运行,并且它不会失败,这不是您想要的。您必须将路径验证移回功能。
我想我也尝试添加[ValidateNotNullOrEmpty()]
,这会在Test-Function
的调用中发现这一点,但是Import-PSSession
也会运行它,而你和&{ #39;当参数未绑定时,我将回到上面提到的错误。
所以在这一点上,我认为在保持验证的同时删除变量就像你没有调用Import-PSSession
一样,是最直接的解决方案。
在脚本块as laid out in this answer上使用.GetNewClosure()
时,看起来是同样的问题。
所以查看.GetNewClosure()
的代码,它会调用a method on modules called .CaptureLocals()
which is defined here。您可以在其中看到它只是复制所有各种属性,包括属性。
我不确定"修复"虽然可以在这一点上应用,因为它有点做正确的事情。它正在复制变量;它对参数一无所知。参数是否绑定不是变量的一部分。
因此我认为应该在将参数定义为局部变量的任何地方应用修复,以便不定义未绑定的参数。这将隐含地解决这个问题,并且基于我考虑过的几分钟,不会产生其他副作用(但谁知道)。
我不知道该代码在哪里..(但是?)。