Let me quickly establish my credentials:
- 15 years of experience in C# on windows
- 10 years of linux and extensive bash/posix/zsh usage pre-LLM
- made or debugged a variety of automation scripts in Powershell, NodeJS and Python, both at work and in my own projects
I have since stopped using Python and started using Golang for some tasks.
Reasons why I think Powershell is indefensible:
-
Nasty breakages between major versions which result in dozens of muddy failure modes, and you never know what is installed on any machine you find at the job.
I was given a freshly installed laptop from my job in the typical manner, I used it without being a sysadmin expert, and somehow I ended up with multiple versions of powershell, 5.x and 7.x. The contortions I witnessed GPT having to go through just to make a simple script work between those major versions reminded me of my own struggles over the years between versions 5 and 3, having to port stuff for our old servers, every line taking me tedious trial and error because I could not find the changes documented anywhere. That part might be my fault.
But what is the purpose of a shell if the maintainers break it every couple of years?! Doing that is fundamentally, obviously wrong in my opinion. Bash does not break all the time! -
The slow startup times!
You might say they are not a huge deal, but for me, these really cut into my flow as a coder when I’m trying to quickly launch some programs in a few new shells and have to wait literally seconds for just a single Powershell to come up. I then have to mentally backtrack to what I was doing, and then for the next tab of my terminal, I have to wait again, and again, and again. Microsoft, you had literally one job: Make a shell that does not suck. Boot times that look like the need access a spinning disk like in days of yore, on a blazing fast modern machine with a solid state drive, constitute a clear case of “sucking” and a level of inefficiency that I will not excuse. -
Too verbose
Note that I’m not calling PS ugly, but characters to type for my fleshy fingers and tokens to feed into an LLM are a real metric to judge a shell language, and it fails horrifically. The most basic built-in commands are so long I can’t even memorize them, not to talk about . And aliasing stuff to -
The primitives suck
PS> which node
which : The term 'which' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Ah yes, we are on windows, lets try the CMD version of “which”.
PS> where node
We get empty answer, because somebody decided we alias where to Where-Object, which filters items in the pipeline:
PS> 1..10 | Where-Object { $_ -gt 5 }`
6
7
8
9
10
I had to get help from Google/LLM to finally find out what the correct command is:
PS> Get-Command node
CommandType Name Version Source
----------- ---- ------- ------
Application node.exe 24.14.1.0 C:\Users\muellerd\AppData\Local\nvs\default\node.exe
Flipping finally! These paper cuts add up so much. Obviously none of them individually were made by malice, but this stuff is just extremely painful when working with any kind of UNIX system at the same time as working with a powershell system.
Would it have been too much to ask that while you were aliasing some stuff like ls and cat ive get-childitem (ls) feature parity with UNIX inin the -a flag for example etc in any Powershell from the absolute beginning, feature complete, a bit slower, but with all the flags for UNIX compat?
Instead, we get a zoo of slow, gap-toothed tools that do not properly align with UNIX.
This is unacceptable. It will also cause LLMs try to use rg or other primitives, fail, and trash around and burn a bunch of money and GPU time just to grep or ls or cat. Why could we not just had feature parity on at least some of those built into Powershell when it was designed?
-
Too complex to write for humans You would thing the syntax can’t be harder to memorize, write and debug than bash. That is true! Sadly, it is also not better. So what is the point? If I have to bring out the LLM anyway, I might as well generate a real program for my tasks which will have the benefit of giving me proper stack traces and compile time errors and all that good stuff.
-
Powershell does not make using the Win32 APIs easier.
It’s literally easier to hit those from most programming languages than from PS.
Add-Type @"
using System;
using System.Runtime.InteropServices;
public static class Win32 {
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBoxW(
IntPtr hWnd,
string lpText,
string lpCaption,
uint uType
);
}
"@
[Win32]::MessageBoxW([IntPtr]::Zero, "Hello from PowerShell", "PS", 0)
This also exists:
Add-Type -AssemblyName PresentationFramework
[System.Windows.MessageBox]::Show("Hello from PowerShell")
But that is a way of using .NET, you should just write a C# program instead of doing that.
- Security by making everyones live worse.
powershell.exe -ExecutionPolicy Bypass -File .\script.ps1
I don’t care how exactly this came to be, and I do not care about Microsofts cat-and-mouse game with hackers: This flag was not the correct place to put a security boundary, and instead of doing whatever the right thing was in the security architecture of Windows, they did this and made Powershell worse to use.
And the -File flags also grind my gears, no programs other than Powershell built-ins ever saw a need to do it in such a weird way, great example of point 4 (too verbose).
Recommendation
Literally have an LLM build y