Noob help please. I\'m trying to write a script that will check if a process is running, and if not, start it. If the process is running, it should do nothing. I\'ve come up wit
In the Get-Process cmdlet, the process name argument must be the name of the executable without the file extension. Try substituting $Prog = "C:\utilities\prog.exe"
with $Prog = "prog"
.
In my opinion, your script would be more readable if you filtered the process out using the Where-Object cmdlet instead. Here's an example:
$programName = "prog"
$isRunning = (Get-Process | Where-Object { $_.Name -eq $programName }).Count -gt 0
if ($isRunning)
# ...
else
# ...
That way you can get rid of the -ErrorAction SilentlyContinue
argument, which can be confusing to someone who is not aware of the fact that Get-Process throws an error if it can't find a process with the specified name.
First of all, here's is what is wrong in your code. In your code, the process is created before you evaluate whether your program is already running
$Prog = "C:\utilities\prog.exe"
$Running = Get-Process prog -ErrorAction SilentlyContinue
$Start = ([wmiclass]"win32_process").Create($Prog) # the process is created on this line
if($Running -eq $null) # evaluating if the program is running
{$Start}
It is possible to create a block of code that should be evaluated further in your code by wrapping it in {} (a scriptblock):
$Prog = "C:\utilities\prog.exe"
$Running = Get-Process prog -ErrorAction SilentlyContinue
$Start = {([wmiclass]"win32_process").Create($Prog)}
if($Running -eq $null) # evaluating if the program is running
{& $Start} # the process is created on this line
However, if you're looking for a short one-liner to solve your problem:
if (! (ps | ? {$_.path -eq $prog})) {& $prog}
$path = "C:\utilities\prog.exe"
$list = get-process | where-object {$_.Path -eq $path }
if ($list -eq $null) { start-process -filepath $path }
Or
$path = "C:\utilities\prog.exe"
get-process | where-object {$_.Path -eq $path } | measure-object | where-object { $_.Count -eq 0} | foreach-object {start-process -filepath $path }
This will save you the if statement and one variable declaration. It can be a one line command as well:
Don't let the foreach at the end put you off. The measure object will return only one item the where will return one or zero. The foreach is only used to execute if the result is zero. It won't start more then one processes. :)
Keep in mind that PowerShell handles objects and not just text. While in normal batch files you could set a variable to a string and then just use it as a command:
set Foo=dir /b
%Foo%
... this doesn't work in PowerShell. Thus your assignment of $Start
already creates the new process since the command after the =
is run and its result assigned to $Start
.
Furthermore you're complicating things needlessly. I'd suggest the following instead:
$Running = Get-Process prog -ErrorAction SilentlyContinue
if (!$Running) { Start-Process C:\utilities\prog.exe }
Since Get-Process
returns an object (which evaluates to $true
) or $null
(which evaluates to $false
) you can simplify the check like shown above. This is called type coercion, since the if
statement expects a boolean value and the rules on what will be treated as $true
and $false
are very consistent in such cases as above. And it reads nicer.
I also used the Start-Process
cmdlet instead of WMI to create the new process. You could even use the following:
if (!$Running) { C:\utilities\prog.exe }
if the application is not a console application (and thus would block the PowerShell script until it exits). PowerShell is still a shell, so starting programs is something that works natively very well :-)
You could even inline the $running
variable, but I guess a comment would be in order to clarify what you do, then.