Search code examples
arrayspowershelladministrator

Array gives no output outside Function in PowerShell


Here is the code

$conn =  'saruspc01', '194.195.5.65'

 function lll {
    foreach($co in $conn)
    {
       $check = Test-Connection $co -Count 3 -ErrorAction SilentlyContinue
       $zugriffzeit = $check | select ResponseTime | Measure-Object ResponseTime -Average
       $avg = [system.math]::Round($zugriffzeit.Average)

        if($check -eq $null)
        {
            $pcre = Write-Output $co
            $pire = Write-Output 'False'
            $zure = 'Null'
        }
        else
        {
            $pcre = Write-Output $co
            $pire = Write-Output 'True'
            $zure = Write-Output "$avg ms"
            $zure = $zure.Replace(' ','')
        }
        $table += @( @{PCName=$pcre;    PingResult=$pire;    Zugriffszeit=$zure} )
        #$table | ForEach {[PSCustomObject]$_} | Format-Table -AutoSize
    }
}

If I execute the same code without Function, it works. I need the Funktion though and want to do this is this way. How can I fix it?


Solution

  • The big issue is that you're adding items to $table but you don't return the table output back to the user. So, first things first, modify the end of your function to read like this. (I added the comment #EndOfForEach to help highlight where the changes need to go.

            $table += @( @{PCName=$pcre;    PingResult=$pire;    Zugriffszeit=$zure} )                
        }#EndOfForEach
        return $table
    }
    

    With that change done, your function will work but only when you call it like so:

    PS:\>lll
    Name                           Value                                             
    ----                           -----                                             
    PCName                         behemoth                                          
    Zugriffszeit                   1ms                                               
    PingResult                     True                                              
    PCName                         notonline                                         
    Zugriffszeit                   Null                                              
    PingResult                     False                                             
    

    At this point, I'd recommend two changes. One, the layout is hard to read, so I'd convert the function to use a [psCustomObject] datatype instead, like so.

    function lll {
        $results = New-Object System.Collections.ArrayList
        #...
    
       $results.Add([psCustomObject]@{PCName=$pcre;    PingResult=$pire;    Zugriffszeit=$zure})| Out-Null
        }#EndOfForEach
        return $results
    }
    

    For an output like so:

    PS>lll
    
    PCName    PingResult Zugriffszeit
    ------    ---------- ------------
    behemoth  True       1ms         
    notonline False      Null  
    

    And if you want to take your function to the next level, you'd be well serverd to look to modify the function to accept parameters instead of relying on the $conn variable already being set. Hope this helps, let me know if you have any questions or if I could dig deeper into an area.

    Why doesn't $results maintain a value?

    PowerShell uses variable scoping, so the $results variable we define in this function will only exist for as long as the function is running. To keep the results, assign them to a variable when you call the function, like this.

    $MyPingResults = lll
    #no output is written to screen.
    
    PS>$MyPingResults #get all results
    PCName    PingResult Zugriffszeit
    ------    ---------- ------------
    behemoth  True       1ms         
    notonline False      Null     
    
    PS>$myPingResults[0] #get first result
    
    PCName   PingResult Zugriffszeit
    ------   ---------- ------------
    behemoth True       7ms         
    
    PS>$myPingResults | Where PingResult -eq $false #only get failed results
    
    PCName    PingResult Zugriffszeit
    ------    ---------- ------------
    notonline False      Null        
    
    

    Completed Script

    function lll {
        $results = New-Object System.Collections.ArrayList
        foreach($co in $conn)
        {
           $check = Test-Connection $co -Count 3 -ErrorAction SilentlyContinue
           $zugriffzeit = $check | select ResponseTime | Measure-Object ResponseTime -Average
           $avg = [system.math]::Round($zugriffzeit.Average)
    
            if($check -eq $null)
            {
                $pcre = Write-Output $co
                $pire = Write-Output 'False'
                $zure = 'Null'
            }
            else
            {
                $pcre = Write-Output $co
                $pire = Write-Output 'True'
                $zure = Write-Output "$avg ms"
                $zure = $zure.Replace(' ','')
            }
            $results.Add([psCustomObject]@{PCName=$pcre;    PingResult=$pire;    Zugriffszeit=$zure})| Out-Null
        }#EndOfForEach
        return $results
    }