在 PowerShell 版本 2 中检查进程和进程状态并根据单个进程或多个进程获得两个不同的输出?

Checking for process and process status in PowerShell version 2 and getting two different outputs depending on single process or multiple processes?

下面是我正在使用的代码:

$ProcessesToCheckFor = (
    'company_name_uat-Historian'
    )

$FoundProcesses = Get-Process -Name $ProcessesToCheckFor -ErrorAction SilentlyContinue

foreach ($Item in $ProcessesToCheckFor)
    {
    if ($FoundProcesses.Name -contains $Item)
        {
        '{0} runn1ng' -f $Item
        }
        else
        {
        '{0} fai1ed' -f $Item
        }
    }

代码检查服务器上的company_name_uat-Historian进程是否为运行,如果是运行,则输出runn1ngfai1ed 如果没有。

问题是,就像上面的代码一样,它只检查一个进程时有效,但当您尝试检查进程列表时却无效。

我需要检查进程列表,所以当我按如下所示链接其余进程时:

$ProcessesToCheckFor = (
'company_name_uat-Historian',
'company_name_uat-KEReviewCollector',
'company_name_uat-lwm',
'company_name_uat-MQAck',
'company_name_uat-MQOutput',
'company_name_uat-SQAC',
'company_name_uat-Store',
'company_name_uat-Store_STS',
'company_name_uat-StoreLegacy',
'spotify'
    )

$FoundProcesses = Get-Process -Name $ProcessesToCheckFor -ErrorAction SilentlyContinue

foreach ($Item in $ProcessesToCheckFor)
    {
    if ($FoundProcesses.Name -contains $Item)
        {
        '{0} runn1ng' -f $Item
        }
        else
        {
        '{0} fai1ed' -f $Item
        }

他们都输出fai1ed.

如果我一个一个地做,每个不同的过程都会 return runn1ng,只是全部聚集在一起 return fai1ed.

旁注(如果有人想知道的话):

它似乎发生在 PowerShell 版本 2 中。

知道是什么原因造成的吗?我该如何重写它?

答案

if (($FoundProcesses | Select-Object -ExpandProperty Name) -contains $Item) {

为什么

PowerShell 3 添加了一个叫做成员枚举的东西。如果在 2.0 中有对象数组,则不能直接调用数组的属性,因为它会在数组对象本身上查找那些属性。在 3.0+ 中,如果数组中不存在该成员,它也会检查该成员的项目。使用 Select-Object -ExpandProperty 是调用成员的更明确的方式。

您也可以将 Get-Process 调用移动到 foreach 循环中。

foreach ($Item in $ProcessesToCheckFor)
    {
    if (Get-Process -Name $Item -ErrorAction SilentlyContinue)
        {
        '{0} runn1ng' -f $Item
        }
        else
        {
        '{0} fai1ed' -f $Item
        }
    }

有效且有帮助,但让我尝试更详细的解释和更有效的解决方案:

首先要做的事情:您的代码在 PSv3+ 中工作得很好,这应该会激励人们放弃 PSv2

PSv3 引入了 unified handling of scalars and collections through member(-access) enumeration,它弥合了困扰 PSv2-的巨大 scalar/array 鸿沟。

具体来说,在 PSv3 中,您不必担心 Get-Process -Name $ProcessesToCheckFor 是否发生在 return 一个 单个 多个 items:在任何一种情况下,您都可以在输出上调用 .Count 来计算 returned 的项目数,并且您可以在结果上调用成员 (属性),其中,数组结果(多项)的情况意味着在每个元素(例如,.Name)上调用成员,并且结果可以再次用作标量或数组根据需要.

但是,在 PSv2- 中,您需要了解一个 cmdlet 在特定情况下是 return 一个项目还是多个项目ones,意思是:

  • 使用数组子表达式运算符@(...)确保即使封闭的命令恰好return一个单个项目(标量),结果是一个 array.

  • 要收集给定数组或新数组或标量中标量的元素的 属性 值,请使用 ... | Select-Object -ExpandProperty - 再次应用 @(...) 以确保结果是 array.

  • 请注意,PSv2- 有 一些 统一的 scalar/array 处理,但 只有 关于 pipeline processing: 将一个标量(单项)发送到管道,你可以按原样使用它,而不需要将它包装在 @(...):
    'foo' | ... 工作正常 - 不需要 @('foo') | ...(即使它也有效)。

应用于您的代码我们得到:

$ProcessesToCheckFor = (
'company_name_uat-Historian',
'company_name_uat-KEReviewCollector',
'company_name_uat-lwm',
'company_name_uat-MQAck',
'company_name_uat-MQOutput',
'company_name_uat-SQAC',
'company_name_uat-Store',
'company_name_uat-Store_STS',
'company_name_uat-StoreLegacy',
'spotify'
)

# Collect the names of all running processes and 
# make sure the result is an array (`@(...)`).
$FoundProcesses = @(Get-Process -Name $ProcessesToCheckFor -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty Name)

foreach ($Item in $ProcessesToCheckFor) {
  if ($FoundProcesses -contains $Item) {
    '{0} runn1ng' -f $Item
  } else {
    '{0} fai1ed' -f $Item
  }
}