top | item 10112911

In defense of PowerShell

56 points| Raesan | 10 years ago |benwilson.me

78 comments

order

JoshTriplett|10 years ago

> I’m willing to admit that PowerShell isn’t obviously better as a shell than something like bash, but it’s unquestionably a better language to use for scripting.

There's a missing "on Windows" here. Sure, PowerShell is clearly a tool designed for the Windows environment. And if you're a Windows system administrator, it has more tools and glue for that environment. You could use PowerShell to replace things that you'd otherwise have to write in Python or similar, not shell.

But that doesn't make it "unquestionably a better language to use for scripting" overall; it makes it a better fit for its target platform, which is certainly true.

And an earlier part of the document made exactly that point: PowerShell on Linux would be as uncomfortable as Cygwin is on Windows. There's an impedance mismatch there.

InclinedPlane|10 years ago

I've lived in both the windows and linux/unix worlds and I will say that powershell is a better scripting language than bash. Bash is ok, but powershell is nicer. Powershell is sort of like python in that it tends to force down a path of doing things in a certain way.

Powershell isn't just "more tools and glue for windows stuff", it's a different way of doing things. In powershell you get named command-line parameters for free, that's a huge win. You get usage messages and simplified man-page help baked into the way things work, that's also huge. In powershell you don't just work with text, you work with objects, which pass along the pipeline. That means that instead of using sed and awk to muck up the output of some other script you can just use simple select, where, and format commands. This is incredibly powerful and an area where linux has fallen behind.

I like linux a lot, but this attitude of sneering down at windows and powershell merely because it's not linux is amateurish and parochial. People should be thinking about adapting the innovations that powershell has made and building on them instead of looking at it as some bizarre alien beast that will never be relevant to them.

wvenable|10 years ago

If you take away the platform and command differences, then Bash is a worse scripting language than Powershell. Bash is a rough programming language to work in.

This whole comment about "on Windows" is completely beside the point. And the impedance mismatch, as you said, was already commented about in the article.

scott_karana|10 years ago

Bash has notorious gotchas, and similarly, doesn't work well natively on Windows without a whole slew of associated applets.

Sounds like both shells have one of those problems... ;)

nailer|10 years ago

> There's a missing "on Windows" here.

A Powershell object piping system would be great on Unix too. Scraping text is fragile and slow.

Obviously for a Unix port you wouldn't write cmdlets in .net like Powershell but something popular in the Linux/Unix admin world, most likely Python.

julianz|10 years ago

I work primarily in a Microsoft environment, although I have Linux shell experience as well, and I totally don't get Powershell. What is a cmdlet? Why does it need a stupid made-up name like that? Why are all the commands incredibly verbose and hard to remember? I avoid using it at every opportunity.

Canada|10 years ago

A cmdlet is a PowerShell native command. It reads and writes objects, where as Unix commands read and write plain text. Try this in PowerShell:

get-command

get-command | where CommandType -eq "alias"

Notice the lack of parsing. In Unix you'd typically do this kind of thing with grep, but then you'd have to watch out that you don't accidently include the wrong rows because some other column happened to contain the string "alias"

Try this:

Get-Command | Out-GridView

There's this thing called PowerGUI. It has a text editor for writing PS and a computer management GUI tool. It's written in PS itself. At first I wasn't too impressed, but then I noticed in the computer management thing there's an option to "view code". And then I saw how simple it is, how these nice interfaces were implemented with a trivial amount of PowerShell. Now I think PowerShell is great.

nailer|10 years ago

As a Unix person, 'Restart-Service' seems a lot easier to remember than 'systemctl'.

Edit: Restart-Service is also easier to remember than /etc/init.d was.

Edit 2 (rate limit): `service` on RHEL is great, but it's a Red Hat-ism. Which is fine, I used to work at Red Hat, but still.

It's also pretty limited: you use service to start/stop/restart, but you still use systemctl to list services, or list /etc/init.d (technically /etc/rc.d/init.d on RHEL) on older boxes.

