将 cmdlet 作为参数传递

Passing a cmdlet as a parameter

我需要在 powershell 脚本中重新启动服务。问题是这个服务有点问题,经常需要关闭几次才能进入 "stopped" 状态。因此,我似乎无法使用 Restart-Service cmdlet,而是需要重试几次 Stop-Service cmdlet。启动服务也是如此。

所以我认为这是编写一个函数的好地方,该函数将执行一个操作(开始或停止)并重试几次直到它起作用。问题是我不确定如何将操作作为参数传递。我可以让动作成为 String,然后说 if action == "start" do starcAction,但这不是很干净。有什么办法可以将 Stop-Service 之类的 cmdlet 作为参数传入?

对于您描述的场景,您通常会这样做:

$maxTries = 5

switch ($args(0)) {
  'start' {
    Start-Service 'MySvc'
  }

  'stop' {
    $i = 0
    do {
      Stop-Service 'MySvc'
      $i++
    } until ((Get-Service 'MySvc').Status -eq 'Stopped' -or $i -ge $maxTries)
    if ((Get-Service 'MySvc').Status -ne 'Stopped') {
      Write-Error "Cannot stop service."
      exit 1
    }
  }

  default {
    Write-Error "Unknown action: $_"
    exit 1
  }
}

如果你真的想避免字符串参数,你可以使用这样的参数集:

[CmdletBinding(DefaultParameterSetName='none')]
Param(
  [Parameter(Mandatory=$true,ParameterSetName='start')]
  [Switch][bool]$Start = $false,
  [Parameter(Mandatory=$true,ParameterSetName='stop')]
  [Switch][bool]$Stop = $false
)

$maxTries = 5

switch ($PSCmdlet.ParameterSetName) {
  'start' {
    Start-Service 'MySvc'
  }

  'stop' {
    $i = 0
    do {
      Stop-Service 'MySvc'
      $i++
    } until ((Get-Service 'MySvc').Status -eq 'Stopped' -or $i -ge $maxTries)
    if ((Get-Service 'MySvc').Status -ne 'Stopped') {
      Write-Error "Cannot stop service."
      exit 1
    }
  }

  'none' {
    Write-Error "Usage: $($MyInvocation.MyCommand.Name) {-Start|-Stop}"
    exit 1
  }
}
Param([Parameter(Mandatory)] [ValidateSet('Start','Stop')] [string] $Action)

这允许用户按 Tab 到 select 可能的值,并将自动拒绝所有无效输入。

传递一个明确定义的参数(不管它是否是一个字符串)实际上比 "passing in a commandlet" 如果有这样的事情更清晰。