Showing posts with label Excel. Show all posts
Showing posts with label Excel. Show all posts

Thursday, February 19, 2009

PowerShell, VM & Excel (Conditional Formatting)

Some of our support staff recently asked if they could get access to the VM Virtual Center in order to see the status of VM servers. We recognized the importance of giving them this information, but did not like the idea of giving them access to Virtual Center. So I was asked for suggestions: Yep you guessed it PowerShell to the rescue!

I wrote a script that gets all the Virtual machines and then populates an Excel spreadsheet. But wait there's more! A colleague asked if it was possible to create a dashboard (you know Green for good, Red for bad). Being quite familiar with Excel, I knew conditional formatting was the answer.

This is a simplified version of the output from the script (only 2 properties):


How did we make this work? Well, the first thing I do when automating Excel from PowerShell is to open up Excel and record a macro. I find it helpful to do this in very meticulous fashion. I record individual tasks then hit Alt-F11 to look at the generated code. If you have no experience with VBA and Excel, you should take a few minutes to get acquainted. Once I see the VBA code, I have a good idea how to convert it into PowerShell.

Here is the script:

   1: # Create $cred variable (only if you need to pass different creds)
   2: $cred = Get-Credential 'osu\fatbeard'
   3: Connect-VIServer -Server 'VM-Server' -Credential $cred
   4:  
   5: # Get all VM Boxes, we are interested in this
   6: # point only in the name and PowerState
   7: $VirtualServers = Get-VM | sort Name | select Name, PowerState 
   8:  
   9: # Create an instance of Excel
  10: $Excel = New-Object -comobject Excel.Application
  11: $Excel.visible = $True 
  12: $Workbook = $Excel.Workbooks.Add()
  13: $Info = $Workbook.Worksheets.Item(1)
  14:  
  15: # Create our column headers
  16: $Info.Cells.Item(1,1) = "VM Name"
  17: $Info.Cells.Item(1,2) = "PowerState"
  18:  
  19: # Add a little formatting to the column header
  20: $Style = $Info.UsedRange
  21: $Style.Interior.ColorIndex = 19
  22: $Style.Font.ColorIndex = 11
  23: $Style.Font.Bold = $True
  24:  
  25: # Data starts at row 2
  26: $intRow = 2
  27:  
  28: # iterate over each VM
  29: foreach ($VirtualServer in $VirtualServers)
  30: {
  31:     if ($VirtualServer.PowerState -eq "PoweredOn")
  32:     {
  33:         $PoweredState = 1
  34:     }
  35:     else
  36:     {
  37:         $PoweredState = 0
  38:     }    
  39:     
  40:     $Style.Cells.Item($intRow, 1) = $VirtualServer.Name
  41:     $Style.Cells.Item($intRow, 2) = $PoweredState 
  42:     $intRow++
  43: }
  44:  
  45: ## Now for some formatting 
  46: #  For more data on the enumeration values look at the following:
  47: #  XlFormatConditionType Enumeration:       http://msdn.microsoft.com/en-us/library/bb241301.aspx 
  48: #  XlFormatConditionOperator Enumeration: http://msdn.microsoft.com/en-us/library/bb241299.aspx
  49: #  XlIconSet Enumeration                  http://msdn.microsoft.com/en-us/library/bb241324.aspx
  50: #  XlConditionValueTypes Enumeration      http://msdn.microsoft.com/en-us/library/bb241028.aspx
  51: ## The constants that we will use
  52:  
  53: $xlCenter = -4108
  54: $xlCellValue = 1
  55: $xlEqual = 3
  56: $xl3TrafficLights2 = 5
  57: $xl3Symbols = 7
  58: $xlConditionValueNumber = 0
  59: $xlIconSet = 6
  60:  
  61: # Make Column "A" wide enough for content
  62: $info.Range("A:A").entireColumn.Autofit()
  63:  
  64: # Make Column "B" wide enough for content and Center the contents
  65: $info.Range("B:B").entireColumn.Autofit()
  66: $info.Range("B:B").HorizontalAlignment = $xlCenter 
  67:  
  68: # This will fill the cell
  69: #$Info.Range("B:B").FormatConditions.Add($xlCellValue,$xlEqual,'="Y"')
  70: #$Info.Range("B:B").FormatConditions.Item(1).Interior.Color = 5296274
  71:  
  72: $Info.Range("B:B").FormatConditions.Add($xlIconSet)
  73: $Info.Range("B:B").FormatConditions.AddIconSetCondition
  74: $Info.Range("B:B").FormatConditions.Item(1).ShowIconOnly = $true
  75: $Info.Range("B:B").FormatConditions.Item(1).IconSet = $Excel.ActiveWorkbook.IconSets.Item($xl3Symbols)
  76: $Info.Range("B:B").FormatConditions.Item(1).IconCriteria.Item(2).Value = 0
  77: $Info.Range("B:B").FormatConditions.Item(1).IconCriteria.Item(2).Operator = 5
  78: $Info.Range("B:B").FormatConditions.Item(1).IconCriteria.Item(3).Value = 1
  79: $Info.Range("B:B").FormatConditions.Item(1).IconCriteria.Item(3).Operator = 7
  80:  
  81:  
  82:  
  83:  