On Windows, to get services, it's `get-service`

Fun exercise for readers, given that you now know `restart-service` and `get-service`:

- Guess what the powershell command to get processes is.

- Guess what the powershell command to stop a process is.

- Guess what the Powershell command to install a package is.

There's some weird ones - dmidecode on Linux becomes get-wmiobject on Powershell (see the rosetta stone link posted earlier) - but for the most part it makes more sense than Linux and Unix.

scott_karana|10 years ago

Powershell cmdlets are different(ly named) than executables/commands because they don't preferentially emit text: they emit .NET object streams. I suspect this is for compatibility/interrop reasons.

(They are implemented as .NET classes loaded from within libraries, as I recall. Eg, `import-module activedirectory` will load the entire library of AD cmdlets.)

Here's what you can do with object streams:

Get-ADUser | select FirstName,LastName,EmailAddress,Department | where {$_.FirstName -contains "Jeffery"} | format-table

In a traditional Unix pipeline, you'd have to make sure that none of the other fields contained "Jeffery", or you could get false positive results. For example, you might have to use multiple named pipes or temporary files for each of the table columns, and reinterpolate them into a table/CSV/whatever after doing the grep. You could always use Python/Perl/Ruby/Tcl instead of course, but those aren't really shells.

You can also do math, method calls, etc. The example above was just a trivial one.

wvenable|10 years ago

I find Powershell extremely weird. We have a fair number of Powershell scripts for admin tasks and frankly I think they'd all be easier to understand if they were just written in C#.

bashinator|10 years ago

The tab completion in powershell is frustrating to me. I never want to cycle through every available option (especially when many PSH commands have literally hundreds of switches). I want the tab-completion to only show options for which I've started typing the prefix. I want double-tab to print a listing of said options so that I can see them all at once. Is this possible? Right now it feels like there's a major lack of discoverability in PSH.

useerup|10 years ago

> I want double-tab to print a listing of said options so that I can see them all at once. Is this possible?

In PowerShell 5 (at least in Windows 10), Ctrl-Space yields a list of matching completions. You can then use the arrow keys (ip, down, left, right) to pick one and hit enter or space to select.

It works for commands as well as for options/parameters and parameter values.

I.e. you can type get-pr[ctrl-space] and powershell responds with:

    Get-PrintConfiguration      Get-PrinterDriver           Get-PrinterProperty         Get-Process
    Get-Printer                 Get-PrinterPort             Get-PrintJob                Get-ProvisionedAppxPackage
Choose Get-Process (right,right,right,space). Now the cmdline shows

    Get-Process _
Hit [-][ctrl-space]. Powershell now shows:

    PS C:\Users\zaphod> Get-Process -Name
    Name                 IncludeUserName      FileVersionInfo      ErrorAction          ErrorVariable        OutVariable
    Id                   ComputerName         Verbose              WarningAction        WarningVariable      OutBuffer
    InputObject          Module               Debug                InformationAction    InformationVariable  PipelineVariable
Pick "Name" and hit space:

    PS C:\Users\zaphod> Get-Process -Name _
Now hit [ctrl-space] again. PowerShell now completes on running processes on the system, offering the list of all of the process names.

Raesan|10 years ago

Yeah, that really bothered me coming from bash. I agree it's not as good from a discoverability perspective. Having said that, it's not the kind of thing that has continued to bother me over time. I've gotten used to it.

drmohundro|10 years ago

Agreed regarding the default tab completion. You might check out PSReadLine at some point - see https://github.com/lzybkr/PSReadLine. Its goal is to try to emulate readline except in PowerShell (this includes tab completion as well as emacs shortcut keys... vim shortcut keys are in the works AFAIK). It does require some additional configuration and it isn't installed by default, but I think it helps with this specific scenario quite a bit.

sithadmin|10 years ago

The usual PowerShell guru's response to your complaint is 'This is what PowerShell ISE is for'.

Personally I don't think this is elegant, but that's what I usually encounter in the wild.

hibbelig|10 years ago

