gpt4 book ai didi

design-patterns - Powershell 脚本 : recommended way to implement ShouldProcess when function calls are nested?

转载 作者:行者123 更新时间:2023-12-04 01:03:24 25 4
gpt4 key购买 nike

测试脚本:

function outer
{
[cmdletbinding(supportsshouldprocess=$true)]
param($s)

process
{
$pscmdlet.shouldprocess("outer $s", "ShouldProcess") | out-null
"" | out-file "outer $s"

inner ImplicitPassthru
inner VerbosePassthru -Verbose:$Verbose
inner WhatifPassthru -WhatIf:$WhatIf
}
}

function inner
{
[cmdletbinding(supportsshouldprocess=$true)]
param($s)

process
{
$pscmdlet.shouldprocess("inner $s", "ShouldProcess") | out-null
"" | out-file "inner $s"
}
}

"`n** NORMAL **"
outer normal
"`n** VERBOSE **"
outer verbose -Verbose
"`n** WHATIF **"
outer whatif -WhatIf

输出:
** NORMAL **
VERBOSE: Performing operation "ShouldProcess" on Target "inner VerbosePassthru".
What if: Performing operation "ShouldProcess" on Target "inner WhatifPassthru".
What if: Performing operation "Output to File" on Target "inner WhatifPassthru".

** VERBOSE **
VERBOSE: Performing operation "ShouldProcess" on Target "outer verbose".
VERBOSE: Performing operation "ShouldProcess" on Target "inner VerbosePassthru".
What if: Performing operation "ShouldProcess" on Target "inner WhatifPassthru".
What if: Performing operation "Output to File" on Target "inner WhatifPassthru".

** WHATIF **
What if: Performing operation "ShouldProcess" on Target "outer whatif".
What if: Performing operation "Output to File" on Target "outer whatif".
What if: Performing operation "ShouldProcess" on Target "inner ImplicitPassthru".
What if: Performing operation "Output to File" on Target "inner ImplicitPassthru".
What if: Performing operation "ShouldProcess" on Target "inner VerbosePassthru".
What if: Performing operation "Output to File" on Target "inner VerbosePassthru".
What if: Performing operation "ShouldProcess" on Target "inner WhatifPassthru".
What if: Performing operation "Output to File" on Target "inner WhatifPassthru".

在我看来,这里有几个奇怪的地方:
  • 指定 -WhatIf:$foo 将 总是 在被调用者(及其被调用者)中打开 $WhatIf,无论 $foo 是什么。
  • 当您指定 -WhatIf “for real”(不将其限制为现有变量)时,它会隐式传播到被调用者。无需通过或飞溅。
  • 与 -WhatIf 不同,显式 -Verbose 不会隐式级联到被调用者。
  • 当您尝试手动通过 -Verbose:$foo 时,您确实看到行为类似于 -WhatIf:$foo。但它只影响手动测试 $psCmdlet.ShouldProcess() 的脚本——内置 cmdlet 不受影响。

  • 注: : Confirm 的行为与 WhatIf 相同。为简洁起见,我省略了它。

    搜索网络和连接,我几乎看不到任何关于与高级功能有关的 ShouldProcess 行为(赞成或反对)的深入讨论。最接近的是 a post from James O'Neill建议在整个调用堆栈中传递 $psCmdlet 的单个实例。然而,他这样做是为了解决一个完全不同的问题(避免多次 -Confirm 提示)。同时,当您坚持使用为每个函数提供的标准 $psCmdlet 时,我看不到有关预期结果的文档……更不用说设计模式、最佳实践等……

    最佳答案

    您不能真正引用 $WhatIf 或 $Verbose,因为它们是为您合成的,即这些变量在您的函数中不存在。如果用户指定了它们,那么您可以通过 $PSBoundParameters 获取它们,但如果用户没有指定它们显然不会出现在这个哈希表中。

    当您将值传递给开关时,PowerShell 将执行典型的强制过程以尝试将指定的值转换为 bool 值。由于未定义 $whatif,因此此 eval 为 $null,导致开关值设置为 $true。这大概是因为它看到开关被明确指定,实际上没有值,这相当于只指定 -Whatif 没有值。跟踪参数绑定(bind)时可以看到这一点:

    function Foo
    {
    [CmdletBinding(SupportsShouldProcess=1)]
    param()

    Process
    {
    $PSBoundParameters
    }
    }

    Trace-Command -name ParameterBinding -expr {Foo -whatif:$xyzzy} -PSHost
    DEBUG: BIND NAMED cmd line args [Foo]
    DEBUG: BIND arg [] to parameter [WhatIf]
    DEBUG: COERCE arg to [System.Management.Automation.SwitchParameter]
    DEBUG: Arg is null or not present, type is SWITCHPARAMTER, value is true.
    DEBUG: BIND arg [True] to param [WhatIf] SUCCESSFUL
    DEBUG: BIND POSITIONAL cmd line args [Foo]
    DEBUG: MANDATORY PARAMETER CHECK on cmdlet [Foo]
    DEBUG: CALLING BeginProcessing
    DEBUG: CALLING EndProcessing

    $WhatIfPreference 和 $VerbosePreference 在 outer 中根据是否使用 -verbose 或 -whatif 调用而适当设置。我可以看到这些值传播到内部就好了。 $pscmdlet.ShouldProcess 似乎存在 PowerShell 错误。在这种情况下,它似乎没有兑现 $VerbosePreference 的值(value)。您可以尝试通过 -Verbose 传递到内部,如下所示:
    inner VerbosePassthru -Verbose:($VerbosePreference -eq 'Continue')

    另一种选择是像这样使用 Get-Variable -Scope:
    function Outer
    {
    [CmdletBinding(SupportsShouldProcess=1)]
    param()

    Process
    {
    $pscmdlet.ShouldProcess("Outer process", '') > $null
    inner
    #inner -Verbose:($VerbosePreference -eq 'Continue')
    }
    }

    function Inner
    {
    [CmdletBinding(SupportsShouldProcess=1)]
    param()

    Process
    {
    $pscmdlet = (Get-Variable -Scope 1 -Name PSCmdlet).Value
    $pscmdlet.ShouldProcess("Inner process", '') > $null
    "Inner $VerbosePreference"
    }
    }

    Outer -Verbose

    我不确定我是否喜欢这个,因为这意味着您知道外部比内部高 1 级。您可以“遍历”范围堆栈,在堆栈中查找下一个 PSCmdlet 变量。这有效地摆脱了必须传入 PSCmdlet(这很恶心),但它仍然是一个 hack。您应该考虑在 MS Connect 上提交一个关于此的错误。

    关于design-patterns - Powershell 脚本 : recommended way to implement ShouldProcess when function calls are nested?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2278876/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com