I have included MSDN links in the code to the Excel enumerations used to write this script.
All that is left to do is to schedule it and save it somewhere accessible to the Support Center staff. Another todo from a VM scripting perspective is figure out a way to get the custom fields. Leave me a comment if you have already figured that one out!

Enjoy!!

Saturday, January 10, 2009

PowerShell & MBSA logs

Was recently asked if I could iterate over a directory containing *.MBSA files from a scheduled run of the Microsoft Baseline Security Analyzer. These *.MBSA files are XML files that contain some basic machine information as well as the number of security and service packs that are required to get the machine to a secure state. The GUI shows the information as follows: The specifics of the request that I received were to grab the count of the following updates per machine (circled in the picture above):
  • SDK Components Security Updates
  • SQL Server Security Updates
  • Windows Security Updates
  • BizTalk Server Security Updates
  • Exchange Security Updates
  • Office Security Updates

What a great opportunity to use PowerShell's XML capabilities! The following script iterates over each file in the directory, parses the file and looks for the count. This information is dynamically entered into an Excel spreadsheet.

  1. # grab our XML files   
  2. $files = Get-ChildItem -path 'C:\SecurityScans'    
  3.   
  4. # Get Excel ready   
  5. $Excel = New-Object -comobject Excel.Application   
  6. $Excel.visible = $True    
  7. $Workbook = $Excel.Workbooks.Add()   
  8. $Info = $Workbook.Worksheets.Item(1)   
  9.   
  10. # Create our column headers   
  11. $Info.Cells.Item(1,1) = "Server name"  
  12. $Info.Cells.Item(1,2) = "SDK Components Security Updates"  
  13. $Info.Cells.Item(1,3) = "SQL Server Security Updates"  
  14. $Info.Cells.Item(1,4) = "Windows Security Updates"  
  15. $Info.Cells.Item(1,5) = "BizTalk Server Security Updates"  
  16. $Info.Cells.Item(1,6) = "Exchange Security Updates"  
  17. $Info.Cells.Item(1,7) = "Office Security Updates"  
  18.   
  19. # Add a little formatting   
  20. $Style = $Info.UsedRange   
  21. $Style.Interior.ColorIndex = 19   
  22. $Style.Font.ColorIndex = 11   
  23. $Style.Font.Bold = $True  
  24.   
  25. $intRow = 2   
  26.   
  27. # iterate over each .mbsa file   
  28. foreach ($file in $files)   
  29. {   
  30.     [XML]$ScanResult = Get-Content $file  
  31.     $Scanned = $ScanResult.SecScan.Check | select Name, Advice   
  32.     $Server = $ScanResult.SecScan.Machine   
  33.     foreach($Scan in $Scanned)   
  34.     {   
  35.         # if Advice doesn't start with a numeric value then set it equal to 0   
  36.         if( $Scan.Advice -match '^(?<Cnt>[0-9]*)'){$Advice=$matches.cnt}    else{$Advice=0}   
  37.            
  38.         $Style.Cells.Item($intRow, 1) = $Server  
  39.            
  40.         switch ($Scan.Name)    
  41.         {   
  42.             "SDK Components Security Updates"   {$Style.Cells.Item($intRow, 2) = $Advice;break}   
  43.             "SQL Server Security Updates"       {$Style.Cells.Item($intRow, 3) = $Advice;break}   
  44.             "Windows Security Updates"          {$Style.Cells.Item($intRow, 4) = $Advice;break}   
  45.             "BizTalk Server Security Updates"   {$Style.Cells.Item($intRow, 5) = $Advice;break}   
  46.             "Exchange Security Updates"         {$Style.Cells.Item($intRow, 6) = $Advice;break}   
  47.             "Office Security Updates"           {$Style.Cells.Item($intRow, 7) = $Advice;break}   
  48.         }   
  49.   
  50.     }   
  51.     $intRow = $intRow + 1   
  52. }  

The result is a nicely formatted Excel spreadsheet that has the total number of updates.

This script hopefully demonstrates a how to use few different PowerShell features:

  • Creating a COM object
  • Using Regular Expressions
  • Using [XML] type

Enjoy