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

时间:2017-07-25 23:11:26

标签: powershell powershell-v2.0

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

$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

如果我逐个执行这些操作,则每个不同的流程都会返回runn1ng,只是将所有流程组合在一起,然后返回fai1ed

附注(如果有人想知道):

  • runn1ngfai1ed是'代码字'使用JavaScript替换为图像。我正在制作一个监控我的Windows服务器工作的HTML仪表板,所以请考虑绿色复选标记和红色x标记以及不是。
  • 使用PowerShell版本2根本不是我的选择,我负责监控的一些服务器是Windows 2008 R2。我相信它们将在今年某个时候更新,但项目可交付成果要求我立即制定监控解决方案。还有一些服务器是2012年,我喜欢为其编写PowerShell脚本。
  • spotify被列为一个进程,因为我知道它是一个合法的进程,但未安装在我们的服务器上。当我编写脚本时,我最初在自己的个人计算机上进行了测试,并使用spotify作为测试runn1ng的方法,如果我打开它,或fai1ed如果我关闭它。如果我的所有流程均为runn1ng且spotify为fai1ed,那么表明PS代码正在运行。

似乎发生在PowerShell版本2中。

任何想法是什么导致它以及我如何重写它?

2 个答案:

答案 0 :(得分:5)

答案

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

为什么

PowerShell 3添加了一个名为member enumeration的东西。如果在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
        }
    }

答案 1 :(得分:2)

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

首先要做的事情:你的代码在PSv3 + 中运行得很好,这应该提供激励我们将PSv2抛在后面

PSv3引入了unified handling of scalars and collections through member enumeration ,它弥合了困扰PSv2的巨大标量/数组鸿沟。 -

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

PSv2 - 中,您需要了解cmdlet(在情境上)是否恰好返回单个项目或多个,这意味着:

  • 使用array-subexpression运算符@(...)来确保即使附带的命令恰好返回单个项(标量),结果也是数组< / EM>

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

  • 请注意,PSv2- 部分统一标量/数组处理,但 管道处理:发送一个标量(单项)到管道,您可以按原样使用它,而无需将其包裹在@(...)中:
    '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
  }
}