tags:

views:

1876

answers:

8

A while back I was reading about multi-variable assignments in PowerShell. This lets you do things like this

64 >  $a,$b,$c,$d = "A four word string".split()

65 >  $a
A

66 >  $b
four

Or you can swap variables in a single statement

$a,$b = $b,$a

What little known nuggets of PowerShell have you come across that you think may not be as well known as they should be?

+11  A: 

The $$ command. I often have to do repeated operations on the same file path. For instance check out a file and then open it up in VIM. The $$ feature makes this trivial

PS> tf edit some\really\long\file\path.cpp
PS> gvim $$

It's short and simple but it saves a lot of time.

JaredPar
never knew about that.. very useful little tidbit. Thanks!
Andy Schneider
Really, -1? Does someone care to explain why they thought this was a bad answer?
JaredPar
THere are a lot of great answers and I thank everyone who posted something up here. I chose this one for a couple reasons. I personally did not know about $$ and also it was the first answer. Thanks again to everyone who chimed in. Lots of great input!
Andy Schneider
+7  A: 

$OFS - output field separator. A handy way to specify how array elements are separated when rendered to a string:

PS> $OFS = ', '
PS> "$(1..5)"
1, 2, 3, 4, 5
PS> $OFS = ';'
PS> "$(1..5)"
1;2;3;4;5
PS> $OFS = $null # set back to default
PS> "$(1..5)"
1 2 3 4 5

Always guaranteeing you get an array result. Consider this code:

PS> $files = dir *.iMayNotExist
PS> $files.length

$files in this case may be $null, a scalar value or an array of values. $files.length isn't going to give you the number of files found for $null or for a single file. In the single file case, you will get the file's size!! Whenever I'm not sure how much data I'll get back I always enclose the command in an array subexpression like so:

PS> $files = @(dir *.iMayNotExist)
PS> $files.length # always returns number of files in array

Then $files will always be an array. It may be empty or have only a single element in it but it will be an array. This makes reasoning with the result much simpler.

Array covariance support:

PS> $arr = '127.0.0.1','192.168.1.100','192.168.1.101'
PS> $ips = [system.net.ipaddress[]]$arr
PS> $ips | ft IPAddressToString, AddressFamily -auto

IPAddressToString AddressFamily
----------------- -------------
127.0.0.1          InterNetwork
192.168.1.100      InterNetwork
192.168.1.101      InterNetwork

Comparing arrays using Compare-Object:

PS> $preamble = [System.Text.Encoding]::UTF8.GetPreamble()
PS> $preamble | foreach {"0x{0:X2}" -f $_}
0xEF
0xBB
0xBF
PS> $fileHeader = Get-Content Utf8File.txt -Enc byte -Total 3
PS> $fileheader | foreach {"0x{0:X2}" -f $_}
0xEF
0xBB
0xBF
PS> @(Compare-Object $preamble $fileHeader -sync 0).Length -eq 0
True

Fore more stuff like this, check out my free eBook - Effective PowerShell.

Keith Hill
+4  A: 

Along the lines of multi-variable assignments.

$list = 1,2,3,4

While($list) {
$head, $list = $list
$head
}

1
2
3
4

Doug Finke
Thank you for making this a community wiki answer.
JasonMArcher
+6  A: 

A feature that I find is often overlooked is the ability to pass a file to a switch statement.

Switch will iterate through the lines and match against strings (or regular expressions with the -regex parameter), content of variables, numbers, or the line can be passed into an expression to be evaluated as $true or $false

switch -file 'C:\test.txt' 
{   
  'sometext' {Do-Something}   
  $pwd {Do-SomethingElse}  
  42 {Write-Host "That's the answer."}  
  {Test-Path $_} {Do-AThirdThing}  
  default {'Nothing else matched'} 
}
Steven Murawski
I think Bruce's book pointed out that switch was one of the most powerful language constructs in PowerShell. Passing in a file is very cool. Thanks Steve.
Andy Schneider
That he did.. and I find the file part the most overlooked. Thanks for the question!
Steven Murawski
+5  A: 

The fact that many operators work on arrays as well and return the elements where a comparison is true or operate on each element of the array independently:

1..1000 -lt 800 -gt 400 -like "?[5-9]0" -replace 0 -as "int[]" -as "char[]" -notmatch "\d"

This is faster than Where-Object.

+8  A: 

By far the most powerful feature of PowerShell is its ScriptBlock support. The fact that you can so concisely pass around what are effectively anonymous methods without any type constraints are about as powerful as C++ function pointers and as easy as C# or F# lambdas.

I mean how cool is it that using ScriptBlocks you can implement a "using" statement (which PowerShell doesn't have inherently). Or, pre-v2 you could even implement try-catch-finally.

function Using([Object]$Resource,[ScriptBlock]$Script) {
    try {
        &$Script
    }
    finally {
        if ($Resource -is [IDisposable]) { $Resource.Dispose() }
    }
}

Using ($File = [IO.File]::CreateText("$PWD\blah.txt")) {
   $File.WriteLine(...)
}

How cool is that!

Josh Einstein
+4  A: 

I've been using this:

if (!$?) {  # if previous command was not successful
    Do some stuff
}

and I also use $_ (current pipeline object) quite a bit, but these might be more known than other stuff.

Bratch
+1  A: 

Not a language feature but super helpful

f8 -- Takes the text you have put in already and searches for a command that starts with that text.

rerun