Trial and Error — Powershell, Get-Process, Remote PCs, and Invoke-Command

Recently, I worked to take advantage of the power and performance of PowerShell to ensure my small network of PCs were up and running. Essentially, I wanted to be notified if certain processes were up and running. The majority of my PCs do not have a physical keyboard, mouse, or monitor attached to the machine. So it is important for me to know when the machine is in a bad state.

Let’s Get Started

I did a fair bit of research and I came up with a script. I utilized the Get-Process cmdlet in PowerShell. For each machine, I would save the message and email it to me. Simple, eh?

Here was my script:

$computers = “machinea”,”machineb”,”machinec”,”machined”;

$EmailMessage = “”

Foreach($computer in $computers) {
write-host $computer
if((Get-Process -ComputerName $computer “myprocess” -ErrorAction SilentlyContinue -ErrorVariable ProcessError) -eq $null) {
$EmailMessage += “MyProcess Not Running on $computer” + “`n`n”
Write-Warning “MyProcess Not Running on $computer”
}
else {
$EmailMessage += “Life is good on $computer” + “`n`n”
Write-Warning “Life is good on $computer”
}

if( $ProcessError ) {
$EmailMessage += “Something went wrong when communicating with $computer” + “`n`n”
Write-Host “Something went wrong when communicating with $computer” -Foregroundcolor Red
}
}

Send-MailMessage -To [email protected] -From “[email protected]” -SmtpServer ServerAddress -Subject “PC System Report” -body $EmailMessage

Oh, life was good. Except for three of the machines, the Get-Process command would return the error message the “Couldn’t connect to remote machine.”

What coudl be the problem???

What Could Be The Problem?

A little troubleshooting:

  • Each machine was up and running
  • Enable-PSRemoting was enabled on each machine
  • I could remote into the machine
  • The admin user was running on the machine

By all accounts, the script shouldn’t have encountered any problems. A google search produced a ton of results. In some of the results, I discovered that Invoke-Command was known to work as opposed to Get-Process. So I chose to give it a go.

$computers = “machinea”,”machineb”,”machinec”,”machined”;

$EmailMessage = “”

$Procname = ‘myprocess’
$chk = (Get-Process | Where-Object {$_.Name -eq $Procname} -ErrorAction SilentlyContinue -ErrorVariable ProcessError)

Foreach($computer in $computers) {

write-host $computer
$EmailMessage += “Status of $computer”

Invoke-Command -ComputerName $computer -ScriptBlock {

if ($using:chk -eq $null) {
$EmailMessage += “ — MyProcess Is Not Running!`r`n”
Write-Warning $EmailMessage
} else {
$EmailMessage += “ — Life is Good, No Worries!`r`n”
write-host $EmailMessage -ForegroundColor Yellow
}

if( $ProcessError ) {
$EmailMessage += “ — An Unexpected Error was encountered!`r`n”
Write-Host $EmailMessage -ForegroundColor Red
}

}
}

Send-MailMessage -To [email protected] -From “[email protected]” -SmtpServer ServerAddress -Subject “PC System Report” -body $EmailMessage

It doesn’t get any simpler than that. 🙂

The Invoke-Command saved the day. According to my research, Invoke-Command uses WinRM while Get-Process does not. Hence, the reason the Invoke-Command was successful. I ran the script and error…

PowerShell had to be wrong!

Yep, the script was able to check if the process was running on the machines. But I received an error the “-Body” could not except a null or empty value. That was stupid, I was passing $EmailMessage for the body of the email. PowerShell had to be confused.

Finding A Solution

Nope, I was confused. In using the Invoke-Command and -ScriptBlock, I am not able to append to a variable outside of the block. Instead, I needed to pass a variable into Invoke-Command or get the return value from it. A light bulb moment, get the return value.

$computers = “machinea”,”machineb”,”machinec”,”machined”;

$EmailMessage = “”

$Procname = ‘myprocessr’
$chk = (Get-Process | Where-Object {$_.Name -eq $Procname} -ErrorAction SilentlyContinue -ErrorVariable ProcessError)

Foreach($computer in $computers) {

write-host $computer
$EmailMessage += “Status of $computer”

$EmailMessage += Invoke-Command -ComputerName $computer -ScriptBlock {

if ($using:chk -eq $null) {
$Status = “ — MyProcess Is Not Running!”
Write-Warning $Status
} else {
$Status = “ — Life is Good, No Worries!”
write-host $Status -ForegroundColor Yellow
}

if( $ProcessError ) {
$Status = “ — An Unexpected Error was encountered!”
Write-Host $Status -ForegroundColor Red
}

return $Status;
}

$EmailMessage += “`r`n”
}

Send-MailMessage -To [email protected] -From “[email protected]” -SmtpServer ServerAddress -Subject “PC System Report” -body $EmailMessage

Ah ha, I needed to formulate a string in the block and return the string as the result of the Invoke-Command. I was successful in running the script and receiving the email.

Wrap Up

Oh, the power of PowerShell and the frustration when it doesn’t work. PowerShell is an awesome tool. If you have problems, don’t give up. Keep working it. After all, if you have the problems, chances are someone else had the same problem.

Leave a Reply