Hacker News new | ask | show | jobs
by nlawalker 3950 days 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 }