Surprises in Powershell coding

Link to My Coding journal for powershell

Yes. There are quite a few surprises


function f1()
{
    #good
    $x = f2 -arg1 "abc"

    #it is a bad idea not to consume what f2 returns
    f2 -arg1 "abc"

    return "somevalue"
}

#f1 may be returning a lot more if not

#do this
$x = f2 -arg1 "abc"

#not
f2("abc")

class {
[void]f1()
  {
     #this won't display
     #this would if this function is outside
     $somearray | select-object .... | Format-Table

     #this would display also if it is outisde
     #but not inside a function in a class
     $somearray
  }
}

if ($count > 10)
{
  break
}

when it should be

if ($count -gt 10)
{
  break
}

function f1($a,$b){}

Calling it as 

f1 -c "blah"

Misspellings is a BIG BUG....Be aware

They have a special meaning in powerhell

Not used for calling functions in powershell native code

However they are used when calling class methods or underlying dotnet classes

I get tripped up all the time and end up using braces when I shouldn't be

this results in significant surprises as they do actually work most of the time!!!

Understand scopes: especially script: scope

a child scope can read its parent scopes variables. It cannot update

a child scope will hide a parent scope if the name is duplicate

You can refer to your immediate parent scope using scope:

that is how you can change a value of a variable in its parent scope

this is useful in your closures

stdin redirection will not work with Read-Host in powershell

Search for: stdin redirection will not work with Read-Host in powershell

and that sucks!

but that is not the most flexible thing to do and paints one into a convention, I am afraid!!!

Do pipes use stdin and stdout in powershell?

Search for: Do pipes use stdin and stdout in powershell?


if ($script:plantName -ne "sidrap")
    {
        $ea.addError("Plant name is not sidrap" #missing brace here
    }

if ($ea.areThereErros -eq $true)
    {
        $ea.printErrorArray
        return $false
    }

The $ea is an object. so the function areThereErrors needs to be arethereerrors(). Missing them will invalidate the boolean check.


function validateConfig() {}

#with out the braces around the function
#it evaluates to true

if ((validateConfig) -eq $false)
    {
        p -message "Validating failed. Returning"
        return
    }

So ... in short pay special attention to if clauses that use output from functions


pe -message "Exception message: $($er.Exception.Message)"

with out the brackets, .Exception.Message are considered literals

1. Casting a class object even to itself will throw an exception

2. So include it only once

3. This normally shows up in embedded powershell scripts in vscode. Just close vscode and reopen to deal with it.


$myargs = @{
    $paramPlantName = $dPlantName
    $paramOverridePlantName =$dOverridePlantName
    $paramPlantDataFileType = $dPlantDataFileType

    $paramPlantBaseDir = $dPlantBaseDir
    $paramMaxFilesToProcess = $dMaxFilesToProcess

    $paramRunLocal = $false
}

That is a hashtable initialization. The left hand side are keys. It is unlikely that they are variables. So the $sign needs to be removed. I run into this often.

How powershell uses console is outright confusing

read-host, write-host and the pipeline printing are not synchronized

1. Not that I know there is a warning for using a variable that is not defined in vscode.

2. But there is a warning for a variable that is not used

3. So pay attention to the unused variables as they indicate what should be used but were not


$myHashTable = @{a="b";c="d"}

#not fruitful
$myHashTable.tostring()

#but you can do this
$myHashTable | Format-table

#or just on a line by itself
$myHashtable

docs on hashtable powershell


function getInverterDataArray($invHt)
{
    $keys = $invHt.Keys
    [System.Collections.ArrayList]$invArrayList = [System.Collections.ArrayList]@()
        
    foreach ($invName in $keys)
    {
        $individualInvArray = $invHt[$invName]
        $m = Measure-Object -Data $individualInvArray -property tag_value
        
        [classInverterData]$inverterData = [classInverterData]::new()
        $inverterData.name = $invName
        $inverterData.numOfPoints = $m.count
        $inverterData.averageEnergy = $m.average
        $inverterData.totalEnergy = $m.sum
    #The below can create havoc as well with out $result
        $result = $invArrayList.Add($inverterData)
    }
    #The below can create havoc
    $invArrayList | Format-table
    return $invArrayList
}

there is no niceway to see it as a hashtable!

1. You need to study how exceptions work

2. To stop a script or not on exceptions

3. how to print these exceptions

1. Not to duplicate running of reusable scripts

2. How best to do this

3. My original trick is sufficiently dangerous and may break things

4. look for a better approach.