Hm? After typing "xyz -fo" I will get completions beginning "-fo", such as "-foo" and "-foobar", but I won't get completions that don't begin with "-fo".

But yeah, I don't like the cycling, either. I'd also prefer to get a list of the possible completions.

rikkus|10 years ago

Powershell is a nice language.

Here's map/filter/reduce. Golf welcome.

  @(1, 2, 3) `
     | % { $_ + 1 } `
     | ? { $_ -gt 2 } `
     | Measure-Object -Sum
     | Select Sum
You can write a generic reduce like this:

  $reduce = {
    param   ([scriptblock]$reducer)
    begin   { $initialised = $false }
    process { 
      if (-not $initialised) {
        $agg = $_
        $initialised = $true
      } else {
        $agg = &$reducer $agg $_
      }
    }
    end     { $agg }
  }
And then use it like this:

  @(1, 2, 3) | &$reduce { param($agg, $i) $agg + $i }

yellowapple|10 years ago

As someone who used to use PowerShell rather extensively (back when my dayjob regrettably involved thousands of Windows machines that needed managing and support), I feel like trying to compare PowerShell to, say, bash is folly. To me, PowerShell has more in common with a proper scripting language - somewhere between Perl and Ruby, but with a nice-ish REPL - than a traditional shell like bash. Both the Unix-style text-centric paradigm and the PowerShell-style object-centric paradigm have their place.

That all said, the most recent PowerShell I've significantly touched was version 2; I've since moved on to greener pastures.

parfe|10 years ago

I dislike windows (and by extension, powershell) because a solution such as changing the port the webserver runs on looks something like:

    New-ItemProperty IIS:\sites\DemoSite -name bindings -value @{protocol="http";bindingInformation=":8081:"}
http://www.iis.net/learn/manage/powershell/powershell-snap-i...

What did I just modify? Is it persisted to the hard disk? How do i back that up? How do I revert the change? How do I move this change (and 20 others) from one server to another? It's three months later, and I want to do something similar, where can I find the current state of DemoSite and mimic it for DevSite?

I like plain text. Clearly companies succeed on microsoft products and people make money administering them. Doesn't mean I have to like it.

coldtea|10 years ago

>I dislike windows (and by extension, powershell) because a solution such as changing the port the webserver runs on looks something like:

Doesn't look that much different or arcane to how you'd do it in Linux.

Except more structured (which is good).

>What did I just modify? Is it persisted to the hard disk? How do i back that up? How do I revert the change? How do I move this change (and 20 others) from one server to another?

Oh, the humanity of learning a different way of doing things.

InclinedPlane|10 years ago

So you're saying that if you expend zero effort to find the answers to these questions then those questions will remain unanswered?

If you want to become a systems administrator of Windows servers then I'd suggest reading at least one book on the subject, you're not going to get there by copying and pasting one command you found on the internet.

Just as it is with linux/unix. Just as it is with anything.

Pretending otherwise is disingenuous and intellectually dishonest.

Raesan|10 years ago

PowerShell has "providers" that let you interact with things as if they were a file system, which is what is going on in your example. I agree that it's not a great way to expose IIS settings.

The other place you see providers in use is when you use PS to edit the registry, but it's HKLM:\ (or whatever other hive) instead of IIS:\, and it makes a lot more sense there since people naturally think of the registry in a filesystem sort of way.

More info if you're curious about providers:

https://technet.microsoft.com/en-us/%5Clibrary/Ee126186(v=VS...

bjourne|10 years ago

So how would you accomplish the same task on Linux using bash? What script would you write to set the web server's port to 1234?

switch007|10 years ago

Why the colons surrounding the port !?

slavik81|10 years ago

I started off as a PowerShell fan, but my introductory experience has been pretty poor. A little while back, I tried testing the output of a sorting algorithm with PowerShell. I wrote a line of bash to check my results:

  diff <(cat output.txt) <(cat output.txt | sort -n)
Then I wrote the PowerShell:

  get-content output.txt | foreach-object { [Int] $_ } | sort-object | out-file -encoding ascii sorted.txt
  compare-object (get-content output.txt) (get-content sorted.txt)
Yeah, it's a lot longer. It was the bug that really soured me, though. The files compare as identical even if output.txt is not sorted.

You go read Microsoft tutorials [1] and they tell you to use Get-Content (cat) and Compare-Object (diff) like this for comparing files, but what they don't tell you is that order is ignored. Given how often I see the above code cited online for comparing files [2][3], I'm not sure that many people actually understand this.

I still haven't actually figured out how you properly compare files with PowerShell. I call fc.exe now, but its output is pretty gnarly so all I use is the return value.

[1] https://technet.microsoft.com/en-us/library/Ee156812.aspx [2] http://blogs.technet.com/b/heyscriptingguy/archive/2015/04/0... [3] http://serverfault.com/questions/5598/how-do-i-diff-two-text...

bjourne|10 years ago

AFAICT, you are just trying to check if a file is sorted? Then wouldn't:

    diff (cat out.txt | sort | out-string) (cat out.txt -raw)
do it?

romualdr|10 years ago

I agree with most of the comment: it's weird.

I also agree with the author, you don't try enough or don't bother trying.

i LOVE nix environnements, but i HAVE to work on Windows. And yeah, at first, it's a pain. Nothing works as expected and you get bunch of errors ... but you have to remember that you're not on a nix terminal !

You don't expect to master a environnement on a first try, do you ? Remember this is not the term you know and love. And if you take some time to get used to, here is your reward:

you will be able to rocks the term on Windows too, and that's pretty badass.

_mgr|10 years ago

"I think many of the misconceptions I see on HN about PowerShell (and much of the Windows hate in general, actually) are because the typical use case on HN is quite a bit different than that of an internal IT department of a non-tech company, which is more Microsoft’s focus."

This, and vice versa that you see in other online communities. Debating your religious position is almost becoming safer than stating your technology choices, which like religion are quite often not your choices to start with.

jfb|10 years ago

Much of the time that PowerShell is mentioned here is in the context of a discussion about how nun-punchingly awful the Unix shell is, and what could possibly replace it. I have never used PowerShell, so I have nothing to add to those discussions, but the fish-out-of-water nature of much of the commentary about it, particularly the negative commentary, is because of this.

Sadly for those of us who detest the shell, nobody seems to have a good replacement at hand.

EDIT: superfluous "I" removed

vezzy-fnord|10 years ago

Much of the time that PowerShell is mentioned here is in the context of a discussion about how nun-punchingly awful the Unix shell is, and what could possibly replace it.

Precisely my impression as well. It's the PowerShell promoters who tend to be the ones that bait first.

I'm personally not partial to PowerShell, but I hardly loathe it, either. I think the likes of the Inferno shell and es show the right path to what a modern shell should resemble.

nivla|10 years ago

I have not used powershell so I can't vouch for it. It is mainly because I couldn't find simple tutorials regarding them. Unix shell on the other hand is dead simple to use. However I get all icky if I have to use them on scripts. The outputs are always raw and never structured so it feels like a hackjob everytime. It also leads way to a different kind of vulnerabilities from incorrect parsing of outputs. I think this is the part where powershell from what I heard comes off as superior. The output is structured and you can work straight with the results.

As far as verbosity, its a mixed bag for me. It makes it easy to read at a glance with minimal mental parsing but at the same time seems such an incorrect fit for a shell where it is optimal to have it under a screen line. You can equate it to trying to write a rant on twitter.

stephengillie|10 years ago

The real "gotcha" for Powershell, for me, is the huge differences between versions. As the author mentions, v3 is much better than v1. The original version is pretty bad. A lot of parsing cmdlets don't work right. And a lot of the really useful ones aren't included, which also blocks some of the cool cmdlets you can download and install.

Having to port a script from Powershell v5 to Powershell v2 is dumb, but sadly necessary. Usually I'll write a script on the oldest server in the farm to ensure interoperability. But often the workarounds for v2 break v5's implementation of select-string or other parsing tools.

And this doesn't get into remote execution or remote script enablement, which are both separate. Powershell fragmentation is a serious problem that complicates Windows adminstration and use of this powerful tool.

nlawalker|10 years ago

Powershell definitely has its quirks, and unfortunately one of its best features - powerful remote administration - is also painful to configure and troubleshoot and is often unreliable and slow.

I wish the team in charge of Powershell would take a page from the Python community and adopt an opinionated, "one right way to do everything" stance. For anyone using or looking in to Powershell, here are a few best practices I've compiled:

- Concurrency in Powershell is generally ugly and painful. Background jobs are OK if you want to background something while you're working at the command line (although you could just open another window) but they're a pain to use in scripts, plus they're very heavyweight and slow if you need any semblance of performance. There are other ways of doing concurrency but they are not well documented and are fairly messy. Events/observer pattern is possible but weird. If you need concurrency, head for C#.

- Handling exceptions is way better than it used to be (trap), but still annoying. For your sanity and everyone else's, set $ErrorActionPreference = "Stop" at the top of every script, along with Set-StrictMode -Version Latest.

- Keep track of what you're outputting to your pipeline - anything that generates output that you're not capturing into a variable gets thrown in the pipeline, which can wreak havoc, especially if you end up with different types of objects being emitted. Sprinkle Out-Null around to avoid this. Combine multiple data fields into a new psobject if necessary (this is also good for scripts that output a bunch of information at the end).

- Don't use Write-Host - it's not output and thus can't be redirected. Use Write-Verbose frequently, and consider adding $VerbosePreference = 'Continue' in your profile to see verbose output all the time.

- If you need to access a SQL database, use ADO.NET. Invoke-SqlCmd and the rest of the sqlps module are a mess, at least the last time I looked. You can use sqlcmd.exe too but then you're back to text output.

- Add this to your profile. With this, any time you run something at the command line, it will be stored in $LastObject. I always forget to store stuff in a variable.

  function Out-Default { $input | Tee-Object -var global:LastObject | Microsoft.PowreShell.Core\out-default }

dafrankenstein2|10 years ago

Powershall comes handy when I work with open source software technologies on windows 7

tyho|10 years ago

I started reading this article not knowing anything about powershell, and finished horrified by the issues he tried to dispel in it. No remoting, no scripting? Are they serious?

WorldMaker|10 years ago

You didn't read deep enough. Remoting and Scripting are <em>off by default</em> but available. Remoting is not great, but getting better soon (as in now-ish) with SSH support getting baked into PowerShell. (Yeah, that SSH, OpenSSH.) Scripting IS great, you just have to turn it on. (It's off by default because Microsoft didn't want it to be a virus vector for your Grandfather's machine who doesn't need shell scripting and likes to click on every attachment he sees in his email.)

Get-Help about_Execution_Policies # Tells you everything you need to know about

So the first thing I typically do in PowerShell in user accounts I control is:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

After that I can run all the scripts I want to run. (From there it's a quick jump over to Chocolatey for application installs and PsGet for useful PowerShell scripts like PoshGit that adds your friendly Git branch info to the PowerShell prompt.)

ossreality|10 years ago

It worse than that, the misunderstanding that is.

I live and breathe Linux. But Powershell is so far ahead of bash for text and object manipulation, it's not really even a close call.

aldanor|10 years ago

That's an interesting claim, care to back it?

P.S. *nix shell != bash, there's zsh and fish that are light years ahead re: tab completion and other general niceties.

yellowapple|10 years ago

I don't think PowerShell v. bash is the right comparison here. PowerShell v. Perl or Python or Ruby or Tcl or somesuch would be more spot-on.

twerkmonsta|10 years ago

Noone gets Powershell.

stephengillie|10 years ago

Some of us do, but we've given up trying to expose HN to the shell. The anti-Microsoft culture that built up in the late 1990s and early 2000s has too much inertia on HN to overcome by occasional articles.