Windows prompt tricks

Command-line shells are powerful tools, even the best UI can’t be as flexible as a command prompt. Especially if you want to use multiple programs at once, pipe output of one into input of another, etc. But if your workstation happens to be a Windows machine, it can be a struggle. Seriously, cmd.exe is a very poorly engineered command prompt, and that was the only reasonable built-in command-line until PowerShell was introduced in around 2006.

We poor Windows users face many challenges. Let’s dive into this rabbit hole…

Cmd.exe sucks

Working with cmd.exe, particularly scripting in .bat files, is a rage inducing activity. Chiefly, you can’t really prevent variable expansion from wrecking your script, because the interpreter first expands variables and then interprets the result. Consider the following:

set foo=bar^>file.txt

The value of foo is now bar>file.txt, we escapped > with ^ so that it is just a character rather than output redirection.

echo %foo%

But here, the line is first expanded into

echo bar>file.txt

and then interpreted, so that it echoes bar into file.txt.

You are probably not going to get rid of cmd.exe completely. You’ll often find cmd.exe solutions for your problems on the Internet. But for your own endeavors, there are good alternatives.

Cygwin & Bash

Cygwin, among other things, brings the power of Bash – a Unix shell to Windows. Knowing Bash is very transferable skill, since it runs almost everywhere, even on Windows apparently 🙂

You can grab cygwin at https://www.cygwin.com/

Cygwin arguably won’t let you do everything. It works well with files and whatever Cygwin programs you installed. On the other hand, the ps command will show only processes running inside Cygwin, so don’t expect to work with your Windows OS like it is actual Unix.

PowerShell

It’s the other prompt from MS and so far it looks like it works quite well. It doesn’t seem to be as poorly engineered as cmd.exe.

Insufficient privileges

You do not have sufficient privilege to perform this operation

So you have your nice cmd.exe or PowerShell instance in the right directory and are about to perform the operation you need and then this happens. You’d like to elevate your prompt, but there’s no easy way to do that.

I don’t think there is a way to elevate your current instance, but there is a way to launch a new elevated instance in the same directory. Let’s make a script to do the heavy lifting.

  1. Pick a directory for helper script and add it to path
    1. Start -> type “View advanced system settings” and open it
    2. Click Environmental Variables…
    3. In the bottom table find “Path” and double click
    4. Add the directory
  2. Download and add following scripts to the directory:
    1. elevate.ps1
    2. elevate.bat
    3. elevatecmd.ps1
  3. Make sure PowerShell scripts are allowed to run, see this superuser.com answer
How does it work?

When you use “elevate” from cmd.exe, it ignores .ps1 scripts, so it runs elevate.bat, which executes elevatecmd.ps1. When you use “elevate” from PowerShell, it prefers elevate.ps1 over the batch file.

In both cases, this will launch a new PowerShell Window as Administrator and if User Access Control is enabled, you will be prompted if you want to allow PowerShell to make changes to your device.

Let’s look at elevate.ps1.

$here = gl
Start-Process powershell `
    -ArgumentList "-NoExit -Command & {cd '$here'}" -verb RunAs

Start-Process supports the “-verb RunAs” argument, this is what asks to run the process as admin. The process to be run is PowerShell. If we used just

Start-Process powershell -verb RunAs

then the new PowerShell would start in the default directory. That would be awkward, so we need to tell the new PowerShell instance to start in different location. The Start-Process -ArgumentList allows us to pass arguments to the new PowerShell. The arguments are

-NoExit -Command & {cd '$here'}

The -Command part tells the new PowerShell to execute a command. Normally PowerShell would exit after doing so, so we pass -NoExit as well. The command changes the directory from defaut starting directory to the one we actually want.

The cmd.exe version is similar, we just want to an elevated cmd.exe rather than PowerShell, so there’s an extra command to run cmd.exe.

$here = gl
Start-Process powershell `
    -ArgumentList "-NoExit -Command & {cd '$here'; cmd.exe}" -verb RunAs
Bash sudo

Personally, I didn’t run into a situation where I needed Bash to run as admin… yet. It can happen though and that’s what the sudo command is normally for. Except it’s not available on Cygwin. But apparently, you can make one yourself.

Morphing prompts

Let’s say you have an instance of prompt X but you want prompt Y instead. If you want PowerShell or cmd.exe then you can just type PowerShell or cmd.exe and it’s done.

But if you want to switch to Cygwin Bash from PowerShell/cmd.exe, then it’s not that simple. You can run bash by typing

C:\cygwin\bin\bash.exe

but it doesn’t run in correct environment and even basic commands like ls don’t work. So I added mintty.bat in the same directory as elevate.bat (included with the other scripts). It launches a new instance of my favorite terminal mintty with correct environment. Similarly to the elevate scripts, I had to convince mintty/bash to open in the current directory.

@setlocal

Don’t affect caller’s environment by setting variable values.

@set directory=%cd%

Get the current working directory.

@set directory=%directory:C:\=/cygdrive/c/%
@set directory=%directory:\=/%

In Cygwin, paths are denoted differently than on Windows, so the above should convert the drive designation and flip slashes. It works only for C drive now, I guess you’d have to add more lines to handle other drives.

@C:\cygwin\bin\mintty.exe --dir "%directory%" ^
    /bin/env CHERE_INVOKING=1 /bin/bash -l

The directory is passed via –dir “%directory%”, we also tell mintty to run in the right environment (don’t ask me how those parameters work, I googled it and it worked) and to use bash.

Open a prompt from Explorer

On Windows 10, you can right-click in Explorer.exe window and as long as you don’t select anything, it give the option to “Open PowerShell window here”. If I recall correctly, Windows 7 offer command prompt. It doesn’t matter much which one it opens, since we already know how to quickly morph and elevate the prompt anyway.

It is totally possible to add other options to the context menu, other prompts and/or elevated prompts, but I don’t feel it’s worth the real estate cost, since we already have a solution to reach them.