首页 > 解决方案 > PowerShell - 从 Invoke-Command 内部调用时,ShouldProcess 不起作用

问题描述

我正在尝试将 ShouldProcess 逻辑添加到删除远程服务器上的文件的脚本中,以便我可以使用 -WhatIf 参数,但它返回错误。这是功能:

function testshouldprocess {
    [CmdletBinding(SupportsShouldProcess = $true]
    param(
        $server
    )
        invoke-command $server {
        Get-ChildItem c:\temp\ | ForEach-Object {
            if($pscmdlet.ShouldProcess($Server)) {
                remove-item $_.fullname
            }
        }
    }
}
testshouldprocess 'Server1' -WhatIf

脚本运行时返回错误

InvalidOperation: You cannot call a method on a null-valued expression.

当每个文件通过管道时。如果我将代码更改为

  if ($pscmdlet.ShouldProcess($server)) {
        invoke-command $server {
            Get-ChildItem c:\temp\ | ForEach-Object {
                remove-item $_.fullname
            }
        }
    }

它可以工作,但 WhatIf 只对整个目录列表执行一次。如果我将代码更改为

Get-ChildItem \\$server\c$\temp\ | ForEach-Object {
        if ($pscmdlet.ShouldProcess($server)) {
            remove-item $_.fullname
        }
    }

它有效,但我更喜欢使用 Invoke-Command。

ShouldProcess 与 Invoke-Command 不兼容吗?

任何见解都值得赞赏。

标签: powershell

解决方案


Hazrelle 的回答提供了关于需要使用$using:范围以便远程执行的脚本块能够访问调用者范围中的值的关键指针。

要完全支持您的方案 --WhatIf用于功能和-Confirm功能,这两者都通过打开来暗示SupportShouldProces- 您必须:

  • 使您的远程执行脚本块也成为高级[CmdletBinding(SupportsShouldProcess)]脚本块,在块上方具有自己的属性param(),因此具有自己的$PSCmdlet实例。

  • 通过和参考调用者范围内的假设/确认相关值$using:WhatIfPreference$using:ConfirmPreference

    • 请注意,对于高级函数和脚本,PowerShell 使用函数局部变量将-WhatIf-Confirm开关转换为等效的首选项变量值;也就是说,传递-WhatIf创建一个$WhatIfPreference具有 value 的函数局部变量$true,传递-Confirm创建一个具有$ConfirmPreferencevalue的函数局部变量High
function testshouldprocess {
  [CmdletBinding(SupportsShouldProcess)]
  param(
    $server
  )

  Invoke-Command $server {
    [CmdletBinding(SupportsShouldProcess)]
    param()

    # Use the caller's WhatIf / Confirm preferences.
    $WhatIfPreference = $using:WhatIfPreference
    $ConfirmPreference = $using:ConfirmPreference

    Get-ChildItem c:\temp\ | ForEach-Object {
      if ($pscmdlet.ShouldProcess($using:server, "delete file: $($_.FullName)")) {
        Remove-Item $_.FullName
      }
    }
  }

}

testshouldprocess 'Server1' -WhatIf

推荐阅读