Random Post: PowerShell Plus IDE
RSS .92| RSS 2.0| ATOM 0.3
  • Home
  • About
  •  

    VMWare Ping Test using PowerShell…

    December 23rd, 2008

    I recently had to come up with a way to verify that virtual server guests on ESX hosts were back online after restarts that were scheduled using the VMWare Infrastructure Client console. Using the VMWare Automation snap-in, I wrote a PowerShell script that will test for basic ping connectivity via WMI and then leverage VMWare cmdlets to attempt to recover any VM’s that are not responding as well as sending an email to recipients when the script fails to bring them online.

    This script was implemented as a scheduled task so I simply hardcoded the values into the script rather than using the param statement since I didn’t plan on calling it from the console; however, it should be easy enough to modify if you wanted to use it interactively. Also, since it is required to connect to the VMServer prior to running any cmdlets, I used Secure-String to generate an encrypted password with a little bit of security since it would be in a text file on the server. To generate the password file, I used the following commands directly in a PowerShell console (second line wrapped):

    $secureString = Read-Host -AsSecureString
    ConvertFrom-SecureString $secureString | out-file C:\Scripts\PowerShell\VMPingTest\acctpass.txt

    As you can see from the script below, it only takes one line of .NET to decrypt the encrypted password from the file so it’s not foolproof, but still better than plain text and NTFS only. I’ve commented the script fairly heavily, so it should be easy to customize for different environments.

    ?View Code POWERSHELL
    #Load VMWare snap in:
    Add-PSSnapin VMware.VimAutomation.Core -ErrorVariable errSnapIn -ErrorAction silentlycontinue
    if ($errSnapIn.Count -ne 0) {
    	Write-Host "VMWare snap in is required."
    	exit
    	}
    #------------------------------------------------------------------------------
    # Set up variables
    #------------------------------------------------------------------------------
    #VM Server hostname
    $VMServer = "MYSERVER.MYDOMAIN"
    #User account to connect to virtual infrastructure:
    $username = "USERNAME"
    #Directory path to secure string password:
    $pass = "C:\Path\to\securestringpass.txt"
    #Directory path to target list of VM's.
    $servers = Get-Content "C:\Path\to\serverlist.txt"
    #Directory path to list of mail recipients.
    $mailrecipients = Get-Content "C:\Path\to\recipients.txt"
    #SMTP relay server
    $smtpserver = "smtp.mydomain.com"
    #Decrypt SecureString password for account:
    $pwd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((gc $pass | ConvertTo-SecureString)))
     
    #------------------------------------------------------------------------------
    # Connect to VM Server
    #------------------------------------------------------------------------------
    $server = Connect-VIServer -Server $VMServer -User $username -Password $pwd
    #Search for specific VM in the production cluster:
    $folder = Get-Folder -Name "Financial Hosts" #Target the Finanancial Hosts folder in the VM Infrastructure Client console
    $cluster = Get-Cluster -Name "Dallas HA Cluster" -Location $folder #Target the Dallas HA Cluster in the VM Infrastructure Client console
     
    #------------------------------------------------------------------------------
    # Methods
    #------------------------------------------------------------------------------
    function SendMail
    {
    	param($svr, $status)
    	foreach ($recipient in $mailrecipients)
    	{
    		$mail = new-object System.Net.Mail.MailMessage
    		$mail.Priority = 'High'
    		$mail.From = new-object System.Net.Mail.MailAddress("PINGTEST@MYDOMAIN.COM");
    		$mail.To.Add("$recipient");
     
    		#set the content
    		$mail.Subject = "$svr is not responding...";
    		$mail.Body = "$svr failed to respond to ping tests with error: $status.`n" + 
    		"This process automatically powers on virtual machines and restart virtual guests where the local network is unresponsive. `n" + 
    		"This server has not responded to automated restart tasks and needs additional attention.`n`n"
     
    		#send the message
    		$smtp = new-object System.Net.Mail.SmtpClient($smtpserver); 
    		$smtp.Send($mail);
    	}
    }
     
    #------------------------------------------------------------------------------
    # Main()
    #------------------------------------------------------------------------------
    foreach ($svr in $servers)
    {
    	$result = gwmi -class Win32_PingStatus -filter "Address='$svr'"
    	$results = $result.StatusCode
    	$vm = Get-VM -Name $svr -Location $cluster #Search for specified VM in cluster
     
    	if (($vm.PowerState -eq "PoweredOff") -and ($results -ne 0))
    	{
    		#If the VM is powered down
    		Start-VM -VM $vm.Name #Start VM
    		Start-Sleep -Seconds 60 #Allow time for VM to come online
    	}
     
    	#If the VM is powered on, but guest OS is not responding to pings
    	if (($vm.PowerState -eq "PoweredOn") -and ($results -ne 0))
    	{
    		Restart-VMGuest -VM $vm.Name #Restart VM Guest OS
    		Start-Sleep -Seconds 60 #Allow time for VM to come online
    	}
     
    	#Re-run ping test if server was originally unresponsive.
    	if ($results -ne 0)
    	{
    		$secondresult = gwmi -class Win32_PingStatus -filter "Address='$svr'"
    		$secondresults = $secondresult.StatusCode
    		switch ($secondresults)
    		{
    			0 	  { $pingresults = "Success" }
    			11001 { $pingresults = "Buffer Too Small" }
    			11002 { $pingresults = "Destination Net Unreachable" }
    			11003 { $pingresults = "Destination Host Unreachable" }
    			11004 { $pingresults = "Destination Protocol Unreachable" }
    			11005 { $pingresults = "Destination Port Unreachable" }
    			11006 { $pingresults = "No Resources" }
    			11007 { $pingresults = "Bad Option" }
    			11008 { $pingresults = "Hardware Error" }
    			11009 { $pingresults = "Packet Too Big" }
    			11010 { $pingresults = "Request Timed Out" } 
    			11011 { $pingresults = "Bad Request" }
    			11012 { $pingresults = "Bad Route" }
    			11013 { $pingresults = "TimeToLive Expired Transit" }
    			11014 { $pingresults = "TimeToLive Expired Reassembly" }
    			11015 { $pingresults = "Parameter Problem" }
    			11016 { $pingresults = "Source Quench" }
    			11017 { $pingresults = "Option Too Big" }
    			11018 { $pingresults = "Bad Destination" }
    			11032 { $pingresults = "Negotiating IPSEC" }
    			11050 { $pingresults = "General Failure" }
    		}
    	}
     
    	if ($secondresults -ne 0) 
    	{
    		SendMail $svr $pingresults
    	}
    }

    Create PowerShell Forms… Fast!

    December 19th, 2008

    The guys at Sapien have release a great utility to create PowerShell forms and since it’s free, the price is right as well. It took me 90 seconds to create the form shown below. Granted, it’s a very basic example, but creating forms in PowerShell by leveraging the System.Windows.Forms namespace takes a long time. If you need to create GUI front ends for your scripts, check out this great editor.

    ?View Code POWERSHELL
    #Generated Form Function
    function GenerateForm {
    ########################################################################
    # Code Generated By: SAPIEN Technologies PrimalForms v1.0.1.0
    # Generated On: 12/18/2008 10:04 PM
    # Generated By: Alan
    ########################################################################
     
    #region Import the Assembles
    [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
    [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
    #endregion
     
    #region Generated Form Objects
    $form1 = New-Object System.Windows.Forms.Form
    $textBox1 = New-Object System.Windows.Forms.TextBox
    $button1 = New-Object System.Windows.Forms.Button
    #endregion Generated Form Objects
     
    #----------------------------------------------
    #Generated Event Script Blocks
    #----------------------------------------------
    #Provide Custom Code for events specified in PrimalForms.
    $button1_OnClick= 
    {
    $wmi = gwmi -class Win32_ComputerSystem
    $textBox1.text=$wmi.Caption
     
    }
     
    #----------------------------------------------
    #region Generated Form Code
    $form1.Text = 'What''s my computer name?'
    $form1.Name = 'form1'
    $form1.DataBindings.DefaultDataSourceUpdateMode = 0
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 292
    $System_Drawing_Size.Height = 266
    $form1.ClientSize = $System_Drawing_Size
     
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 173
    $System_Drawing_Size.Height = 20
    $textBox1.Size = $System_Drawing_Size
    $textBox1.DataBindings.DefaultDataSourceUpdateMode = 0
    $textBox1.Name = 'textBox1'
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 60
    $System_Drawing_Point.Y = 123
    $textBox1.Location = $System_Drawing_Point
    $textBox1.TabIndex = 1
     
    $form1.Controls.Add($textBox1)
     
    $button1.TabIndex = 0
    $button1.Name = 'button1'
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 111
    $System_Drawing_Size.Height = 23
    $button1.Size = $System_Drawing_Size
    $button1.UseVisualStyleBackColor = $True
     
    $button1.Text = 'Computer Name'
     
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 93
    $System_Drawing_Point.Y = 78
    $button1.Location = $System_Drawing_Point
    $button1.DataBindings.DefaultDataSourceUpdateMode = 0
    $button1.add_Click($button1_OnClick)
     
    $form1.Controls.Add($button1)
     
    #endregion Generated Form Code
     
    #Show the Form
    $form1.ShowDialog()| Out-Null
     
    } #End Function
     
    #Call the Function
    GenerateForm

    PowerShell Plus IDE

    September 30th, 2008

    I’ve been using PrimalScript for all of my script authoring for a few years. VBScript, Batch, Perl… just about any scripting language was nicely handled by the IDE. When PowerShell came out I played around with Power Analyzer, but decided to stay with PrimalScript for the IDE. That was until Idera launched PowerShell Plus which is a progression from Power Analyzer. I have to say that this IDE beats all others for PowerShell, hands down! The code completion is astonishing for a scripting tool. While PrimalScript does well with code completion for the cmdlets, this baby code completes everything in PowerShell; including .NET classes. It has a nicely embedded script editor which allows you to easily jump between the console and your current project. The variable window is nice to view what values are currently held by the variables including help on selected variables. This is a very cool product and there are so many other features that make it definitely worth a look. If you do a lot of work with PowerShell, take this IDE out for a test drive. Even if you are a die hard PrimalScript fan, I bet you will sway your PowerShell scripting work to this editor.