Polish PingTool script

I mange to do form what is pinging servers.

Can someone help me to polish that script so it would look more professional way.

And I am not happy how I handle Dynamics Form Items LB_* and PB_*. (LB = Label, PB = PictureBox)

Also I was finally find away parallel pinging. But it is still not work nicely because it is under loop that why form handling is not so smooth.

You import csv file. Header: Name, Address. Separator is <Tab>

Sample csv file

Name	Address
google	google.com
powershell	powershell.org

Code

function Set-LabelElement {
    Param(
        [Parameter(Mandatory=$true)][system.Windows.Forms.Label] $Label,
        [Parameter(Mandatory=$true)][string] $Text,
        [Parameter(Mandatory=$true)][int16] $Width,
        [Parameter(Mandatory=$true)][int16] $Height,
        [Parameter(Mandatory=$true)][int16] $LocationX,
        [Parameter(Mandatory=$true)][int16] $LocationY
    )

    $Label.Name                   = ("LB_" + $text)
    $Label.text                   = $Text
    $Label.AutoSize               = $false
    $Label.width                  = $Width
    $Label.height                 = $Height
    $Label.Anchor                 = "Top, Left"
    $Label.location               = New-Object System.Drawing.Point($LocationX, $LocationY)
    $Label.Font                   = 'Microsoft Sans Serif,10'

    return $Label
}

function Set-PictureBoxElement {
    Param(
        [Parameter(Mandatory=$true)][system.Windows.Forms.PictureBox] $PictureBox,
        [Parameter(Mandatory=$true)][string] $Name,
        [Parameter(Mandatory=$true)][int16] $Width,
        [Parameter(Mandatory=$true)][int16] $Height,
        [Parameter(Mandatory=$true)][int16] $LocationX,
        [Parameter(Mandatory=$true)][int16] $LocationY
    )

    $PictureBox.Name                = ("PB_" + $Name)
    $PictureBox.width               = $Width
    $PictureBox.height              = $Height
    $PictureBox.Anchor              = "Top, Left, Right"
    $PictureBox.location            = New-Object System.Drawing.Point($LocationX, $LocationY)
    $PictureBox.BorderStyle         = 1

    return $PictureBox
}

function PreFormatPicture {
    Param(
        [Parameter(Mandatory=$true)][system.Windows.Forms.PictureBox] $PBox
    )
    # Drawing Blue Backroud to "Status Bar" Begening of script

    $bmp = New-Object System.Drawing.Bitmap 1000, 20
    
    $PenWidth = 20
    $BluePen = new-object Drawing.Pen Blue
    $BluePen.width = $PenWidth

    $Graph1 = [Drawing.Graphics]::FromImage($bmp)
    $Graph1.DrawRectangle($BluePen,  10,0,990,20)

    $PBox.Image = $bmp
    return $PBox
}

function UpdateGraph {
    Param(
        [Parameter(Mandatory=$true)][system.Windows.Forms.PictureBox] $PBox,
        [Parameter(Mandatory=$true)][int16] $Value
    )
    # Shifting picture to right and draw new status to left (over write existing)

    $bmp = New-Object System.Drawing.Bitmap $PBox.Image
    $TempGraph = [Drawing.Graphics]::FromImage($bmp)
    $PenWidth = 10

    $RedPen = new-object Drawing.Pen Red
    $RedPen.width = $PenWidth
    $GreenPen = new-object Drawing.Pen Green
    $GreenPen.width = $PenWidth

    $TempGraph.DrawImage($bmp, 10, 0)

    if ($Value -eq 1){
        $TempGraph.DrawRectangle($GreenPen,  5,0,1,20)
    } else {
        $TempGraph.DrawRectangle($RedPen,  5,0,1,20)
    }

    $PBox.Image = $bmp
    return $PBox    
}

function Prepare {
    Param(
        [Parameter(Mandatory=$true)][System.Object[]] $PictureBoxs
    )
    
    foreach ($PBox in $PictureBoxs) {
        Set-Variable -Name "$($PBox.Name)" -Value  (PreFormatPicture -PBox (Get-Variable -Name "$($PBox.Name)" -ValueOnly -Scope Script))  -Scope Script
    }    
}

function MainLoop {
    Param(
        [Parameter(Mandatory=$true)][object[]] $Servers
    )

    $script:CancelLoop = $false
    
    do {	
        foreach ($server in $servers) {
            while(@(get-job -state Running).count -ge 10){
                start-sleep -Milliseconds 50
            }
            Start-Job -Name $server -scriptblock $Pinging -ArgumentList $($server.Name), $($server.Address) | out-null            
        }

        [System.Windows.Forms.Application]::DoEvents()
        $results = get-job | Wait-Job | Receive-Job | select-object ComputerName, ComputerAddress, Status
        [System.Windows.Forms.Application]::DoEvents()

        foreach ($server in $servers) {
            $Value = ($results | Where-Object {$_.ComputerName -eq $($server.Name) -and $_.ComputerAddress -eq $($server.Address)} | select-object Status).Status
            $TempName = ($Servers | Where-Object {$_.Name -eq $($server.Name) -and $_.Address -eq $($server.Address)} | Select-Object Name).Name

            Set-Variable -Name "PB_$TempName" -Value  (UpdateGraph -Value $Value -PBox (Get-Variable -Name "PB_$TempName" -ValueOnly -Scope Script)) -Scope Script
        }
        start-sleep 0.1
        [System.Windows.Forms.Application]::DoEvents()
        start-sleep 0.1
    } until ($script:CancelLoop -eq $True)
}

