Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell pitfalls

Tags:

powershell

What Powershell pitfalls you have fall into? :-)

Mine are:

# -----------------------------------
function foo()
{
    @("text")
}

# Expected 1, actually 4.
(foo).length

# -----------------------------------
if(@($null, $null))
{
    Write-Host "Expected to be here, and I am here."
}

if(@($null))
{
    Write-Host "Expected to be here, BUT NEVER EVER."
}

# -----------------------------------

function foo($a)
{
    # I thought this is right.
    #if($a -eq $null)
    #{
    #    throw "You can't pass $null as argument."
    #}

    # But actually it should be:
    if($null -eq $a)
    {
        throw "You can't pass $null as argument."
    }
}

foo @($null, $null)

# -----------------------------------

# There is try/catch, but no callstack reported.
function foo() 
{
   bar
}

function bar() 
{
  throw "test"
}

# Expected:
#  At bar() line:XX
#  At foo() line:XX
#  
# Actually some like this:
#  At bar() line:XX
foo

Would like to know yours to walk them around :-)

like image 272
alex2k8 Avatar asked Apr 29 '09 17:04

alex2k8


5 Answers

My personal favorite is

function foo() {
  param ( $param1, $param2 = $(throw "Need a second parameter"))
  ...
}

foo (1,2)

For those unfamiliar with powershell that line throws because instead of passing 2 parameters it actually creates an array and passes one parameter. You have to call it as follows

foo 1 2
like image 82
JaredPar Avatar answered Nov 05 '22 06:11

JaredPar


Another fun one. Not handling an expression by default writes it to the pipeline. Really annoying when you don't realize a particular function returns a value.

function example() {
  param ( $p1 ) {
  if ( $p1 ) {
    42
  }
  "done"
}

PS> example $true 
42
"done"
like image 44
JaredPar Avatar answered Nov 05 '22 08:11

JaredPar


$files = Get-ChildItem . -inc *.extdoesntexist
foreach ($file in $files) {
    "$($file.Fullname.substring(2))"
}

Fails with:

You cannot call a method on a null-valued expression.
At line:3 char:25
+ $file.Fullname.substring <<<< (2)

Fix it like so:

$files = @(Get-ChildItem . -inc *.extdoesntexist)
foreach ($file in $files) {
    "$($file.Fullname.substring(2))"
}

Bottom line is that the foreach statement will loop on a scalar value even if that scalar value is $null. When Get-ChildItem in the first example returns nothing, $files gets assinged $null. If you are expecting an array of items to be returned by a command but there is a chance it will only return 1 item or zero items, put @() around the command. Then you will always get an array - be it of 0, 1 or N items. Note: If the item is already an array putting @() has no effect - it will still be the very same array (i.e. there is no extra array wrapper).

like image 10
Keith Hill Avatar answered Nov 05 '22 06:11

Keith Hill


# The pipeline doesn't enumerate hashtables.
$ht = @{"foo" = 1; "bar" = 2}
$ht | measure

# Workaround: call GetEnumerator
$ht.GetEnumerator() | measure
like image 7
Richard Berg Avatar answered Nov 05 '22 06:11

Richard Berg


Here are my top 5 PowerShell gotchas

like image 6
John D. Cook Avatar answered Nov 05 '22 06:11

John D. Cook