Welcome PowerShell User! This recipe is just one of the hundreds of useful resources contained in the PowerShell Cookbook.

If you own the book already, login here to get free, online, searchable access to the entire book's content.

If not, the Windows PowerShell Cookbook is available at Amazon, or any of your other favourite book retailers. If you want to see what the PowerShell Cookbook has to offer, enjoy this free 90 page e-book sample: "The Windows PowerShell Interactive Shell".

1.2 Run Programs, Scripts, and Existing Tools

Problem

You rely on a lot of effort invested in your current tools. You have traditional executables, Perl scripts, VBScript, and of course, a legacy build system that has organically grown into a tangled mess of batch files. You want to use PowerShell, but you don’t want to give up everything you already have.

Solution

To run a program, script, batch file, or other executable command in the system’s path, enter its filename. For these executable types, the extension is optional:

Program.exe arguments
ScriptName.ps1 arguments
BatchFile.cmd arguments

To run a command that contains a space in its name, enclose its filename in single quotes (') and precede the command with an ampersand (&), known in PowerShell as the invoke operator:

& 'C:\Program Files\Program\Program.exe' arguments

To run a command in the current directory, place .\ in front of its filename:

.\Program.exe arguments

To run a command with spaces in its name from the current directory, precede it with both an ampersand and .\:

& '.\Program With Spaces.exe' arguments

Discussion

In this case, the solution is mainly to use your current tools as you always have. The only difference is that you run them in the PowerShell interactive shell rather than cmd.exe.

Specifying the command name

The final three tips in the Solution merit special attention. They are the features of PowerShell that many new users stumble on when it comes to running programs. The first is running commands that contain spaces. In cmd.exe, the way to run a command that contains spaces is to surround it with quotes:

"C:\Program Files\Program\Program.exe"

In PowerShell, though, placing text inside quotes is part of a feature that lets you evaluate complex expressions at the prompt, as shown in Example 1-1.

Example 1-1. Evaluating expressions at the PowerShell prompt
PS > 1 + 1
2
PS > 26 * 1.15
29.9
PS > "Hello" + " World"
Hello World
PS > "Hello World"
Hello World
PS > "C:\Program Files\Program\Program.exe"
C:\Program Files\Program\Program.exe
PS >

So, a program name in quotes is no different from any other string in quotes. It’s just an expression. As shown previously, the way to run a command in a string is to precede that string with the invoke operator (&). If the command you want to run is a batch file that modifies its environment, see Recipe 3.5.

Note

By default, PowerShell’s security policies prevent scripts from running. Once you begin writing or using scripts, though, you should configure this policy to something less restrictive. For information on how to configure your execution policy, see Recipe 18.1.

The second command that new users (and seasoned veterans before coffee!) sometimes stumble on is running commands from the current directory. In cmd.exe, the current directory is considered part of the path: the list of directories that Windows searches to find the program name you typed. If you are in the C:\Programs directory, cmd.exe looks in C:\Programs (among other places) for applications to run.

PowerShell, like most Unix shells, requires that you explicitly state your desire to run a program from the current directory. To do that, you use the .\Program.exe syntax, as shown previously. This prevents malicious users on your system from littering your hard drive with evil programs that have names similar to (or the same as) commands you might run while visiting that directory.

To save themselves from having to type the location of commonly used scripts and programs, many users put commonly used utilities along with their PowerShell scripts in a “tools” directory, which they add to their system’s path. If PowerShell can find a script or utility in your system’s path, you do not need to explicitly specify its location.

If you want PowerShell to automatically look in your current working directory for scripts, you can add a period (.) to your PATH environment variable.

For more information about updating your system path, see Recipe 16.2.

If you want to capture the output of a command, you can either save the results into a variable, or save the results into a file. To save the results into a variable, see Recipe 3.3. To save the results into a file, see Recipe 9.2.

Specifying command arguments

To specify arguments to a command, you can type them just as you would in other shells. For example, to make a specified file read-only (two arguments to attrib.exe), simply type:

attrib +R c:\path\to\file.txt

Where many scripters get misled when it comes to command arguments is how to change them within your scripts. For example, how do you get the filename from a PowerShell variable? The answer is to define a variable to hold the argument value, and just use that in the place you used to write the command argument:

$filename = "c:\path\to\other\file.txt"
attrib +R $filename

You can use the same technique when you call a PowerShell cmdlet, script, or function:

$filename = "c:\path\to\other\file.txt"
Get-Acl -Path $filename

If you see a solution that uses the Invoke-Expression cmdlet to compose command arguments, it is almost certainly incorrect. The Invoke-Expression cmdlet takes the string that you give it and treats it like a full PowerShell script. As just one example of the problems this can cause, consider the following: filenames are allowed to contain the semicolon (;) character, but when Invoke-Expression sees a semicolon, it assumes that it is a new line of PowerShell script. For example, try running this:

$filename = "c:\file.txt; Write-Warning 'This could be bad'"
Invoke-Expression "Get-Acl -Path $filename"

Given that these dynamic arguments often come from user input, using Invoke-Expression to compose commands can (at best) cause unpredictable script results. Worse, it could result in damage to your system or a security vulnerability.

In addition to letting you supply arguments through variables one at a time, PowerShell also lets you supply several of them at once through a technique known as splatting. For more information about splatting, see Recipe 11.14.

See Also

Recipe 3.3, “Store Information in Variables”

Recipe 3.5, “Program: Retain Changes to Environment Variables Set by a Batch File”

Recipe 11.14, “Dynamically Compose Command Parameters”

Recipe 16.2, “Modify the User or System Path”

Recipe 18.1, “Enable Scripting Through an Execution Policy”