function LoadData{
    $Filter = "Text File (*.txt) | *.txt"

    $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = "C:\UserData\Work\Powershell Scripts\atoll\"
                                                                               Filter = $Filter
    }

    $result = $FileBrowser.ShowDialog()

    if ($result -eq "OK") {
       $FileBrowser.FileNames
       $servers = Import-Csv -Path $($FileBrowser.FileNames) -Delimiter "`t"
       $servers = $servers | Where-Object {$_.Name -ne "" -or $_.Address -ne ""}
    } else {
        $servers = @()
    }

    return $servers
}


###########################################################################

$Pinging = { 
    Param(
        [Parameter(Mandatory=$true)][string] $computerName,
        [Parameter(Mandatory=$true)][string] $computerAddress
    )

    $ping = New-Object System.Net.NetworkInformation.Ping;

    try {
        [System.Net.NetworkInformation.PingReply]$res = $ping.Send($computerAddress)
    }
    catch [System.Net.NetworkInformation.PingException] { 
        Write-Error $_ 
    } 

    $result = $res | select-object Status
                            
    if ($result.Status -eq "Success") {
        new-object psobject -Property @{
            ComputerName=$computerName;
            ComputerAddress=$computerAddress;
            Status=1;
        }
    }
    else {
        new-object psobject -Property @{
            ComputerName=$computerName;
            ComputerAddress=$computerAddress;
            Status=0;
        }
    }
}

###########################################################################
add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

$Width =1100
$Height = 35

$Size =  $Width.ToString() + "," + $Height.ToString()

$ItemWidth = 85
$ItemHeight = 25
$StatusHeight = 20
$Border = 5
$ItemCount = -1

$PB_Width = $Width - ($Border*3 + $ItemWidth *1)

$Items = @()

$Form                            = New-Object system.Windows.Forms.Form
$Form.Name                       = "PingingTool"
$Form.text                       = "Pinging Tool"
$Form.TopMost                    = $false
$Form.MinimizeBox                = $false
$Form.MaximizeBox                = $false

$Form.ClientSize                 = $Size
$form.MinimumSize                = New-Object System.Drawing.Size(($Width + 16),($Height + 39))
$form.MaximumSize                = New-Object System.Drawing.Size(($Width + 16),($Height + 39))

$BT_Info                         = New-Object system.Windows.Forms.Button
$BT_Info.text                    = "Info"
$BT_Info.Name                    = "BT_Info"
$BT_Info.width                   = $ItemWidth
$BT_Info.height                  = $StatusHeight
$BT_Info.Anchor                  = "Bottom, Right"
$BT_Info.location                = New-Object System.Drawing.Point($Border, ($Border + $ItemHeight * ($ItemCount + 1)))
$BT_Info.Font                    = 'Microsoft Sans Serif,10'

$BT_Load                         = New-Object system.Windows.Forms.Button
$BT_Load.text                    = "Load"
$BT_Load.Name                    = "BT_Load"
$BT_Load.width                   = $ItemWidth
$BT_Load.height                  = $StatusHeight
$BT_Load.Anchor                  = "Bottom, Right"
$BT_Load.location                = New-Object System.Drawing.Point(($Width - ($Border+ $ItemWidth * 3)), ($Border + $ItemHeight * ($ItemCount + 1)))
$BT_Load.Font                    = 'Microsoft Sans Serif,10'

$BT_StartStop                    = New-Object system.Windows.Forms.Button
$BT_StartStop.text               = "Start"
$BT_StartStop.Name               = "BT_StartStop"
$BT_StartStop.width              = $ItemWidth
$BT_StartStop.height             = $StatusHeight
$BT_StartStop.Anchor             = "Bottom, Right"
$BT_StartStop.location           = New-Object System.Drawing.Point(($Width - ($Border+ $ItemWidth * 2)), ($Border + $ItemHeight * ($ItemCount + 1)))
$BT_StartStop.Font               = 'Microsoft Sans Serif,10'

$BT_Exit                         = New-Object system.Windows.Forms.Button
$BT_Exit.text                    = "Exit"
$BT_Exit.Name                    = "BT_Exit"
$BT_Exit.width                   = $ItemWidth
$BT_Exit.height                  = $StatusHeight
$BT_Exit.Anchor                  = "Bottom, Right"
$BT_Exit.location                 = New-Object System.Drawing.Point(($Width - ($Border+ $ItemWidth * 1)), ($Border + $ItemHeight * ($ItemCount + 1)))
$BT_Exit.Font                    = 'Microsoft Sans Serif,10'

