Monday, June 3, 2013

Power Shell Today

I absolutely love powershell and all the wonderful things you can do. Every day I work with it I find yet another thing it can do and another way it can automate my work process. Here was my problem. A series of about 11 servers on the network. Each server must be started in a particular order and be completely running before the next one gets started. The problem is when there is a power outage and with the current technology we have, I am required to be on site and start each server in the right order. Depending when the power goes down this may be when I am at another site or in the early morning hours. So the question remains is there a way to automate this without me being onsite and without spending a dime of the company's money. With powershell there is a way. So lets consider what we need. 1. First server power back on in the event of a power failure. 2. Start servers from script or remotely. 3. Check and verify not only that the server is started but services are started before proceeding to the next. 4. Repeat until complete with all servers. The first challenge can be addressed two ways. One we could have the server power up once power is restored through BIOS setting. However, there are some dangers to this. For instance if the power is fluctuating after full battery backup is depleted then that server might have several hard reboots. This would not be good for the power. Since I can get alerts when the power is down, I can setup the drac on this dell server for remote access and remote startup. However, since all servers do not have this I cannot do this with the rest. Now how to start up the next servers remotely or from script without DRAC? We could enable to WOL feature. Now some will say this is a security risk. Honestly it is not with a properly configured firewall. In addition since servers are supposed to be on all the time anyway the worst thing that could happen is that an attacker connected locally to the network with the MAC address of the server could turn it on. Not really going to be a problem. WOL will have to be enabled in the OS at the card and also enabled at the BIOS level. This will require a NIC with the right driver and a BIOS that is designed to do this. You might have to update one or both. If your server is really old you might not have this as an option. The next step is to create the WOL packet. I have chosen to do this in Powershell. No surprise there. I created a function based on this guys script found here. http://andrewmorgan.ie/2011/08/22/simple-wake-on-lan-powershell-module/
function send-wakeonlan{
    param(
        [string]$mac)
    if (!($mac -like "*:*:*:*:*") -or ($mac -like "*-*-*-*-*")){
    write-error "mac address not in correct format"
    break
    }

    $string=@($mac.split(":""-") | foreach {$_.insert(0,"0x")})
    $target = [byte[]]($string[0], $string[1], $string[2], $string[3], $string[4], $string[5])

    $UDPclient = new-Object System.Net.Sockets.UdpClient
    $UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)
    $packet = [byte[]](,0xFF * 102)
    6..101 |% { $packet[$_] = $target[($_%6)]}
    $UDPclient.Send($packet, $packet.Length) | out-null
}
# Author ITBABLE.BLOGGER.COM This is an edited and altered scrip from the link below.
# source http://andrewmorgan.ie/2011/08/22/simple-wake-on-lan-powershell-module/
The reason I am making this a function is so that I can dot source this in a later script. It keeps the end result clean and simple. to dot source something just browse powershell to the right folder path and then ./script-name.ps1 Now to call the function I will only need to find the correct MAC Address to use and then enter it into the following command. send-wakeonlan -mac “00:11:22:33:AA:BB" There that was not so hard was it? Now for the next step. How to know when the server has fully started and is ready. For this I have adapted a script that was not exactly set to do what we are doing with it but it works great. Please understand I am a big believer in not rewriting what someone else has already done. I big thank you for those have gone before and worked out the bigger problems. This script I did not modify. Make sure to take a look at the original site I found it it on. Located here http://gallery.technet.microsoft.com/scriptcenter/PowerShell-queryService-94ecfac6
# This Function Will Query A Dependancy Service and wait until the timer expires OR for the service to start.

function Query-Service { param($Service,$timer1,$Computer)
    $success = ""
    write-host "Waiting on $Service Service..."
   
    # Create a for loop to INC a timer Every Second
    for ($b=1; $b -lt $timer1; $b++) {
            $servicestat = get-service $Service -ComputerName $Computer
            $status = $servicestat.status
            $b2 = $timer1 - $b

            # Determine the Percent Complete for the seconds.
            $percent = $b * (100 / $timer1)
           
            # Display the progress on the Screen
            Write-Progress -Activity "Waiting on $Service Service..." -PercentComplete $percent -CurrentOperation "$b2 Seconds Remaining" -Status "Current WMI Status: $status"
           
            # Determine if the Process is Running. If not, reloop. If so exit loop.
            if ($status -eq "Running") {
                write-host "$Service Service Started Successfully: $status in $b Seconds"
                [int]$b = $timer1    
                    $success = "yes"
               
                # Tells the Loop to Stop Incrementing as the Service is running
                Write-Progress -Activity "Completed" -Status "Current $Service Status: $status in $b Seconds" -Completed
               
            }
       
        # Start-Sleep is available for the write-progress. Its value is in seconds.
        start-sleep 1

    }
    # The script will now stop as the above loop has meet its time criteria and the success is not set to yes.time has expired.
    if ($success -ne "yes") {
        write-host "ERROR in Script: $Service Service Did Not Start In $timer1 Seconds. Status: $status"
        # Stop the Script
       BREAK
    }
}

# The service must be the actual executible name, not the friendly name
# The Below Examples are Querying SQL Services for startup waiting 120 seconds for a timeout.
# Source http://gallery.technet.microsoft.com/scriptcenter/PowerShell-queryService-94ecfac6
</blockquote>
Now we have all the pieces we need. All we need to do now is create a new script dot source the two functions and we have something that looks like this.
 . "c:\Scripts\Samples\QueryService.ps1"
. "c:\Scripts\functions\Send-WakeOnLan.PS1" #Wake SERVER1 send-wakeonlan -mac 00:11:22:AA:BB:CC" Queryservice "Some Service" "300" "192.168.1.10" #Wake SERVER2 send-wakeonlan -mac 11:22:33:BB:CC:DD"
Queryservice "Another Service" "300" "192.168.1.11"

 The cool thing is the script will hold and wait for as long as you tell it to. Here the wait is 300 seconds and you can change that based on how long the server can take to start. You can also add the names of multiple services to wait for on one server making sure all the needed ones have started. That is the quick and dirty part. Later it would be wise to enter error coding to send you an email alert if a service has failed. Or change it to move on any way gather the alerts and send them off in one email. That however, can get a little tricky and would be best to save for another post. When I have the time to take that on.

No comments:

Post a Comment