I Like Powershell
buttondown.email
buttondown.email
1. The PowerShell separation of, what on *ix* systems is stdout and stderr, doesn't really work. Want to know whether your invocation of a PowerShell command worked? Well, it might be that the error stream has content, otherwise check the warning stream, otherwise check the regular output stream, and see if it contains an error-message-like-ish string
2. Continuing on this theme, just 'give me all the output, regardless of type/class, from this command' is just plain impossible. You want to see what this command would print on a terminal? Good luck with that!
3. Serializing PowerShell output to JSON (which, naively, you would assume would be sort-of reliable) generates heaps of PS*-specific junk. Just the common '|fl XXX' expression will trigger this
4. Even commands that appear to be successful, may in fact have failed. The Azure commandlets are especially guilty of this. Remove a load balancer NAT rule? Sure, we'll pretend to do that! Except, nothing happens, and you'll need a support ticket to actually modify your configuration
But ...
1. *> is a thing
2. see above, I agree that Start-Transcript could be better and include all
3. Just provide your own massaged JSON
4. Not a pwsh problem, problem in general. For example take a look at Invoke-Builds `exec` as one way to handle this
But really, 4 random things, and you don't like 2 decades of work. Awesome!Silly how you need sh to do a very basic thing in PowerShell
or use -Depth parameter...
``` > Get-Process | Select -Last 5 Name,ProcessName,Company,Path | ConvertTo-Json [ { "Name": "winlogon", "ProcessName": "winlogon", "Company": null, "Path": null }, { "Name": "WmiPrvSE", "ProcessName": "WmiPrvSE", "Company": null, "Path": null }, { "Name": "WMIRegistrationService", "ProcessName": "WMIRegistrationService", "Company": null, "Path": null }, { "Name": "Zoom", "ProcessName": "Zoom", "Company": "Zoom Video Communications, Inc.", "Path": "C:\\Users\\user\\AppData\\Roaming\\Zoom\\bin\\Zoom.exe" }, { "Name": "Zoom", "ProcessName": "Zoom", "Company": "Zoom Video Communications, Inc.", "Path": "C:\\Users\\user\\AppData\\Roaming\\Zoom\\bin\\Zoom.exe" } ] ```
And when you say "Just the common '|fl XXX' expression will trigger this" does that mean you are doing this `<command> | fl X | ConvertTo-Json`? Because if so, that's why your getting all the PS specific junk.
```
foo
bar
```
it'll be happier.2. Try piping your output through `| Format-List -Property *`. This isn't very discoverable really.
3. Try selecting the properties you want: `| select Name, ID, Etc`
4. This is the fault of the module developer, not Powershell. You can also write bad software in C.
2. Pipe to Out-String. Now you know.
3. Format commands generate console-host-specific markup. You would never pipe through FL to json, that's a bizarre thing to do. You're complaining that the boot doesn't fit on your head. If you want to filter properties, use select or generate new objects in foreach.
4. Fair, but not a Powershell issue
Sure, all languages have these, but the ones in PS feel nastier and more subtle than most, compounded by the fact that it's not a language I use more than once every few months and should be easy to pick up and put down.
Basic stuff like parens, commas, function calls, casting, variable interpolation and arrays are frequently surprising. Many behaviors fail silently.
For example, arrays with 1 element behave differently than arrays with 2+ elements. PS is "smart" and treats the 1-element array as a scalar. Why? I've wasted hours dealing with arrays in PowerShell.
See this post for a sampling of the problems: https://stackoverflow.com/a/69644807/6243352
Even without the gotchas, case insensitivity, optional abbreviations, optional parens, etc, make PS scripts harder to read and debug than they need to be. PS feels like a mashup of many of the most confusing parts of PHP and Perl and adds its own fresh mess on top. Adding parameters and resolving a few of Bash's failings isn't much of an achievement given ~20 years of time to design it properly. Neither language is as easy to work with as it should be.
PowerShell has real functions, not just exit codes and text streams so you can easily write maintainable scripts past 100 lines. It’s got a debugger. It’s got modules and a package gallery. It’s got autocomplete and help messages. It’s got try/catch/finally instead of traps. It’s got an optional type system so you can be as loose or strongly typed as you want. It’s cross platform so the Windows devs don’t get confused migrating to Linux. It’s got batteries included for everything between cmdlets and .net. Anything you can do in C# can be replicated. Sed/awk/Grep are nice but sometimes you just want structured data converted into an object to pass around functions instead of reinventing the wheel.
Case sensitivity is a feature, $foo and $Foo should be the same and if they’re not you should call it something different or invoke it differently. “$foo = new [foo]” separates variables from types. “$env:foo” namespaces your env vars. In Bash is FOO a var, constant or env var?
Good PowerShell is readable with little effort. Good Bash is readable with significant effort if you are familiar with Bash and the problem domain already.
I'd like to see a native OS scripting language that has a low bar of entry, isn't silent on undefined variables and other common mistakes, imposes syntactical consistency like Go or Python, has decent basic data structures and isn't riddled with pitfalls. PS isn't that language.
If Bash and PS were good, it'd be so much easier to bring non-programmers into the command line so they can automate tasks and hack on their systems. Unfortunately, these languages aren't doing that, much less passing the usability test with most programmers who'd just assume script with Py, Perl, JS, or whatever their preferred language is.
In terms of ease of use PowerShell and ISE is available on every PC, is more consistent than Bash and more powerful than a user friendly shell like Fish. I don’t know how you get easier than Get-Foo, Set-Foo.
Bash doesn’t really offer anything out of the box except the ability to glue external commands together and most people use it because of its availability and portability rather than its virtues as a language. Zsh, Fish, Elvish, Xonsh haven’t managed to displace it and Xonsh is even written in Python.
The only thing I can think of that could make automation more friendly to nontechnical users is something like autohotkey to mimic manual interaction.
And PS doesn't include things for free, it brings a lot of baggage from the same company that made the win32 APIs unergonomic, though it does have a few structural advantages like typed data
(the easier part to Get-/Set- could be losing the pinky-typed dashes since you already separate by Case, and for such common things you could even just use gFoo sFoo)
But none of these options are anywhere close to the ergonomics needed to bring non-technical users into the fold
It's not saying much for the language that Windows sysadmins use PS primarily. Like Bash, the reason people use it is availability, not language virtue. See last year's Stack Overflow developer survey, where Bash was more popular than PS (29% (Bash) to 12% (PS)[1]) and loved (57% (Bash) to 43% (PS)[2]).
I don't like Bash. I'm using it as a yardstick to show how disappointing PS is.
[1]: https://survey.stackoverflow.co/2022/#most-popular-technolog...
[2]: https://survey.stackoverflow.co/2022/#technology-most-loved-...
Array unrolling is a legitimate gripe. The design justification is that Powershell is pipeline-oriented. On occasions where you specifically need an array, either type your variable or use the array operator:
[object[]]$foo = 42
$foo = @(42)I think I'm missing which problem your code solves. There are a few array issues in my gotcha journal. Adding types like [object[][]] doesn't seem to help with getting PS to understand nested arrays with 1 element, for example, and $foo = @(42) is the array declaration syntax I usually use.
[1]: https://gist.github.com/ggorlen/1e337f211f508124321c8bc7c1d2...
An good example is the Citrix management console. It is a very thin Windows GUI wrapper around a bunch of PowerShell modules. Literally everything it does, and everything it shows comes from PowerShell, not from direct API calls. When managing a Citrix farm remotely, it uses WinRM PowerShell remoting, not traditional COM+ RPC.
This is easy because:
1. The PowerShell runtime can be trivially embedded into any .NET app. It's just a reference and about 3 lines of biolerplate.
2. It runs "in-process", making it much faster than calling out to external shells.
3. The commands are (relatively) strongly typed, so there's no concerns about escaping, shell injection, or other similar security issues.
4. Outputs come back as lists of strongly typed C# objects, making them trivial to bind to grid views or other GUI user controls.
5. Even tree views are easy to wire up, because PowerShell has a concept of virtual "drive" providers that can wrap anything in a file/folder structure. You just write a generic "folder and item navigator" GUI control once and then you can use it with any number of providers for free.
The end-result looks like a traditional GUI, but basically guarantees that anything you can do in the GUI, you can also do in the shell. It's also ridiculously easy to add a "generate a script for this change" button, because it's just spitting out the internal representation!
$ui = (Get-Host).UI.RawUI
$ui | Get-Member (to see the methods and attributes available)
$ui.WindowTitle = "Hello World Window!"
After that, I was hooked. PowerShell providers and modules are incredibly useful, as is piping output to Out-GridView. Later versions have introduced more cmdlets that, quite honestly, everyone should use instead of DOS commands (e.g., Get-NetIPConfiguration instead of ipconfig). I do remember a bit of timing issues (often solved by inserting Start-Sleep) and other general flakiness like others have noted here, but the ones I've noticed were fixed in later versions.
Using PS is a joy, I've re-written all of my usual utility stuff from bash/zsh to PS inside a few week, and managed to improve on a bunch that I didn't want to do before because bash is painful to debug/test/etc.
I rarely fire up WSL now, and it has replaced Python for my general utility scripting language.
Note: if anyone is reading this - if you're still using PS5 built into W11, then you owe it to yourself to install PS7 (it can be installed alongside 5). It is invoked via pwsh rather than powershell, and can be setup to use the same startup scripts as the default PS.
For something as complicated as Windows Server, there is not enough time to build GUI screens and OLE/COM/DCOM interfaces for every little flag, function or feature. Microsoft must have realised this quite some time ago.
The evidence? That even Windows 11 contains ancient, crufty GUI screens from Windows XP and older. It turned out the Unix guys were right all along. There is nothing wrong with the core of Windows as an operating system, but the baggage it carries mostly due to all those failed GUI screens makes it inferior in practice to Unix based systems.
I have one powershell script I use, which is something that manipulates an Outlook mailbox. It's unreliable (thanks to Outlook) but again demonstrates what a pointless idea the entire Powershell project was and to a certain extent what a dead end things like systemd will eventually end up being.
If you can specify some sort of schema for configuration in general, then the screens can generally be generated.
You generally don't want or need to display different instances of the same sort of configuration property in fundamentally different ways.
I think that what you get from a (decent) GUI is discoverability of features, whereas what you get with the CL is specificity.
The former makes computers accessible to the masses, the latter provides power to administrators.
Big asterisk, my day job is as a .NET/C# developer. So much of Powershell does feel like a .NET wrapper or C#-lite, and that's not necessarily a bad thing. It lends itself very well to feeling like a traditional programming language. Hell, it even has a debugger! My only real complaint about it and adoption thus far is the release management. Windows 11 _still_ ships with 5.1, and 7 is leagues ahead in terms of performance and features.
> ls --full-time | cut -d' ' -f6,7 # WRONG
> If two “fields” have different lengths, ls will add spaces to the name of the smaller one to make the two line up, which will break cut -d' '. And in fact you can’t solve this at all with ls, you have to write stat -c %w. Text streams don’t compose.
I mean, ok, I get the point how he's saying Powershell has 'objects', but the example is super-contrived. All it takes to fix the offending 'padding spaces' is to remove them.
ls --full-time | tr -s ' ' | cut -d' ' -f6-7
Moreover, that's not even "bash" you're comparing against, but 'coreutils'. If you really wanted to grab the output of 'ls' with pure bash then you'd probably go with something like this instead: ls --full-time | while read -r FIELD{1..8}; do echo "$FIELD6 $FIELD7"; done
which isn't exactly complicated either.Otherwise, if the gripe is about the command you're using not being field based, then go ahead and use one that is, on data that supports it. This isn't exactly a language issue.
Case in point, if 'stat' is the right command to get that "field" for that "object type", then there you go. Nagging that if you don't use the right tool for the job will leave you with having to work around things, is not exactly the environment's fault.
Also, text streams absolutely do compose. It's just that the underlying type will always be a text stream. But composability is 100% the reason behind this in the first place.
>learn to use your machine.
Now, you can keep whining for next decade, or fix your problem and stop this millenial shaneningas.
I think consensus would more likely support "learn to keep your machine from using you".
A new PowerShell session takes anywhere from *five to thirty seconds* just to give me a prompt I can type at.
Blame it on the other software if you want, but PowerShell isn't just a little slow. It's hundreds of times slower than any interactive shell should be.
The part of my PowerShell profile that takes the most time to execute is removing all of the fake, useless aliases for Unix commands that PowerShell bundles and refuses to remove.
I am a wizard. My profile is my power. With great care and sacrifice I've got it down to about 2s and I just have to load less-commonly-used stuff ad-hoc.
I have a 3900X with 64gb of ram and a recent ssd.
Powershell startup time is the number one problem with the tool, GP is correct.
For example, many people keep each function in a separate file, instead of merging them into psm1 during build. That will speed it up A LOT.
You can have different profiles and load them when you need them, even when you enter specific folder.
There are ways around it. You complain that you want everything everything everything loaded in advance for your wizardry but are u really a wizard if you can't solve this? So if you buy a porche and then put a house on top of it, shop in cart in the back of it, tires for every season, and so on, and then complain its slow, then guess what...
> Pwsh starts on my machine in 400-500ms. Far slower than I'd like. That is with no profile.
This is already 10x slower than a reasonable shell startup time, with no profile configuration at all, on an extremely fast desktop system. It's downright embarrassing that you are even attempting to defend this state of affairs.
The feature is called 'executable aliases', in case you want something to Google to find out how to disable it.
But regardless of platform I use bash or powershell usually for very small self-contained scripts and python for anything more extensive.
I always say powershell is more akin to python or perl than bash except python never got around to making repl into a shell interpreter or nice things like script signing enforcement.
Except Tab is a lateral pinky key press, one of the worst key presses out there
Though my hands don't complain so long as I don't use a mouse, so YMMV.
I have used bash in depth over the past year, I maintain the local dev cluster tooling at work (because nobody else wants to, see: bash). It's about 2kloc of pretty advanced bash.
While PowerShell is a terrible language, piping around text (or rather, let's face it, JSON) is objectively worse. I do feel more productive with the Bash language/syntax, but I have no faith in any code that I write. Bash is littered with footguns and odd behavior.
I have been learning nushell recently and have been greatly enjoying it. You get to pipe around structures, while avoiding the obnoxious PowerShell syntax. As an example from today, I was double-checking that some envars made it into a container image:
skopeo inspect ... --format json | from json | each { |x| $x.Env }
Now that's certainly possible with bash and jq, but I'd probably be leaning on Google even after 1000s of hours of maintaining a bash behemoth.I would call it un-called-for criticism.
But I don't want to be too critical . . .
Don't get me wrong. Yey for the *nix stuff, I am huge fan. We wouldn't be here if that was absent. I am not working for MS or anybody that have stakes here. Its simply no comparrison.
scripts are some 100x longer and normally break due to everything or anything changing...
You can code-golf in Powershell. There are terse aliases. But generally the community doesn't do that. Looking at some of the bash garbage I've been subjected to, I'm glad.
"normally break" yeah bad devs use bash too, trust me.