$BaseButtons = @($BT_Info, $BT_Load, $BT_Exit, $BT_StartStop)
$Form.controls.AddRange($BaseButtons)
                     
$BT_StartStop.Add_Click({ 
    if ($script:ItemCount -gt 0 ) {
        if ($BT_StartStop.Text -eq "Start") {
            Prepare -PictureBoxs ($Form.controls | Where-Object {$_.Name -like 'PB_*'})
            
            $BT_StartStop.Text = "Stop"

            foreach ($Button in $BaseButtons) {
                if ($Button.Name -ne 'BT_StartStop') {
                    $Button.enabled  = $false
                }    
            }
            
            [System.Windows.Forms.Application]::DoEvents()
            MainLoop -Servers $script:servers
        } else {
            $BT_StartStop.Text = "Start"
            $script:CancelLoop = $true

            foreach ($Button in $BaseButtons) {
                if ($Button.Name -ne 'BT_StartStop') {
                    $Button.enabled  = $true
                }    
            }
        }
    }
})

$BT_Load.Add_Click({ 
    [array]$script:servers = LoadData 
    $script:servers = $script:servers | Where-Object {($_.Name).Length -gt 0 -and ($_.Address).Length -gt 0}

    if($script:servers.Length -eq 0){
        $script:ItemCount = -1
        $List = $Form.controls | Where-Object {$_.Name -like "LB_*" -or $_.Name -like "PB_*" }
        
        foreach ($item in $List) {
            $form.controls.remove($item)
            Remove-Variable -Name $($item.Name) -Scope Script
        }

        $Height = (30 + $Border + $ItemHeight * ($ItemCount + 1))
        $Size =  $Width.ToString() + "," + $Height.ToString()

        $Form.ClientSize                 = $Size
        $form.MinimumSize                = New-Object System.Drawing.Size(($Width + 16),($Height + 39))
        $form.MaximumSize                = New-Object System.Drawing.Size(($Width + 16),($Height + 39))
    } else {
        $script:ItemCount = $script:servers.Length
        $List = $Form.controls | Where-Object {$_.Name -like "LB_*" -or $_.Name -like "PB_*" }
        
        foreach ($item in $List) {
            $form.controls.remove($item)
            Remove-Variable -Name $($item.Name) -Scope Script
        }
        
        if ($script:ItemCount -gt 0) {
            $Height = (30 + $Border + $ItemHeight * ($ItemCount + 1))
            $Size =  $Width.ToString() + "," + $Height.ToString()

            $Form.ClientSize                 = $Size
            $form.MinimumSize                = New-Object System.Drawing.Size(($Width + 16),($Height + 39))
            $form.MaximumSize                = New-Object System.Drawing.Size(($Width + 16),($Height + 39))

            $Items = @()
            $i = 0
            foreach ($server in $servers) {
                $TempName = $server.Name
        
                New-Variable -Name "LB_$tempName" -Value (New-Object system.Windows.Forms.Label) -Scope Script
                Set-Variable -Name "LB_$tempName" -Value  (Set-LabelElement -Label  (Get-Variable -Name "LB_$tempName" -ValueOnly -Scope Script)  -Text $TempName -Width $ItemWidth -Height $ItemHeight -LocationX  $Border -LocationY ($Border + $ItemHeight * $i)) -Scope Script
                $Items = $Items + (Get-Variable -Name "LB_$tempName" -ValueOnly -Scope Script)

                New-Variable -Name "PB_$tempName" -Value (New-Object system.Windows.Forms.PictureBox) -Scope Script
                Set-Variable -Name "PB_$tempName" -Value  (Set-PictureBoxElement -PictureBox (Get-Variable -Name "PB_$tempName" -ValueOnly -Scope Script) -Name "$tempName" -Width $PB_Width -Height $StatusHeight -LocationX  ($ItemWidth + $Border) -LocationY ($Border + $ItemHeight * $i)) -Scope Script
                $Items = $Items + (Get-Variable -Name "PB_$tempName" -ValueOnly -Scope Script)
                $i = $i + 1
            }

            $Form.controls.AddRange($Items)
            Prepare -PictureBoxs ($Form.controls | Where-Object {$_.Name -like 'PB_*'})
        }
    } 
})

$BT_Exit.Add_Click({ 
    # Exiting Script
    $Form.Close() 
})

$BT_Info.Add_Click({ 
    # Info What kind CSV file need to be to import to tool.
    $Message = @(" Import CSV file: `r`n",
                 "Headers: Name, Address `r`n",
                 "Separator: "
    )
    [System.Windows.Forms.Messagebox]::Show($Message)
})

[void]$Form.ShowDialog()
$Form.Dispose()