PowerShell How-To

Use PowerShell Parameters Instead of Interactive Prompts

Increase the usage of your code snippets by creating them with a universal approach.

Each of us has our own unique way of solving a problem with PowerShell. We all tend to code how we think; linearly. Our brains go from point A to point B -- sending those messages to our fingers -- and ultimately the code follows. The problem with this approach is that we tend to group distinct code snippets all together when we should be treating the code like distinct building blocks. Let me give you an example.

Let's say I want to query a server to determine whether any of the services are running under a certain EXE. I'm thinking ahead and I intend on making this script query not just a single server, but multiple servers and different EXEs. (I'm writing a more flexible script now in case I need this functionality later.) To do this, I'll start building my script by getting some input from the user for a group of server names and getting the EXE file name. I might as well provide the user with some feedback about what it's doing, so I'll add a Write-Host line after the script has captured the input.

$Servers = Read-Host -Prompt 'Please input one of more server  names separated by a comma'
$ExeFile = Read-Host -Prompt 'Please input the EXE file name to search for'
Write-Host "You're querying server '$Servers' for the EXE file '$ExeFile'"

When the script is run, the user can input the server name and the EXE file she's looking for. Yay!

[Click on image for larger view.] 

Now I have a way to get variable input into my script. The next step is to actually do something with this input. Because I'm trying to get the actual EXE files that are running my services, I can't use the Get-Service cmdlet, unfortunately. Instead, I'm forced to use CIM. So let's add a step to the script that finds all the services behind my EXE file on all the servers I've specified.

$Services = Get-CimInstance -Computername $Servers -ClassName  Win32_Service -Property DisplayName,PathName | Select-Object  DisplayName,PathName
$Services | Where-Object {$_.PathName -like '*$ExeFile'}

We should now have a functioning script. Let's run it again and see what I come up with.

[Click on image for larger view.] 

Great! You can see I was able to query my server, named LABDC, for any of the services running under an EXE file named Microsoft.ActiveDirectory.Webservices.exe. I've completed the task at hand, and I'm ready to go about my day.

Two months later …

Again, a need has come up to find the EXE files behind services. But this time, a coworker has given me a list of server names in a text file. So how do I feed these server names into my script? You'll recall I only had a single server previously, so I could just prompt for the name and type it in. This time, I've got dozens of server names, and I'm not about to copy and paste all those names one at a time into this script. This is the downside of creating interactive prompts inside your script. They completely box in your script, keeping it from other uses.

Here's how this script should have been written from the beginning.

param([string[]]$Servers,[string]$ExeFile)

$Services = Get-CimInstance -Computername $Servers -ClassName Win32_Service -Property DisplayName,PathName | Select-Object DisplayName,PathName
$Services | Where-Object {$_.PathName -like "*$ExeFile

Notice how I've turned the two Read-Host lines into parameters of the script itself? By converting the interactive prompts to parameters, I can now support one or many servers, which will provide just about any kind of input I need. In this case, it's a text file full of server names.

By changing those interactive prompts to parameters, I can now specify a server as well as the EXE file in a single like the below screenshot.

[Click on image for larger view.] 

I can also easily adapt our script to multiple servers in a text file as shown in the below screenshot.

[Click on image for larger view.] 

The key here is to avoid using interactive prompts unless you absolutely need them. Instead, use parameters. If you must use interactive prompts, try to separate them as much as possible from your "working" code. Perhaps you can include your prompts in a function you can easily swap out -- or put them in a separate script altogether. Go for as much separation as possible to make modifying your script later as easy as possible.

About the Author

Adam Bertram is an independent consultant, technical writer, trainer and presenter. Adam specializes in consulting and evangelizing all things IT automation mainly focused around Windows PowerShell. Adam is a Microsoft Windows PowerShell MVP, 2015 powershell.org PowerShell hero and has numerous Microsoft IT pro certifications. He is a writer, trainer and presenter and authors IT pro course content for Pluralsight. He is also a regular contributor to numerous print and online publications and presents at various user groups and conferences. You can find Adam at adamtheautomator.com or on Twitter at @adbertram.

comments powered by Disqus

SharePoint Watch

Sign up for our newsletter.

I agree to this site's Privacy Policy.