mercredi 29 avril 2015

PowerShell - If/Else Statement Doesn't Work Properly

First off I apologize for the extremely long, wordy post. It’s an interesting issue and I wanted to be as detailed as possible. I’ve tried looking through any related PowerShell posts on the site but I couldn’t find anything that helped me with troubleshooting this problem.

I've been working on a PowerShell script with a team that can send Wake-On-Lan packets to a group of computers. It works by reading a .csv file that has the hostnames and MAC’s in two columns, then it creates the WOL packets for each computer and broadcasts them out on the network. After the WOL packets are sent, it waits a minute and then pings the computers to verify they are online, and if any don’t respond it will display a window with what machines didn’t respond to a ping. Up until the final If/Else statement works fine, so I won't be going into too much detail on that part of the script (but of course if you want/need further details please feel free to ask).

The problem I’m having is with the final If/Else statement. The way the script is supposed to work is that in the ForEach loop in the middle of the script, the value of variable $PingResult is true or false depending on whether or not the computer responds to a ping. If the ping fails, $PingResult is $false, and then it adds the hostname to the $PingResult2 variable.

In theory if all of the machines respond, the If statement fires and the message box displays that it was a success and then the script stops. If any machines failed to respond, the Else statement runs and it joins all of the items together from the $PingResult2 variable and displays the list in a window. What actually happens is that even if all of the machines respond to a ping, the If statement is completely skipped and the Else statement runs instead. However, at that point the $PingResult2 variable is blank and hence it doesn’t display any computer names of machines that failed to respond. In my testing I’ve never seen a case where the script fails to wake a computer up (assuming it’s plugged in, etc.), but the Else statement still runs regardless. In situations where the Else statement runs, I’ve checked the value of the $PingResult2 variable and confirmed that it is blank, and typing $PingResult2 –eq “” returns $true.

To add another wrinkle to the problem, I want to return to the $PingResult2 variable. I had to create the variable as a generic list so that it would support the Add method to allow the variable to grow as needed. As a test, we modified the script to concatenate the results together by using the += operator instead of making $PingResult2 a list, and while that didn’t give a very readable visual result in the final display window if machines failed, it did actually work properly occasionally. If all of the computers responded successfully the If statement would run as expected and display the success message. Like I said, it would sometimes work and sometimes not, with no other changes making a difference in the results. One other thing that we tried was taking out all of the references to the Visual Basic assembly and other GUI elements (besides the Out-GridView window) and that didn’t work either.

Any idea of what could be causing this problem? Me and my team are completely tapped out of ideas at this point and we’d love to figure out what’s causing the issue. We’ve tried it on Windows 7, 8.1, and the latest preview release of Windows 10 with no success. Thanks in advance for any assistance.

P.S Extra brownie points if you can explain what the regular expression on line 29 is called and how it exactly works. I found out about it on a web posting that resolved the issue of adding a colon between every two characters, but the posting didn’t explain what it was called. (Original link http://ift.tt/1DCHRZb)

Original WOL Script we built the rest of the script around was by John Savill (link http://ift.tt/1bVFM5d)

Script

Add-Type -AssemblyName Microsoft.VisualBasic,System.Windows.Forms

$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.ShowDialog() | Out-Null

$FileVerify = Get-Content -Path $OpenFileDialog.FileName -TotalCount 1
$FileVerify = ($FileVerify -split ',')

If($FileVerify[0] -ne "Machine Name" -or $FileVerify[1] -ne "MAC")

{

    $MsgBox = [System.Windows.Forms.MessageBox]::Show("The CSV File's headers must be Machine Name and MAC.",'Invalid CSV File headers!',0,48)
    Break

}

$ComputerList = Import-Csv -Path $OpenFileDialog.FileName |
Out-GridView -PassThru -Title "Select Computers to Wake up"

ForEach($Computer in $ComputerList)

    {

        If($Computer.'MAC' -notmatch '([:]|[-])')

            {

                $Computer.'MAC' = $Computer.'MAC' -replace '(..(?!$))','$1:'

            }

        $MACAddr = $Computer.'MAC'.split('([:]|[-])') | %{ [byte]('0x' + $_) }
        $UDPclient = new-Object System.Net.Sockets.UdpClient
        $UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)
        $packet = [byte[]](,0xFF * 6)
        $packet += $MACAddr * 16
        [void] $UDPclient.Send($packet, $packet.Length)
        write "Wake-On-Lan magic packet sent to $($Computer.'Machine Name'.ToUpper())"

    }

Write-Host "Pausing for sixty seconds before verifying connectivity."
Start-Sleep -Seconds 60

$PingResult2 = New-Object System.Collections.Generic.List[System.String]

ForEach($Computer in $ComputerList)

    {

        Write-Host "Pinging $($Computer.'Machine Name')"
        $PingResult = Test-Connection -ComputerName $Computer.'Machine Name' -Quiet

        If ($PingResult -eq $false)

            {

                $PingResult2.Add($Computer.'Machine Name')

            }

    }

If($PingResult2 -eq "")

    {

        [System.Windows.Forms.MessageBox]::Show("All machines selected are online.",'Success',0,48)
        Break

    }

Else

    {

        $PingResult2 = ($PingResult2 -join ', ')
        [System.Windows.Forms.MessageBox]::Show("The following machines did not respond to a ping: $PingResult2",'Unreachable Machines',0,48)

    }

Aucun commentaire:

Enregistrer un commentaire