You can use PowerShell to run an executable (exe). However, you have to consider a few things.
Latest posts by Timothy Warner (see all)

PowerShell and external commands

PowerShell and external commands

Many of my Windows systems administrator friends know that they can run commands such as the following successfully from a PowerShell console session:

PS C:\> ping www.4sysops.com
PS C:\> notepad 'C:\file.txt'
PS C:\> ipconfig /all

On the other hand, I’m somewhat surprised at how few of these sysadmins understand why and how PowerShell allows these commands run an exe in the first place. Well, I’m here to teach you both the theory and the practice.

The basics

We can execute programs such as ping and notepad because their enclosing directory paths (C:\Windows\System32 and C:\Windows, respectively) exist in the Windows search path by default. See here:

PS C:\> Get-ChildItem -Path env:\path | Format-List
Name  : Path
Value  : C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft SQLServer\110\Tools\Binn\;C:\Program Files

When PowerShell detects “oldie but goodie” command-line tools such as nslookup, ipconfig, and net, the parser fires up an on-the-spot Cmd.exe instance and gives temporary control to those programs.

Let’s use a practical example to illustrate. On my system, I use the free and open-source 7-Zip utility for my file archiving and expansion needs. 7-Zip includes a command-line utility named 7z.exe that exists in the directory path C:\Program Files\7-zip.

As you can see, “dot slashing” the call to 7z.exe fails unless we first navigate to the proper directory:

PS C:\> ./7z.exe
Command './7z.exe' cannot be found.

PowerShell can run external tools

PowerShell can execute an exe, but you need to be explicit in your instructions.

Let’s add that path to our system search path and try again:

$env:Path = $env:Path + ';C:\Program Files\7-zip'

The previous statement works all day long; however, you’ll find that the new environment variable disappears after you close the current PowerShell session! To make a permanent change, we’ll need to tap more directly into the .NET Framework by using the [Environment] type accelerator:

[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\7-zip", [EnvironmentVariableTarget]::Machine)

Note that you’ll need to open a new PowerShell session to see the change.

The call operator

Sublime Text is my favorite text editor, and I can run the program on my workstation by running the following two lines of PowerShell code:

cd 'C:\Program Files\Sublime Text 3\subl.exe'
.\subl.exe

However, the following statement fails:

PS C:\> 'C:\Program Files\Sublime Text 3\subl.exe'
C:\Program Files\Sublime Text 3\subl.exe
PS C:\>

PowerShell politely runs executables that exist inside search path directories, as previously discussed. Likewise, if we’re in the target directory already, the “dot slash” (./) notation explicitly instructs PowerShell to treat the file as executable. That’s fine.

The problem in the above example is that PowerShell has no earthly idea that subl.exe is an executable. As far as the PowerShell parser is concerned, we simply defined an anonymous string. What’s cool, though, is that we can use the call operator (&) to notify PowerShell that the target resource is, in fact, executable:

PS C:\> & 'C:\Program Files\Sublime Text 3\subl.exe'

Passing arguments - where the fun begins

Thus far, you may be thinking, “Tim, you’re not teaching me anything new!” Perhaps you already understood environment variables and even the call operator. Fair enough. But have you ever tried to run an external command in PowerShell that used arguments?

Sure, PowerShell can handle switch parameters and key/value arguments on the most popular network utilities, like so:

PS C:\> ping -f -n 1 -l 1 203.113.0.32
PS C:\> ipconfig /all

However, you’ll find that PowerShell gets a bit...confused...when you use lesser-known command-line tools.

For instance, let’s imagine I have a command-line tool named whizbang.exe that fails spectacularly when I send arguments like so:

PS C:\tools\whizbang> ./whizbang.exe -host server01 -retry 5

The following solution is a bit hacky, but it’s the best we have, even as of PowerShell v5. First, we call the executable with & and then use the --% (that’s two dashes and a percent sign) escape character to instruct PowerShell to ignore what follows and pass it through to the referenced executable:

PS C:\tools\whizbang> & ./whizbang --% -host server01 -retry 5

The following approach, though much more formal, also works. Here, we define variables for each external command element, and then plug the variables into our call:

$exe = 'C:\tools\whizbang\whizbang.exe'
$host = 'server01'
$retry = 5
& $exe -host $host -retry $retry

That last statement reminds me of Perl. 🙂

Splatting

The last method I want to show you involves splatting. In splatting, we pass a hash table into a command and PowerShell spreads out the hash table contents to be used as parameters. To do this, we first create a hash table that contains our arguments and their values:

$a = @{
    Host = 'server01'
    retry = 5
}

By the way, a hash table, also called an associative array, is simply a collection of key/value pairs that we can treat as a unit or by its constituent parts.

We finish by running the exe and passing the hash table variable:

& $exe @a
7 Comments
  1. AceyMan 8 years ago

    Thanks for the concise guide; using external executables in PoSH is kind of tricky, so this is rather helpful.

    Note: Errata regarding the last example on _splatting_, viz;

    $args is a built-in, automatic variable [0], so we cannot choose that name as your example shows. When constructing a hash table to pass to the executable it’d need to be a name other than $args

    [0] https://technet.microsoft.com/en-us/library/Hh847768.aspx

  2. Author

    Hi AceyMan. You’re right of course–thanks for pointing it out. I’ll submit a change request immediately. Peace, Tim

  3. Basit 7 years ago

    Thank you so much! I was looking for a way to save the executable directory into powershell so I call call it later without navigating to it’s directory.

    This solved it for me: [Environment]::SetEnvironmentVariable(“Path”, $env:Path + “;C:\Program Files\7-zip”, [EnvironmentVariableTarget]::Machine)

  4. Neeraj 6 years ago

    Hi Timothy Warner,

    Thanks for sharing the wonderful content. I am getting error while executing an exe file for sQL server patch on remote computer using invoke-command. The command runs without any error but do not start the patching process.

    Command is: $A = “$Servicepack /action=patch /InstanceName=$Instance /IAcceptSQLServerLicenseTerms”
    $Server = $GetPatchFile.servernames
    invoke-command -ComputerName $Server scriptblock{$PatchCMD}

    $server shows the servername and $a shows correct statement to execute patching but it doesn’t start the patching process.

    Please help with this?

    THanks,
    Neeraj

  5. Neeraj 6 years ago

    Command is:

    $Servicepack = “Location of service pack”

    $PatchCMD = “$Servicepack /action=patch /InstanceName=$Instance /IAcceptSQLServerLicenseTerms”
    $Server = $GetPatchFile.servernames
    invoke-command -ComputerName $Server scriptblock{$PatchCMD}

  6. NeoBeum 4 years ago

    For lazy people like myself;

    Get-ChildItem -Path env:\path | Format-List

    can be shortened to:

    $env:path

  7. nimaj 3 years ago

    Thank you!! This is by far the best article I’ve found on this with some truly unique solutions. Love it.

    avatar

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account