Almost always when I see PowerShell critiqued by people used to Linux and Bash, the criticisms leveled against if often add up to: "I am used to the workarounds for the limitations of my system. Sure, your system does not have these limitations, but what if I need the workarounds, like with my current system?"
This is like... AutoCAD before the year 2000. It was digital paper, and acted exactly like a drafting board with pens, rulers, and protractors. It was better than paper, but not by much! SolidWorks came out and blew it away. It was proper 3D, with constructive solid modelling. It could generate drawings of arbitrary projections or cross sections in under a second, saving months of time. Yet... people complained the same way. What if I need drafting tools? What if I want to draw lines manually? How do I draw "just" a circle? Why do I need to define what I'm doing in 3D? Just give me digital paper! That's what I want!
Seriously. In UNIX, if you want to sort the output of "ps"... sss... that's hard. Sure, it has some built-in sorting capabilities, but they're not a "sort" command, this is a random addon it has accumulated over time. It can order its output by some fields, but not others. It can't do complex sorts, such as "sort by A ascending, then by B descending". To do that, you'd have to resort to parsing its text output and feeding that into an external tool. Ugh.
Heaven help you if you want to sort the output of several different tools by matching parameters. Some may not have built-in sort capability. Some may. They might have different notions of collations or internationalisation.
In PowerShell, no command has built in sort, except for "Sort-Object". There are practically none that do built in grouping, except for "Group-Object". Formatting is external too, with "Format-Table", "Format-List", etc...
So in PowerShell, sorting processes by name is simply:
ps | sort ProcessName
And never some one-character parameter like it is in UNIX, where every command has different characters for the same concept, depending on who wrote it, when, what order they added features, what conflicting letters they came across, etc...
UNIX commands are more an accident of history than a cohesive, coherent, composable design. PowerShell was designed. It was designed by one person, in one go, and it is beautiful.
The acid test I give UNIX people to see if they really understand how weak the classic bash tools they use is this:
Write me a script that takes a CSV file as an input, finds processes being executed by users given their account names and process names from the input file, and then terminates those processes. Export a report of what processes were terminated, with ISO format dates of when the processes were started and how much memory they used into a CSV sorted by memory usage.
Oh, there's a user called "bash", and some of the CSV input fields may contain multiple lines and the comma character. (correctly stored in a quoted string, of course!)
This kind of thing is trivial in PowerShell. See if you can implement this, correctly in bash, such that you never kill a process that isn't in the input list.
Give it a go.
...
After I posted the above, "JoshuaDavid" provided a correct Bash solution, which blew my mind because I just assumed it was borderline impossible: https://news.ycombinator.com/item?id=23267901
Note how complex his solution is, and that he had to resort to using "jq" to convert the output of "ps" to JSON for the processing!
Clear, readable, and easy to modify even for a junior tech.
What I didn't say in that thread was this: I didn't actually bother to work out the solution to my toy problem in PowerShell before JoshuaDavid posted his solution.
I made up the problem simply assuming that it's ludicriously difficult in bash -- without checking -- and I similarly assumed that it's trivial in PowerShell -- without bothering to check.
I was that confident.
Are you still that confident that Bash is superior to PowerShell? Or have you internalised its constraints, and are too used to drawing fiddly little lines on digital paper to realise that your tooling is hopelessly outmatched by solid modelling?
> Find it hard to set a script to abort with a stack trace.
$script:ErrorActionPreference = 'Stop'
# or
throw "Oops!"
> Find it hard to deal with relative imports
That's a very unfortunate limitation that I've never understood myself, to be honest. The typical "best practice" is to not use relative imports, but to use "installed" modules or scripts instead.
> Disklike explains how your array is now a single object when you returned it from a function
This is also "one of those irritations" that tends to bite people when dealing with search results, e.g.: "Get-ADUser". If you always want an array (even an empty or single-valued array) then wrap functions in @(...), e.g.:
$users = @( Get-ADUser -Filter ... )
This is also the syntax to create an empty array, or an array of one item:
$empty = @()
$listOfOne = @( 'foo' )
> miss native yaml support
But this would be trivial to add. Writing a module to provide commandlets such as "ConvertFrom-Yaml" and "ConvertTo-Yaml" is about a day of effort in PowerShell. Good luck doing the same thing in Bash and producing something useful, let alone full-featured!
Set-PSBreakpoint -Command Write-Error -Action { break; }
cmd.exe /c "exit 1"
echo "if this->($LASTEXITCODE) is 1 I shouldn't be here"
Your stack trace code is wrong. What your code is doing is essentially saying throw an exception when you encounter an error. All I am asking is when exception hits the top, dump the stack trace.
$script:ErrorActionPreference = 'Stop'
function bar() {
throw "oops"
}
function foo() {
$a = 123
bar
}
foo
PS C:\tmp> .\a.ps1
Exception: C:\tmp\a.ps1:6:5
Line |
6 | throw "oops"
| ~~~~~~~~~~~~
| oops
I use `trap{$_.ScriptStackTrace; break}` but unfortunately I cannot hide this code into a helper script that I can dot source... because of scoping rules! Even though I am dot sourcing a file which I would think would load it into my current scope according to dot sourcing link you sent.
Why this is not the default behavior when leaking an exception and aborting I have no clue
enforcing things are arrays
yes you can wrap stuff in arrays, but that is making the callsite look ugly for a function definition problem. The solution "return ,$array" is just weird
Honestly I prefer the bash way of $yaml | yaml2json(.exe) | convert-fromjson. Easier to find cross platform converters which your example is not. Takes me like 5 seconds to write, however then I have to teach others to do it as well, I want it in the platform. Also why they are at it, add toml support as well.
for documentation
# .SYNOPSIS
# Why do I need to type .SYNOPSIS above here, and yes that extra line is too many
function foo(
# but here its just obviously a comment for a parameter
[string] $param=""
) {
$param
}
Also didn't mention this before I wish there was a version of powershell that was static checked like typescript for javascript.
> Honestly I prefer the bash way of $yaml | yaml2json(.exe) | convert-fromjson
I always prefer native support, but that's just me. I recently even wrote a converter for DNS bind zone files because they're such a pain to deal with as "text" files.
> Why do I need to type .SYNOPSIS above here, and yes that extra line is too many
Because there are other sections as well.
Consider yourself lucky! If you're writing binary modules in C#, the automatic help generation is missing. Instead, you have to use a hideous legacy XML-based help system nobody asked for. There are thankfully generators available now that plug into the Visual Studio build system, but in the past you literally had to author these by hand.
> I wish there was a version of powershell that was static checked like typescript for javascript.
Don't we all?
Set-StrictMode adds some static checks (not enough IMHO), and there are also linters available. If using VS Code, you get a bunch by default.
Fundamentally, once I start getting too frustrated by the weak typing, I realise that I'm writing software, not scripts. I simply crack open Visual Studio and start writing C#...
> Why this is not the default behavior
PowerShell conceptually is nearly perfect at a high level. It was originally called the "monad shell", and that design pedigree still shines through.
Unfortunately the implementation has many gaps that are as yet unresolved.
I was hoping PowerShell Core would fix everything, but it only fixed a few things (parallel foreach finally!) while leaving simple things like break-on-exception on the table.
Nonetheless, having worked with both Bash and PowerShell, I hugely prefer the latter because of that purity of vision.
This is like... AutoCAD before the year 2000. It was digital paper, and acted exactly like a drafting board with pens, rulers, and protractors. It was better than paper, but not by much! SolidWorks came out and blew it away. It was proper 3D, with constructive solid modelling. It could generate drawings of arbitrary projections or cross sections in under a second, saving months of time. Yet... people complained the same way. What if I need drafting tools? What if I want to draw lines manually? How do I draw "just" a circle? Why do I need to define what I'm doing in 3D? Just give me digital paper! That's what I want!
I made a comment on YC News nearly a year ago that I'm going to partially repeat below: https://news.ycombinator.com/item?id=23257776
PowerShell is more UNIX than UNIX.
Seriously. In UNIX, if you want to sort the output of "ps"... sss... that's hard. Sure, it has some built-in sorting capabilities, but they're not a "sort" command, this is a random addon it has accumulated over time. It can order its output by some fields, but not others. It can't do complex sorts, such as "sort by A ascending, then by B descending". To do that, you'd have to resort to parsing its text output and feeding that into an external tool. Ugh.
Heaven help you if you want to sort the output of several different tools by matching parameters. Some may not have built-in sort capability. Some may. They might have different notions of collations or internationalisation.
In PowerShell, no command has built in sort, except for "Sort-Object". There are practically none that do built in grouping, except for "Group-Object". Formatting is external too, with "Format-Table", "Format-List", etc...
So in PowerShell, sorting processes by name is simply:
And never some one-character parameter like it is in UNIX, where every command has different characters for the same concept, depending on who wrote it, when, what order they added features, what conflicting letters they came across, etc...UNIX commands are more an accident of history than a cohesive, coherent, composable design. PowerShell was designed. It was designed by one person, in one go, and it is beautiful.
The acid test I give UNIX people to see if they really understand how weak the classic bash tools they use is this:
Write me a script that takes a CSV file as an input, finds processes being executed by users given their account names and process names from the input file, and then terminates those processes. Export a report of what processes were terminated, with ISO format dates of when the processes were started and how much memory they used into a CSV sorted by memory usage.
Oh, there's a user called "bash", and some of the CSV input fields may contain multiple lines and the comma character. (correctly stored in a quoted string, of course!)
This kind of thing is trivial in PowerShell. See if you can implement this, correctly in bash, such that you never kill a process that isn't in the input list.
Give it a go.
...
After I posted the above, "JoshuaDavid" provided a correct Bash solution, which blew my mind because I just assumed it was borderline impossible: https://news.ycombinator.com/item?id=23267901
Note how complex his solution is, and that he had to resort to using "jq" to convert the output of "ps" to JSON for the processing!
Compare to the solution in PowerShell, of which nearly half is just sample data: https://news.ycombinator.com/item?id=23270291
Clear, readable, and easy to modify even for a junior tech.
What I didn't say in that thread was this: I didn't actually bother to work out the solution to my toy problem in PowerShell before JoshuaDavid posted his solution.
I made up the problem simply assuming that it's ludicriously difficult in bash -- without checking -- and I similarly assumed that it's trivial in PowerShell -- without bothering to check.
I was that confident.
Are you still that confident that Bash is superior to PowerShell? Or have you internalised its constraints, and are too used to drawing fiddly little lines on digital paper to realise that your tooling is hopelessly outmatched by solid modelling?