如果参数不存在,我可以通过删除参数来解决它,如下所示:
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。
$_ 最终为 null,因此 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
}
}
这将责任重新放在验证属性上。如果参数未绑定,Test-Function 调用将不会运行它,因此else { $true } 无关紧要。但是一旦Import-PSSession 运行它,它将跳过Test-Path 部分。
问题是,如果您调用Test-Function -SomePath "",验证将由Test-Function 的调用运行,并且不会失败,这不是您想要的。您必须将路径验证移回函数中。
我想我也会尝试添加[ValidateNotNullOrEmpty()],它会在Test-Function 的调用中捕获它,但随后Import-PSSession 也会运行它,你会回到我上面提到的错误参数未绑定。
因此,在这一点上,我认为删除变量同时保持验证就像您不调用 Import-PSSession 时一样,是最直接的解决方案。
找到了
看起来这与在脚本块 as laid out in this answer 上使用 .GetNewClosure() 时发生的问题相同。
所以查看.GetNewClosure() 的代码,它调用a method on modules called .CaptureLocals() which is defined here。在那里你可以看到它只是简单地复制了所有不同的属性,包括属性。
我不确定此时是否可以应用“修复”,因为它在做正确的事情。它正在复制变量;它对参数一无所知。参数是否绑定不是变量的一部分。
因此,我认为应该在将参数定义为局部变量的任何地方应用修复,以便未定义未绑定的参数。这将隐含地解决这个问题,并且基于我花了几分钟思考它,不会有其他副作用(但谁知道)。
我不知道那个代码在哪里..(还没有?)。