Use PowerShell to Start Random Processes at Random Times


Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create random processes at random times.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to start a process that I pick randomly from a list. I would like these processes to start at random times so I can test my monitoring application. Is this something Windows PowerShell can do?

—JD

Hey, Scripting Guy! Answer Hello JD,

Microsoft Scripting Guy, Ed Wilson, is here. This morning, I am sipping a cup of Darjeeling tea that I made with spearmint, licorice root, and a cinnamon stick. The taste is understated, and quite nice. It goes well with the Irish steel-cut oats and blueberries that I am having for breakfast. I am sitting in the kitchen this morning (it is raining outside) and eating at the counter. I have my Surface Pro 3 with me, and I am checking email sent to scripter@microsoft.com.

Create random processes the easy way

If you really want the path to an executable that is random, the easy way to do it is to use the Get-Command cmdlet, and search for *.exe. This will return a CommandInfo object that has a Path property. I would then feed that to the Get-Random cmdlet as an InputObject. Here is a command that would work for this:

Get-Random -InputObject (Get-Command *.exe) | Select path

The output displays the complete to the executable. Here is an example:

PS C:> Get-Random -InputObject (Get-Command *.exe) | Select path

Path

----

C:WINDOWSSYSTEM32gpresult.exe

A safer approach

The issue with the previous approach of gathering really random executables is that if I later decide I want to launch the executables, I could really get some dangerous and unpredictable results. A safer approach is to create an array of executable names, use Get-Command to find the path, and send that to Start-Process. In this way, I can ensure that I am only starting processes that I want to start. Not really random processes, but launching known processes in a random order.

Because I need to create an array of strings, it would normally mean using a lot of quotation marks and commas, and extra typing. I then assign it to a variable to hold the array. But I was recently watching Todd Klindt’s Netcast, and he used a trick that I had forgotten about. I have added it back to my repertoire. The secret is to create a string that contains commas, and then use the Split method to create the array. It is simple and fast. Here is an example of what I am talking about:

First the old way:

$a = "mspaint.exe","write.exe","calc.exe","notepad.exe"

Now for the new way:

$a = "mspaint.exe,write.exe,calc.exe,notepad.exe".Split(',')

I like doing this because although it is a little bit more typing (only a couple extra key strokes), it is easier to type. I don’t like having to hold down the Shift key and then pressing the quotation mark. (Actually, if I include Shift in my keystroke count, it is a real savings in typing.)

Getting the random process names from the array

It is possible to index into the array to get the process names. To do this, I might use a command such as the following:

PS C:> $a

mspaint.exe

write.exe

calc.exe

notepad.exe

PS C:> $r = Get-Random -Maximum 3 -Minimum 0

PS C:> $a.Item($r)

mspaint.exe

But that is cumbersome, and it uses extra lines of code and extra variables. In addition, if I later add additional executable names to the array, I have to update the Get-Random portion (an easy thing to forget). A better way to do this is to pass the array of executable names directly to Get-Random and let it handle the details. Here is the command:

Get-Random -InputObject $a

To make sure I have the path to the executable, I call the Get-Command cmdlet and select the path.

   Note  I could simply type the complete path to the executable in my array, but that is a lot of extra typing, and it is
   error prone. Using Get-Command is much simpler.

Here is the command I use to get the path to my randomly selected executable:

Get-Random -InputObject $a | Get-Command | select path

Unfortunately, the Start-Process cmdlet does not accept pipelined input. So I need to use a Foreach-Object cmdlet prior to calling the Start-Process cmdlet. So I use Get-Random to select random executable names, get the path by using Get-Command, and pass it to Start-Process. Here is the command:

Get-Random -InputObject $a | Get-Command | Foreach-Object {Start-Process $_.path}

Groovy…now put it with yesterday’s script

I am now ready to put my new command into the script I wrote yesterday in Use PowerShell to Start a Process at Random Times.  

After I do that, I will launch a randomly selected process from an array of executable names, and I will do so at random intervals.

Here is the complete script:

$prog = "mspaint.exe,write.exe,calc.exe,notepad.exe".Split(',')

while ($true)

{

 $rnd = Get-Random -Minimum 1 -Maximum 5

 Start-Sleep -Seconds $rnd

 Get-Random -InputObject $prog |

 Get-Command |

 ForEach-Object {

   start-process -FilePath $_.path -WindowStyle Minimized } }

   Note  Calculator does not start if it is minimized, but the other three processes will. So be aware of this prior to
   running the script.

JD, that is all there is to using Windows PowerShell to create random processes at random times. Process Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (1)

  1. Sven says:

    Hey Ed,

    First I like to say that i really like reading your Blog ^^.
    This is also a quite nice short Post. I just want to make one Suggestion as we are talking about saving typings 😉
    You wrote: "Unfortunately, the Start-Process cmdlet does not accept pipelined input. So I need to use a Foreach-Object cmdlet…"

    But wouldnt it be easier to change this line you wrote:
    Get-Random -InputObject $a | Get-Command | Foreach-Object {Start-Process $_.path}

    Into something like that?:
    Start-Process $(Get-Random -InputObject $a | Get-Command).Path

    As I think it is easier to read, shorter to write (for us lazy guys 😉 ) and we would avoid a call to the Foreach-Object Cmdlet, which is not necessary.

    I am really looking forward to some remarks.
    Have a good day, and Kind Regards from Germany

Skip to main content