• Home
  • Contact
  • About
  • RSS

dustin.io

Menu
  • Home
  • Contact
  • About
  • RSS

Running legacy command line commands in PowerShell

Written by Dustin Tatgenhorst
September 27, 2016 PowerShell cmd, cmd.exe, command, powershell Leave a Comment
Share:
Share on Facebook
Share on Twitter
Share on Google+
Share on LinkedIn
Share on Pinterest
Share on Reddit
Share on Whatsapp

Last week I was asked by two different colleagues to help them sort out some issues they were having running old command prompt (cmd.exe) commands in a PowerShell script or shell environment.  On its face it seems like an odd question, since almost all command prompt commands and EXEs run without issue in PowerShell.  But, there are a few subtle gotchas that do come up, so I thought I’d write a quick post to point out these lesser-known issues and some ways to deal with them.

For the few edge cases where PowerShell does indeed trip up on older commands, most, if not all, of these issues stem from characters in the legacy command (parameters and/or switches) colliding with or having a different meaning in PowerShell than they do in the command prompt.  A few examples are:

  • Passing in computer objects or machine account names like COMPUTERNAME$ as parameters (computer objects end in $, but in PowerShell, $ has a special meaning)
  • Collisions where a legacy executable has the same name as a PowerShell cmdlet or alias, but are not the same command (think sc.exe and the PowerShell alias sc for Set-Content)
  • Commands that use parentheses as part of their parameters which, again, have a different meaning in PowerShell (icacls.exe is the only one coming to mind at the moment, but there may be more)

To deal with these commands in PowerShell, you have a number of options:

  • Use a PowerShell equivalent to the command you are trying to run
  • Use PowerShell’s escape character to escape out the characters being misinterpreted
  • Use PowerShell’s –% sequence in the legacy command to stop parsing the rest of the command as PowerShell syntax (requires PowerShell v3 or later)
  • Explicitly pass your command to the cmd.exe shell itself for execution

 

Use the PowerShell equivalent

I’ll first mention the most obvious (and preferred) way to resolve this issue: use the PowerShell equivalent of the command prompt command you are trying to run.  Under the hood, many of the old commands are just aliases of new PowerShell cmdlets anyway (dir is an alias for Get-ChildItem, for example).  And yes, even though cmdlets usually require more typing (Get-ChildItem instead of dir, or Test-Connection instead of ping), it’s not a bad habit to get into.  Also, tab completion is your friend.  And who knows, one day your brilliant code may be distributed to others in your company or online, so avoiding legacy commands as much as possible keeps things as modern and portable as possible, and is technically faster execution-wise (see below).

 

Use PowerShell’s escape character

If you cannot, for whatever reason, use a PowerShell equivalent (or there just isn’t one), a second option is to escape out the offending characters that are breaking the command execution.  If you know which character(s) are causing PowerShell to misinterpret the command prompt command, you can use PowerShell’s escape character (the backtick, or `) to escape out that character.  For example:

1
icacls.exe C:\inetpub /grant Users:`(R`)

will allow this command to run correctly in PowerShell because the backticks are telling to PowerShell to interpret the parentheses literally, in the same way you would escape out special characters in a string.

 

Use PowerShell’s “- -%” sequence

Similar to using the escape character above, PowerShell v3 and later support using –% (“dash dash percent”) as a way of telling PowerShell to stop interpreting whatever follows that sequence as PowerShell syntax.  Using the example command from above, either one of the following would work:

1
icacls.exe --% C:\inetpub /grant Users:(R)

1
icacls.exe C:\inetpub --% /grant Users:(R)

Think of the –% as another parameter in your command prompt command.  The 2 things to remember when using this method are:

  • Do not start the command line with this sequence.  For example, this will not work:

1
--% icacls.exe C:\inetpub /grant Users:(R)

  • PowerShell will stop interpreting as PowerShell syntax anything after the –%

 

Explicitly pass the legacy command to cmd.exe for execution

I list this one last because, in my opinion, it is the least desirable, and is less efficient resource-wise than the other methods listed above.  With that said, one other solution is to explicitly pass the command you want to run (in quotes) to the cmd.exe shell for execution using the /c switch.  This was also a trick back in the day when you wanted to execute batch or shell commands in VBS scripts.  So, for example, doing this:

1
cmd.exe /c "sc query eventlog"

will execute the sc.exe command as you would expect.

Small side-note: for the case of very specific collisions like the sc.exe command and sc alias, typing the full executable command with it’s extension (sc.exe) will often resolve the problem.  As a PowerShell command, sc can mean the executable sc.exe or the alias sc.  By typing sc.exe as the command, the ambiguity is removed and the shell knows how to proceed.

As I mentioned above, one minor thing to note about using this cmd.exe /c method is that it will be slower than the other ways mentioned in this post.  What’s really happening behind the scenes is that our PowerShell process is spawning a separate cmd.exe process, and that cmd.exe process will then execute your command. The spawning of these additional processes has computational overhead and cost in terms of performance and resources.  If only done once or a few times, this difference is almost imperceptibly negligible.  However, if this is part of a script or process that runs often, loops in any way, or acts on many objects, those costs in resources and execution time may become a factor and lead you to choose one of the other methods mentioned here.


Also published on Medium.

Related

Share:
Share on Facebook
Share on Twitter
Share on Google+
Share on LinkedIn
Share on Pinterest
Share on Reddit
Share on Whatsapp

Leave a Reply Cancel reply

  • Popular Posts
  • Recent Posts
  • Running legacy command line commands in PowerShell September 27, 2016
  • Running legacy command line commands in PowerShell September 27, 2016

Recent @dustin_io tweets:

My Tweets

Categories

  • PowerShell
© Copyright 2019 Dustin Tatgenhorst