The woes of PowerShell

Here is my initial experience with Windows PowerShell, Microsoft’s attempt to give Windows something better than the (ancient and extremely arcane) UNIX command line. This should not have been hard — with a fresh start and a funded team it’d be difficult to not produce something better than the UNIX command line: a toolset that was mostly organically grown rather than designed, and which is dragged down by over three decades of legacy.

But Microsoft managed it all the same. This article is here to save you time. If you are used to UNIX and need to achieve some basic scripting task in Windows you may be tempted to explore PowerShell, as it’s the current “state of the art” in Windows command lines.

Ideally, don’t: PowerShell feels like it was built by people who had heard about command lines a long time ago and tried to recreate one based on stories passed down through generations of their ancestors. It may well be a powerful and appropriate tool for Windows sysadmins who have taken the time to learn it. But if you have a UNIX background and for some reason you do want to use it, here is what it’s like.

The terminal emulator cannot be resized beyond about half the width of the screen. Selection of text is based on squares not lines, so you can’t easily copy and paste a command if it wraps onto a new line. Because of the first problem this is quite common. You can get a program called “Console”, which does a slightly better job. You will have to configure it to run PowerShell explicitly as it doesn’t come that way out of the box. This lets you resize the terminal at least, but don’t expect anything fancy like reverse i-search.

To run a program from the PowerShell command line, you must start with an & symbol. This has nothing to do with the bash use of & which goes at the end of a command and puts it into the background. Omitting the & means PowerShell will simply print the name of the program you want to run.

On UNIX, shell scripts use the .sh file extension, if they have one. So it’d make sense that PowerShell scripts end in .psh. In fact they end in .ps1 (that’s a one, not a lowercase i).

But don’t try and actually put your copied command into a .ps1 file and run it. Attempting to run a script from the PowerShell command line on Windows 8.1 yields this error:

.\my-script.ps1 : File Y:\my-script.ps1 cannot be loaded because running scripts is disabled on this system. For more
information, see about_Execution_Policies at
At line:1 char:1
+ .\win-build.ps1
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : SecurityError: (: ) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess

Out of the box, PowerShell cannot actually run its own scripts.

You may notice that although this error gives you a link to a web page, the document itself (“about_Execution_Policies”) is formatted like a man page. This combines the convenience of an external web page with the richness of 1970's era ASCII text. That is no co-incidence: PowerShell has an equivalent of man pages and this is one of them. The equivalent of “man” is called “Get-Help” so let’s try it:

PS C:\> Get-Help about_execution_policies
Get-Help : Get-Help could not find about_execution_policies in a help file in this session. To download updated help topics type: “Update-Help”. To
get help online, search for the help topic in the TechNet library at
At line:1 char:1
+ Get-Help about_execution_policies
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (☺ [Get-Help], HelpNotFoundException
+ FullyQualifiedErrorId : HelpNotFound,Microsoft.PowerShell.Commands.GetHelpCommand

Or not. PowerShell does not come with help installed by default. Following its advice yields another error:

PS C:\> Update-Help
Update-Help : Failed to update Help for the module(s) ‘Microsoft.PowerShell.Management, Microsoft.PowerShell.Utility,
Microsoft.PowerShell.Diagnostics, Microsoft.PowerShell.Host, Microsoft.PowerShell.Security, Microsoft.WSMan.Management, Microsoft.PowerShell.Core’ :
The command could not update Help topics for the Windows PowerShell core modules, or for any modules in the $pshome\Modules directory. To update these
Help topics, start Windows PowerShell by using the “Run as Administrator” command, and try running Update-Help again.
At line:1 char:1
+ Update-Help
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (☺ [Update-Help], Exception
+ FullyQualifiedErrorId : UpdatableHelpSystemRequiresElevation,Microsoft.PowerShell.Commands.UpdateHelpCommand

This error is saying we need to run Update-Help as root (administrator) in order to install the help docs. PowerShell does not have any equivalent of sudo or su. As the error says, we must start a new copy of Console using the “Run as administrator…” option in the right click menu in Explorer and then try again. You can also try:

Start-Process powershell -runAs

… but then you’re back to the default terminal emulator.

Get-Help now runs, but the content is just dumped the console. Apparently there’s no equivalent for less? Except yes, there is. It turns out if we run “man about_execution_policies” then we do get the old DOS “more” pager — it’s just not used when you run the native PowerShell command.

The help page is not particularly helpful (it does not contain the actual command I want as an example and has some typos in it), but badly written man pages are a plague on UNIX too. The right fix is to run this in the administrator console:

Set-ExecutionPolicy Unrestricted

Now you can run your .ps1 script.

The command set PowerShell has is not a perfect match for what UNIX provides. For example there is a command to retrieve the AuthentiCode signature on an executable but none which hashes a file (shasum).

Still, the commands that do exist often have aliases so people used to UNIX or batch can get started quicker.

PS C:\> cd $HOME
PS C:\Users\mike> cat one.txt
This is a two line file
that has some text in it

That’s promising! Let’s try something a bit more ambitious:

PS C:\Users\mike> diff one.txt two.txt
InputObject SideIndicator
—————- ——————-
two.txt =>
one.txt <=

Here, it’s interpreted the arguments as strings and is giving us a “diff” (lol) of those two strings. We can try to fix it:

PS C:\Users\mike> diff (cat one.txt) (cat two.txt)
InputObject                              SideIndicator
----------- -------------
that has some INTERESTING! text in it =>
that has some text in it <=

Slightly better, but still not that useful.

Wikipedia has a translation table between common UNIX and PowerShell commands. But again, this is of limited use:

PS C:\Users\mike> sls -pattern text one.txt
one.txt:2:that has some text in it

We have a grep-like thing that works. The table also contains wget, let’s try it:

PS C:\Users\mike> wget

StatusCode : 200
StatusDescription : OK
Content : <!doctype html><html itemscope=”” itemtype=”" lang=”de-CH”><head><meta
content=”/images/google_favicon_128.png” itemprop=”image”><title>Google</title><script>(function(){windo…
RawContent : HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
Date: Fri, 10 Oct 2014 13:12:16 GMT
Expires: -1
Set-Cookie: PREF=ID=2cc496cb4a5dcadf:FF=0:TM=1412946736:LM…
Forms : {f}
Headers : {[Cache-Control, private, max-age=0], [Content-Type, text/html; charset=UTF-8], [Date, Fri, 10 Oct 2014 13:12:16 GMT], [Expires,
[lots more snipped]

At this point we realise the truth — PowerShell is not designed to be an actual shell for users, as you would expect from the name. Running “wget” does not download the URL to a file. PowerShell is actually a very verbose and vaguely shell-looking object oriented .NET scripting language. It may well be a good fit for someone trying to achieve a complex programming task in the Windows environment, and it makes a very very basic attempt to be welcoming to people used to other operating systems, but trying to use it interactively like a UNIX shell will end in immediate and total failure.