# Tips for golfing in PowerShell

What general tips do you have for golfing in Windows PowerShell? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to PowerShell (e.g. "remove comments" is not an answer). Please post one tip per answer.

—taken nearly verbatim from marcog's question.

• When I googled "PowerShell golf" this was the first hit! – Matt Mar 14 '16 at 15:53

Starting with PowerShell Core 6, you can also use ranges for characters:

'a'..'z'


which can replace the much more cumbersome

0..25|%{[char]($_+97)}  • Oh, this is going to come in so handy. – AdmBorkBork Nov 29 '17 at 13:34 • [char[]](65..90) is also a handy way to generate the alphabet – Veskah Jun 21 '19 at 15:06 A simple one but control-flow statements (as opposed to pipelines), such as if, for, and while, do not need a semi-colon after their braces. E.g. # Control-flow statements (All are valid) if(...){...}"foo" for(...){...}"foo" while(...){...}"foo" switch(...){...}"foo" # Pipelines 1..2|%{...}"bar" #This will throw an error. 1..2|%{...};"bar" #This will work.  A free byte that's easy to miss. • Good point. I've been using this for ages. I've also taken the liberty of using the correct terms in your answer; I hope you don't mind. – Joey Oct 26 '18 at 7:29 • @Joey S'all good. – Veskah Oct 26 '18 at 19:59 # SLS instead -match You can use an sls cmdlet (alias for Select-String) with |% M* as shortcut for property Matches instead a -match operator with a $Matches automatic variable. Compare:

$args|sls 'pattern'|% M* vs. if("$args"-match'pattern'){$Matches} You can also use sls with -a parameter (-AllMatches) to find all matches: $args|sls 'pattern'-a|% M*

Also, you can find all matched lines in a multiline string without explicitly line breaking. It need to use a regexp option ?(m). Compare:

$args|sls '(?m)^pattern$'-a|% M*

vs.

$args-split"n"|%{$_-match'^pattern$';$Matches}

If you need an if/else at the end of the program (maybe to handle a special case differently), then instead of

if(foo){a}else{b}


do

if(foo){a;exit}b


which saves a character.

Declaring an anonymous function should come up alot. There are multiple variations of this that are covered here https://stackoverflow.com/questions/10995667/lambda-expression-in-powershell involving scripts blocks. I use a similar one to this

$a={iex([int[]][char[]]$args[0]-join"+")}
&$a 'abcd'  This would save a few character from declaring a function with a name and goes better if used more than once. The one above converts a string into a char array then into an int array. Then creates a string joined with + so that Invoke-Expression will add all the values. When declaring a hard-coded list of strings, depending on the size of the strings and the number of them, it's often shorter to split a single string up by spaces, since space-delimited splitting doesn't require a delimiter provided as a parameter For example, Instead of $numbers='one','two','three','four','five','six','seven','eight','nine','ten'


Do

$numbers=-split'one two three four five six seven eight nine ten'  You can further delimit with another character and split twice to hold shortened hard-coded multidimensional arrays • $numbers=echo one two three four five six seven eight nine ten ;) – briantist Dec 27 '18 at 20:58

# Get Length of elements of an array

You can write the name immediately after the point to get the value of the property or method.

$a=gci$a.fullName


compare to:

$a|%{$_.fullName}


Both expressions returns array like this:

C:\Archive
C:\PerfLogs
C:\Pictures
C:\Program Files
C:\Program Files (x86)
C:\Users
C:\Windows


There is a property Length which is defined for the array itself. So the Powershell expression $a.Length returns the number of elements in an array. You can use the Shortening Names to get length of elements: $s=@('22','55555','7777777')
$s|% Length # 11 bytes  or shortcut: $s|% Le*          # 8 bytes.


Compare to:

$s|%{$_.Length}   # 15 bytes


Result is the array 2,5,7, not the number 3.

# Use $x-shr$k if you want to get the result of $$\ \big\lfloor{x\over2^k}\big\rfloor \$$.

The biggest application of this is getting the truncated int result of halving a positive number without having to deal with Banker's rounding.

Works on ints and floats, however it will cast floats to ints before shifting, resulting in the same banker problem as before. Whether or not this is acceptable will obviously depend. Below is a sample script that shows the results of -5..10. 3/2 and 7/2 demonstrate the difference in return value.

Try it online!

Inspired by this answer

• note that this might not be as useful for negative numbers – ASCII-only Mar 11 '19 at 3:25

# Use Uppercase over lowercase when dealing with ASCII values

When given the choice, it's usually better to deal entirely with Uppercase. This is because their range is 65..90 vs lowercase's 97..122. For example, the one-liner to generate ABCD...Z in PS v5

-join([char[]](65..90))
-join([char[]](97..122))


This still applies when normalizing mix-case because using the |% short-property trick, ToUpper and ToLower shorten to *per and *wer, respectively.

"Lower to upper: "+-join([char[]](97..122))|% *per
"Upper to lower: "+-join([char[]](65..90))|% *wer


Try it online!

# Use the new() method instead of New-Object

For example, instead of doing the following (37 bytes):

New-Object Drawing.Bitmap(1024,1024)


Try (32 bytes):

[Drawing.Bitmap]::new(1024,1024)


Kind of an edge case, but you can do this pretty much anytime you initialize a new .NET object. Sadly, there's no equivalent for COM objects so you still have to use New-Object for those :P

# Short way to convert bits to integer:

if you trust that $args contains int only (see Joey's comments below): $args|%{$r+=$_+$r};$r


if you assume that $args is an array of int or string representation: $args|%{$r+=+$r+$_};$r


$args is an array of char 48, 49: $args|%{$r+=+$r+"$_"};$r


A sliding byte containing 8 bits from the array of int:

$args|%{($r=2*$r%256+$_)}


Compare to:

[Convert]::ToInt64($args,2)  • Any reason why you're using $r+=+$r+$_ instead of just $r+=$_+$r? Coercion should work the same for the $null case. – Joey Jan 13 at 11:37
• Good point. The +$r guarantees that $r will be converted $r to an integer. because the array of int was specified as an incoming condition, you are right: it should be $args|%{$r+=$r+$_};$r. Thanks – mazzy Jan 13 at 13:00
• That's why I proposed $_+$r, as $_ is already numeric and arithmetic operators convert the right operand to the type of the left. If $r were a string $r+$_ would not do the same as +$r+$_. – Joey Jan 13 at 14:10
• \$args is input parameters. I'm afraid to trust the input parameters so much :) Text fixed. Joey, freely edit the text as you wish. Thanks. – mazzy Jan 13 at 14:50

If you're calling a command with a string argument, you don't need quotes unless there are spaces:

gci MyPath
gci 'My Path'


But that space cost you 2 extra bytes. You can save a single byte by escaping the space without quotes:

gci My Path


This is only worth it when there's a single space, because there's no advantage with 2 or more.

If a path contains more than 1 space, you can do :

gci C:\My*Example*Path


gci 'C:\My Example Path'


or

gci C:\My Example Path

• Useful to know, although it risks picking up a different but similar path. And I'm not sure how many code golf challenges involve the file system, as I'd be very wary of testing any solution that might be clobbering my system. If you wrote this answer as a continuation of this one, the gci` was only for illustrative purposes of a command that may receive an argument with spaces. Not an actual file system golfing trick. – Joey Oct 10 '18 at 5:12