, 30 tweets, 9 min read
My Authors
Read all threads
I sat down to learn enough PowerShell to recreate one of my bash functions.

What have I learned so far?
PowerShell prefers long names, and it tries to make them generic. Verb-Noun, do what to what resource.
Get-Item, Set-Location.

The PowerShell glossary defines "noun" as "The word that follows the hyphen in a Windows PowerShell cmdlet name."
I like long names for readability of scripts (when trailblazing).

Short names are better for exploring.
PowerShell has aliases, and the standard ones also combine, like "g" for Get- and "l" for Location => gl=Get-Location

I love that you get these AND long names for making descriptive scripts.
In bash (and other Unix shells), programs compose on STDIN and STDOUT. The interface between them is strings of text.

In PowerShell, the interface is objects. Programs (cmdlets) pipe objects to each other.

Ah, rich data! Ah, no string parsing!
PowerShell provides each cmdlet with standard

- command-line parsing
- help, triggered by -?
- definitions of some common parameters
- output formatting
- error handling options (coooool)
The common parameter -WhatIf is a great idea! It's like --dry-run in some Unix utilities like make.

Separate making decisions from implementing them.

You can even turn it on for the whole session with `$WhatIfPreference=$true`
Then there's the very cool -ErrorAction common parameter.
Set it to "SilentlyContinue" when you don't want errors printed to stderr.

For instance, test whether a directory exists:
if (Get-Location -Path $ofInterest -ErrorAction SilentlyContinue) { … }
Output formatting: by default you get some reasonable printout of the object. Or, pipe the output to a formatting cmdlet, like
Format-Table -Property name,value,etc -wrap
Out-Host -paging (like piping to 'less')
Get-Member (like reflection -- see methods & properties)
I got all excited about this and then had a very hard time figuring out how to make a cmdlet at all.

So far:
- make a file with extension .ps1
- create a function in there, and then make it an "advanced function" by adding cmdlet support
- source this file: . ./whatever.ps1
but watch out - you need the cmdlet spell and then params(). You'll get an error about CmdletBinding "Unexpected attribute"
until you add params() AFTER it.
Here's a weird thing: any command that you call in your function, if it returns something and you don't assign that to a variable or pipe it somewhere, that becomes an object that is output from your script.
Also any value that you put on a line by itself.
PowerShell has a distinction between data output, which continues through the pipeline, and output to the user.

`Write-Host` sends a message to the person running the cmdlet. Something on a line by itself goes down the pipe.
Ah, this must be an annotation on ‘params’

That makes the error reasonable
Checking the exit code of a command is different than in bash. Use $LastExitCode, and test with bash-like comparison operators.

This pops a dialog if "git push" fails:
Windows is generally case-insensitive. Comparison operators like "-eq" are case-insensitive with strings.

There are case-sensitive versions that add a C.
"Yes" -eq "yes"
but NOT
"Yes -ceq "yes"

I guess this is a benefit of using short names instead of symbols for the operators.
like unix tee but even more useful: Tee-Object.
Use it to send output to multiple places. The extra one can be a file or a variable.
oh, and PowerShell for newline in strings is


(backtick n)
Instead of \n
My function (and the alias to it) automatically accept positional parameters in the order I declared them, or named parameters in any order.
Cool! Did not expect!

I love happy surprises like this. It's like Ruby, except easier to install.
Now I want to change the title of the terminal tab.

echo -ne "\033]0;Changed Title\007"

$host.ui.RawUI.WindowTitle = “Changed Title”
ooh VS Code has a snippet for cmdlets --
Type "cmdlet" and ctrl-space. It gives me a whole template for the cmdlet!
I finally figured out how to map the objects in the pipe.
It's foreach, then a block in curlies and $_ is the current object.

Get-ChildItem | foreach { $_.name }
OK, here's something weird. I wanted to get the error message from 'git push' and save it, so that I can display it in my popup dialog.

So, pipe stderr to stdout (like in unix), then tee it to a variable

git push 2>&1 | Tee-Object -Variable PushOutput
The weird thing is, when git push succeeds, I get a sad error to my console. And the git push output doesn't make it to my screen.
Here's the deal: git push writes "Everything up to date" to STDERR.
PowerShell turns everything that came in on STDERR from a string into an ErrorRecord. So I get an ErrorRecord instead.

It's worse when the push does something; the output of the push report is obscured.
Why does git send these happy messages to STDERR?
Because it's reserving STDOUT for data that might be piped to another Linux command.
Git writes to STDERR for lack of Write-Host.

PowerShell distinguishes between data output and messages to the user. 💝
So I made a Function to unwrap the error and put it back into a string. It makes sense to pipe through this when I know the command I ran uses STDERR for messages.

Piping through my process converts those ErrorRecords in the pipe back into strings, and everything works as expected.

git push 2>&1 | fix-stderr | Tee-Object -Variable PushOutput
Useful: pipe to Get-Member to list all the members in the objects in the pipe.
More useful: pipe to Select-Object * to see property values.
You can ask Select-Object for specific properties instead of all of them. Separate the property names with commas.
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Jessica Joy Kerr

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!

This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!