Checking process and process status in PowerShell version 2 and getting two different outputs depending on one process or multiple processes?
Here is the code I'm using:
$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
}
}
The code checks to see if the process is running company_name_uat-Historian
on the server and if it is running it will output runn1ng
and fai1ed
if not.
The problem is that it works by checking only one process, like the code above, but not when trying to check the list of processes.
I need to check the list of processes, so when I link the rest like below:
$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
}
They all deduce fai1ed
.
If I do them one by one, every other process will return runn1ng
, and all grouped together will return fai1ed
.
Side notes (if anyone is interested):
-
runn1ng
andfai1ed
are "codewords" that are replaced with images using JavaScript. I'm making an HTML control panel that controls my windows servers to work, so use green check marks and red x icons and what not. - Using PowerShell 2 is not my choice, some of the servers I am responsible for monitoring are Windows 2008 R2. I believe they will be updated this year, but in order to complete the project I need to make an immediate decision on monitoring. There are also some servers that in 2012 I love writing PowerShell scripts for.
-
spotify
listed as a process because I know it is a legitimate process, but not installed on our servers. When I was writing the script, I tested my personal machine first and used itspotify
as a testing toolrunn1ng
if I opened it orfai1ed
if I closed it. If all my processesrunn1ng
are and spotify isfai1ed
, then this indicates that the PS code is working.
This is similar to PowerShell version 2.
Any ideas what is causing it and how can I rewrite it?
source to share
Answer
if (($FoundProcesses | Select-Object -ExpandProperty Name) -contains $Item) {
Why
PowerShell 3 added something called member listing. If you have an array of objects in 2.0, you cannot directly call the properties of the array, because it looks for those properties in the array itself. In 3.0+, if an element does not exist in the array, it also checks the elements for that element. Usage Select-Object -ExpandProperty
is a more explicit way to call members.
You can also just move the call Get-Process
to the loop foreach
.
foreach ($Item in $ProcessesToCheckFor)
{
if (Get-Process -Name $Item -ErrorAction SilentlyContinue)
{
'{0} runn1ng' -f $Item
}
else
{
'{0} fai1ed' -f $Item
}
}
source to share
Patrick Meinecke's answer is efficient and helpful, but let me try for a more detailed explanation and a more efficient solution:
First things first: Your code works great in PSv3 + , which should provide an incentive to leave PSv2 behind .
PSv3 introduced unified handling of scalars and collections using member enumeration , which bridged the large scalar / array scatter that PSv2 suffers from.
Particularly in PSv3, you don't have to worry about returning Get-Process -Name $ProcessesToCheckFor
one or more elements: in any case, you can call .Count
on the output to count the number of elements returned and you can call a member (property) on the result, which in the case of an array result (multiple elements) means the element is called for every element (for example .Name
) and the result can be reused as a scalar or array as needed.
In PSv2 - . , You need to know if the cmdlet is happening - ad-hoc - returning one item or multiple items , which means:
-
Use the array subexpression operator
@(...)
to ensure that even if the nested command returns a single element (scalar), the result is an array. -
To collect the property values of the elements of a given array or scalar into a new array or scalar, use
... | Select-Object -ExpandProperty
- again, apply@(...)
to ensure that the result is an array. -
Note that PSv2- had some unified scalar / array handling, but only with regard to pipeline handling: to send a scalar (single element) to a pipeline, you can use it as is, without having to wrap it in
@(...)
:'foo' | ...
works just fine - no need@('foo') | ...
(although this works too).
Applied to your code, we get:
$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
}
}
source to share