PoshCode Logo PowerShell Code Repository

VMware Daily Report by alanrenouf 31 months ago (modification of post by alanrenouf view diff)
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1213"></script>download | new post

For more information and sample out put please visit http://www.virtu-al.net/2009/07/14/powercli-daily-report/

  1. # vCheck - Daily Error Report
  2. #
  3. # Changes:
  4. # Version 1.12 - Added Hosts in Maintenance Mode and not responding + Bug Fixes
  5. # Version 1.11 - Simplified mail function.
  6. # Version 1.10 - Added How many days old the snapshots are
  7. # Version 1.9 - Added ability to change user account which makes the WMI calls
  8. # Version 1.8 - Added Real name resolution via AD and sorted disk space by PerfFree
  9. # Version 1.7 - Added Event Logs for VMware warnings and errors for past day
  10. # Version 1.6 - Add details to service state to see if it is expected or not
  11. # Version 1.5 - Check for objects to see if they exist before sending the email + add VMs with No VMTools
  12. param( [string] $VISRV)
  13.  
  14. # You can change the following defaults by altering the below settings:
  15. #
  16. # Set the SMTP Server address
  17. $SMTPSRV = "myexchangeserver.mydomain.comk"
  18. #
  19. # Set the Email address to recieve from
  20. $EmailFrom = "reports@mydomain.com"
  21. #
  22. # Set the Email address to send the email to
  23. $EmailTo = "myemail@mydomain.com"
  24.  
  25. #### Detail Settings ####
  26. # Set the username of the account with permissions to access the VI Server
  27. # for event logs and service details - you will be asked for the same username and password
  28. # only the first time this runs after setting the below username.
  29. # If it is left blank it will use the credentials of the user who runs the script
  30. $SetUsername = ""
  31. # Set the location to store the credentials in a secure manner
  32. $CredFile = ".\mycred.crd"
  33. # Set the warning threshold for Datastore % Free Space
  34. $DatastoreSpace = "5"
  35. # Set the warning threshold for snapshots in days old
  36. $SnapshotAge = 14
  37. # Set the number of days to show VMs created & removed for
  38. $VMsNewRemovedAge = 5
  39. # Set the number of days of VC Events to check for errors
  40. $VCEventAge = 1
  41. # Set tge bumber of days of VC Event Logs to check for warnings and errors
  42. $VCEvntlgAge = 1
  43.  
  44.  
  45. #######################################
  46. # Start of script
  47. if ($VISRV -eq ""){
  48.         Write-Host
  49.         Write-Host "Please specify a VI Server name eg...."
  50.         Write-Host "      powershell.exe DailyReport.ps1 MYVISERVER"
  51.         Write-Host
  52.         Write-Host
  53.         exit
  54. }
  55.  
  56. function Send-SMTPmail($to, $from, $subject, $smtpserver, $body) {
  57.         $mailer = new-object Net.Mail.SMTPclient($smtpserver)
  58.         $msg = new-object Net.Mail.MailMessage($from,$to,$subject,$body)
  59.         $msg.IsBodyHTML = $true
  60.         $mailer.send($msg)
  61. }
  62.  
  63. Function Get-CustomHTML ($Header){
  64. $Report = @"
  65. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
  66. <html><head><title>$($Header)</title>
  67. <META http-equiv=Content-Type content='text/html; charset=windows-1252'>
  68.  
  69. <meta name="save" content="history">
  70.  
  71. <style type="text/css">
  72. DIV .expando {DISPLAY: block; FONT-WEIGHT: normal; FONT-SIZE: 10pt; RIGHT: 8px; COLOR: #ffffff; FONT-FAMILY: Tahoma; POSITION: absolute; TEXT-DECORATION: underline}
  73. TABLE {TABLE-LAYOUT: fixed; FONT-SIZE: 100%; WIDTH: 100%}
  74. *{margin:0}
  75. .dspcont { BORDER-RIGHT: #bbbbbb 1px solid; BORDER-TOP: #bbbbbb 1px solid; PADDING-LEFT: 16px; FONT-SIZE: 8pt;MARGIN-BOTTOM: -1px; PADDING-BOTTOM: 5px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; WIDTH: 95%; COLOR: #000000; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; BACKGROUND-COLOR: #f9f9f9}
  76. .filler {BORDER-RIGHT: medium none; BORDER-TOP: medium none; DISPLAY: block; BACKGROUND: none transparent scroll repeat 0% 0%; MARGIN-BOTTOM: -1px; FONT: 100%/8px Tahoma; MARGIN-LEFT: 43px; BORDER-LEFT: medium none; COLOR: #ffffff; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: medium none; POSITION: relative}
  77. .save{behavior:url(#default#savehistory);}
  78. .dspcont1{ display:none}
  79. a.dsphead0 {BORDER-RIGHT: #bbbbbb 1px solid; PADDING-RIGHT: 5em; BORDER-TOP: #bbbbbb 1px solid; DISPLAY: block; PADDING-LEFT: 5px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; MARGIN-BOTTOM: -1px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; CURSOR: hand; COLOR: #FFFFFF; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; HEIGHT: 2.25em; WIDTH: 95%; BACKGROUND-COLOR: #cc0000}
  80. a.dsphead1 {BORDER-RIGHT: #bbbbbb 1px solid; PADDING-RIGHT: 5em; BORDER-TOP: #bbbbbb 1px solid; DISPLAY: block; PADDING-LEFT: 5px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; MARGIN-BOTTOM: -1px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; CURSOR: hand; COLOR: #ffffff; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; HEIGHT: 2.25em; WIDTH: 95%; BACKGROUND-COLOR: #7BA7C7}
  81. a.dsphead2 {BORDER-RIGHT: #bbbbbb 1px solid; PADDING-RIGHT: 5em; BORDER-TOP: #bbbbbb 1px solid; DISPLAY: block; PADDING-LEFT: 5px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; MARGIN-BOTTOM: -1px; MARGIN-LEFT: 0px; BORDER-LEFT: #bbbbbb 1px solid; CURSOR: hand; COLOR: #ffffff; MARGIN-RIGHT: 0px; PADDING-TOP: 4px; BORDER-BOTTOM: #bbbbbb 1px solid; FONT-FAMILY: Tahoma; POSITION: relative; HEIGHT: 2.25em; WIDTH: 95%; BACKGROUND-COLOR: #A5A5A5}
  82. a.dsphead1 span.dspchar{font-family:monospace;font-weight:normal;}
  83. td {VERTICAL-ALIGN: TOP; FONT-FAMILY: Tahoma}
  84. th {VERTICAL-ALIGN: TOP; COLOR: #cc0000; TEXT-ALIGN: left}
  85. BODY {margin-left: 4pt}
  86. BODY {margin-right: 4pt}
  87. BODY {margin-top: 6pt}
  88. </style>
  89. </head>
  90. <body>
  91. <b><font face="Arial" size="5">$($Header)</font></b><hr size="8" color="#cc0000">
  92. <font face="Arial" size="1"><b>Generated on $($ENV:Computername)</b></font><br>
  93. <font face="Arial" size="1">Report created on $(Get-Date)</font>
  94. <div class="filler"></div>
  95. <div class="filler"></div>
  96. <div class="filler"></div>
  97. <div class="save">
  98. "@
  99. Return $Report
  100. }
  101.  
  102. Function Get-CustomHeader0 ($Title){
  103. $Report = @"
  104.                 <h1><a class="dsphead0">$($Title)</a></h1>
  105.         <div class="filler"></div>
  106. "@
  107. Return $Report
  108. }
  109.  
  110. Function Get-CustomHeader ($Num, $Title){
  111. $Report = @"
  112.         <h2><a class="dsphead$($Num)">
  113.         $($Title)</a></h2>
  114.         <div class="dspcont">
  115. "@
  116. Return $Report
  117. }
  118.  
  119. Function Get-CustomHeaderClose{
  120.  
  121.         $Report = @"
  122.                 </DIV>
  123.                 <div class="filler"></div>
  124. "@
  125. Return $Report
  126. }
  127.  
  128. Function Get-CustomHeader0Close{
  129.  
  130.         $Report = @"
  131. </DIV>
  132. "@
  133. Return $Report
  134. }
  135.  
  136. Function Get-CustomHTMLClose{
  137.  
  138.         $Report = @"
  139. </div>
  140.  
  141. </body>
  142. </html>
  143. "@
  144. Return $Report
  145. }
  146.  
  147. Function Get-HTMLTable {
  148.         param([array]$Content)
  149.         $HTMLTable = $Content | ConvertTo-Html
  150.         $HTMLTable = $HTMLTable -replace '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', ""
  151.         $HTMLTable = $HTMLTable -replace '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"  "http://www.w3.org/TR/html4/strict.dtd">', ""
  152.         $HTMLTable = $HTMLTable -replace '<html xmlns="http://www.w3.org/1999/xhtml">', ""
  153.         $HTMLTable = $HTMLTable -replace '<html>', ""
  154.         $HTMLTable = $HTMLTable -replace '<head>', ""
  155.         $HTMLTable = $HTMLTable -replace '<title>HTML TABLE</title>', ""
  156.         $HTMLTable = $HTMLTable -replace '</head><body>', ""
  157.         $HTMLTable = $HTMLTable -replace '</body></html>', ""
  158.         Return $HTMLTable
  159. }
  160.  
  161. Function Get-HTMLDetail ($Heading, $Detail){
  162. $Report = @"
  163. <TABLE>
  164.         <tr>
  165.         <th width='25%'><b>$Heading</b></font></th>
  166.         <td width='75%'>$($Detail)</td>
  167.         </tr>
  168. </TABLE>
  169. "@
  170. Return $Report
  171. }
  172.  
  173. function Find-Username ($username){
  174.         if ($username -ne $null)
  175.         {
  176.                 $root = [ADSI]""
  177.                 $filter = ("(&(objectCategory=user)(samAccountName=$Username))")
  178.                 $ds = new-object  system.DirectoryServices.DirectorySearcher($root,$filter)
  179.                 $ds.PageSize = 1000
  180.                 $ds.FindOne()
  181.         }
  182. }
  183.  
  184. function Get-VIServices
  185. {
  186.         If ($SetUsername -ne ""){
  187.                 $Services = get-wmiobject win32_service -Credential $creds -ComputerName $VISRV | Where {$_.DisplayName -like "VMware*" }
  188.         } Else {
  189.                 $Services = get-wmiobject win32_service -ComputerName $VISRV | Where {$_.DisplayName -like "VMware*" }
  190.         }
  191.        
  192.         $myCol = @()
  193.  
  194.         Foreach ($service in $Services){
  195.                 $MyDetails = "" | select-Object Name, State, StartMode, Health
  196.                 If ($service.StartMode -eq "Auto")
  197.                 {
  198.                         if ($service.State -eq "Stopped")
  199.                         {
  200.                                 $MyDetails.Name = $service.Displayname
  201.                                 $MyDetails.State = $service.State
  202.                                 $MyDetails.StartMode = $service.StartMode
  203.                                 $MyDetails.Health = "Unexpected State"
  204.                         }
  205.                 }
  206.                 If ($service.StartMode -eq "Auto")
  207.                 {
  208.                         if ($service.State -eq "Running")
  209.                         {
  210.                                 $MyDetails.Name = $service.Displayname
  211.                                 $MyDetails.State = $service.State
  212.                                 $MyDetails.StartMode = $service.StartMode
  213.                                 $MyDetails.Health = "OK"
  214.                         }
  215.                 }
  216.                 If ($service.StartMode -eq "Disabled")
  217.                 {
  218.                         If ($service.State -eq "Running")
  219.                         {
  220.                                 $MyDetails.Name = $service.Displayname
  221.                                 $MyDetails.State = $service.State
  222.                                 $MyDetails.StartMode = $service.StartMode
  223.                                 $MyDetails.Health = "Unexpected State"
  224.                         }
  225.                 }
  226.                 If ($service.StartMode -eq "Disabled")
  227.                 {
  228.                         if ($service.State -eq "Stopped")
  229.                         {
  230.                                 $MyDetails.Name = $service.Displayname
  231.                                 $MyDetails.State = $service.State
  232.                                 $MyDetails.StartMode = $service.StartMode
  233.                                 $MyDetails.Health = "OK"
  234.                         }
  235.                 }
  236.                 $myCol += $MyDetails
  237.         }
  238.         Write-Output $myCol
  239. }
  240.  
  241. function Get-DatastoreSummary {
  242.         param(
  243.                 $InputObject = $null
  244.         )
  245.         begin {
  246.         }
  247.         process {
  248.                 if ($InputObject -and $_) {
  249.                         throw 'The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.'
  250.                         return
  251.                 }
  252.                 $processObject = $(if ($InputObject) {$InputObject} else {$_})
  253.                 if ($processObject) {
  254.                         $myCol = @()
  255.                         foreach ($ds in $_)
  256.                         {
  257.                                 $MyDetails = "" | select-Object Name, Type, CapacityMB, FreeSpaceMB, PercFreeSpace
  258.                                 $MyDetails.Name = $ds.Name
  259.                                 $MyDetails.Type = $ds.Type
  260.                                 $MyDetails.CapacityMB = $ds.CapacityMB
  261.                                 $MyDetails.FreeSpaceMB = $ds.FreeSpaceMB
  262.                                 $MyDetails.PercFreeSpace = [math]::Round(((100 * ($ds.FreeSpaceMB)) / ($ds.CapacityMB)),0)
  263.                                 $myCol += $MyDetails
  264.                         }
  265.                         $myCol | Where { $_.PercFreeSpace -lt $DatastoreSpace }
  266.                 }
  267.         }
  268.         end {
  269.         }
  270. }
  271.  
  272. function Get-SnapshotSummary {
  273.         param(
  274.                 $InputObject = $null
  275.         )
  276.  
  277.         BEGIN {
  278.         }
  279.  
  280.         PROCESS {
  281.                 if ($InputObject -and $_) {
  282.                         throw 'ParameterBinderStrings\AmbiguousParameterSet'
  283.                         break
  284.                 } elseif ($InputObject) {
  285.                         $InputObject
  286.                 } elseif ($_) {
  287.                        
  288.                         $mySnaps = @()
  289.                         foreach ($snap in $_){
  290.                                 $SnapshotInfo = Get-SnapshotExtra $snap
  291.                                 $mySnaps += $SnapshotInfo
  292.                         }
  293.  
  294.                         $mySnaps | Select VM, Name, @{N="DaysOld";E={((Get-Date) - $_.Created).Days}}, @{N="Creator";E={(Find-Username (($_.Creator.split("\"))[1])).Properties.displayname}}, Created, Description -ErrorAction SilentlyContinue | Sort DaysOld
  295.  
  296.                 } else {
  297.                         throw 'ParameterBinderStrings\InputObjectNotBound'
  298.                 }
  299.         }
  300.  
  301.         END {
  302.         }
  303. }
  304.  
  305. function Get-SnapshotTree{
  306.         param($tree, $target)
  307.        
  308.         $found = $null
  309.         foreach($elem in $tree){
  310.                 if($elem.Snapshot.Value -eq $target.Value){
  311.                         $found = $elem
  312.                         continue
  313.                 }
  314.         }
  315.         if($found -eq $null -and $elem.ChildSnapshotList -ne $null){
  316.                 $found = Get-SnapshotTree $elem.ChildSnapshotList $target
  317.         }
  318.        
  319.         return $found
  320. }
  321.  
  322. function Get-SnapshotExtra ($snap){
  323.         $guestName = $snap.VM   # The name of the guest
  324.         $tasknumber = 999               # Windowsize of the Task collector
  325.         $taskMgr = Get-View TaskManager
  326.        
  327.         # Create hash table. Each entry is a create snapshot task
  328.         $report = @{}
  329.        
  330.         $filter = New-Object VMware.Vim.TaskFilterSpec
  331.         $filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime
  332.         $filter.Time.beginTime = (($snap.Created).AddDays(-5))
  333.         $filter.Time.timeType = "startedTime"
  334.        
  335.         $collectionImpl = Get-View ($taskMgr.CreateCollectorForTasks($filter))
  336.        
  337.         $dummy = $collectionImpl.RewindCollector
  338.         $collection = $collectionImpl.ReadNextTasks($tasknumber)
  339.         while($collection -ne $null){
  340.                 $collection | where {$_.DescriptionId -eq "VirtualMachine.createSnapshot" -and $_.State -eq "success" -and $_.EntityName -eq $guestName} | %{
  341.                         $row = New-Object PsObject
  342.                         $row | Add-Member -MemberType NoteProperty -Name User -Value $_.Reason.UserName
  343.                         $vm = Get-View $_.Entity
  344.                         if($vm -ne $null){
  345.                                 $snapshot = Get-SnapshotTree $vm.Snapshot.RootSnapshotList $_.Result
  346.                                 if($snapshot -ne $null){
  347.                                         $key = $_.EntityName + "&" + ($snapshot.CreateTime.ToString())
  348.                                         $report[$key] = $row
  349.                                 }
  350.                         }
  351.                 }
  352.                 $collection = $collectionImpl.ReadNextTasks($tasknumber)
  353.         }
  354.         $collectionImpl.DestroyCollector()
  355.        
  356.         # Get the guest's snapshots and add the user
  357.         $snapshotsExtra = $snap | % {
  358.                 $key = $_.vm.Name + "&" + ($_.Created.ToString())
  359.                 if($report.ContainsKey($key)){
  360.                         $_ | Add-Member -MemberType NoteProperty -Name Creator -Value $report[$key].User
  361.                 }
  362.                 $_
  363.         }
  364.         $snapshotsExtra
  365. }
  366.  
  367. Function Set-Cred ($File) {
  368.         $Credential = Get-Credential
  369.         $credential.Password | ConvertFrom-SecureString | Set-Content $File
  370. }
  371.  
  372. Function Get-Cred ($User,$File) {
  373.         $password = Get-Content $File | ConvertTo-SecureString
  374.         $credential = New-Object System.Management.Automation.PsCredential($user,$password)
  375.         $credential
  376. }
  377.  
  378. If ($SetUsername -ne ""){
  379.         if ((Test-Path -Path $CredFile) -eq $false) {
  380.                 Set-Cred $CredFile
  381.         }
  382.         $creds = Get-Cred $SetUsername $CredFile
  383. }
  384.  
  385. $VIServer = Connect-VIServer $VISRV
  386. If ($VIServer.IsConnected -ne $true){
  387.         # Fix for scheduled tasks not running.
  388.         $USER = $env:username
  389.         $APPPATH = "C:\Documents and Settings\" + $USER + "\Application Data"
  390.  
  391.         #SET THE APPDATA ENVIRONMENT WHEN NEEDED
  392.         if ($env:appdata -eq $null -or $env:appdata -eq 0)
  393.         {
  394.                 $env:appdata = $APPPATH
  395.         }
  396.         $VIServer = Connect-VIServer $VISRV
  397.         If ($VIServer.IsConnected -ne $true){
  398.                 send-SMTPmail -to $EmailTo -from $EmailFrom -subject "ERROR: $VISRV Daily Report" -smtpserver $SMTPSRV -body "The Connect-VISERVER Cmdlet did not work, please check you VI Server."
  399.                 exit
  400.         }
  401.        
  402. }
  403.  
  404.  
  405. $VM = Get-VM
  406. $VMH = Get-VMHost
  407. $Clusters = Get-Cluster
  408. $Datastores = Get-Datastore
  409. $FullVM = Get-View -ViewType VirtualMachine
  410.  
  411. $MyReport = Get-CustomHTML "$VIServer Daily Report"
  412.         $MyReport += Get-CustomHeader0 ($VIServer.Name)
  413.                
  414.                 # ---- General Summary Info ----
  415.                 $MyReport += Get-CustomHeader "1" "General Details"
  416.                         $MyReport += Get-HTMLDetail "Number of Hosts:" (($VMH).Count)
  417.                         $MyReport += Get-HTMLDetail "Number of VMs:" (($VM).Count)
  418.                         $MyReport += Get-HTMLDetail "Number of Clusters:" (($Clusters).Count)
  419.                         $MyReport += Get-HTMLDetail "Number of Datastores:" (($Datastores).Count)
  420.                 $MyReport += Get-CustomHeaderClose
  421.                
  422.                 # ---- Snapshot Information ----
  423.                 $Snapshots = $VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-$SnapshotAge))} | Get-SnapshotSummary
  424.                 If (($Snapshots | Measure-Object).count -gt 0) {
  425.                         $MyReport += Get-CustomHeader "1" "Snapshots (Over $SnapshotAge Days Old)"
  426.                                 $MyReport += Get-HTMLTable $Snapshots
  427.                         $MyReport += Get-CustomHeaderClose
  428.                 }
  429.                                
  430.                 # ---- Datastore Information ----
  431.                 $OutputDatastores = $Datastores | Get-DatastoreSummary | Sort PercFreeSpace
  432.                 If (($OutputDatastores | Measure-Object).count -gt 0) {
  433.                         $MyReport += Get-CustomHeader "1" "Datastores (Less than $DatastoreSpace% Free)"
  434.                                 $MyReport += Get-HTMLTable $OutputDatastores
  435.                         $MyReport += Get-CustomHeaderClose
  436.                 }
  437.                
  438.                 # ---- Hosts in Maintenance Mode ----
  439.                 $MaintHosts = $VMH | where {$_.State -match "Maintenance"} | Select name,CustomFields
  440.                 If (($MaintHosts | Measure-Object).count -gt 0) {
  441.                         $MyReport += Get-CustomHeader "1" "Hosts in Maintenance Mode"
  442.                                 $MyReport += Get-HTMLTable $MaintHosts
  443.                         $MyReport += Get-CustomHeaderClose
  444.                 }
  445.                
  446.                 # ---- Hosts Not responding ----
  447.                 $RespondHosts = $VMH | where {$_.State -match "Not"} | Select name,CustomFields
  448.                 If (($RespondHosts | Measure-Object).count -gt 0) {
  449.                         $MyReport += Get-CustomHeader "1" "Hosts not responding"
  450.                                 $MyReport += Get-HTMLTable $RespondHosts
  451.                         $MyReport += Get-CustomHeaderClose
  452.                 }
  453.                
  454.                 # ---- VMs created or Cloned ----
  455.                 $VIEvent = Get-VIEvent -maxsamples 10000 -Start (Get-Date).AddDays(-$VMsNewRemovedAge)
  456.                 $OutputCreatedVMs = $VIEvent | where {$_.Gettype().Name -eq "VmCreatedEvent" -or $_.Gettype().Name -eq "VmBeingClonedEvent" -or $_.Gettype().Name -eq "VmBeingDeployedEvent"} | Select createdTime, @{N="User";E={(Find-Username (($_.userName.split("\"))[1])).Properties.displayname}}, fullFormattedMessage
  457.                 If (($OutputCreatedVMs | Measure-Object).count -gt 0) {
  458.                         $MyReport += Get-CustomHeader "1" "VMs Created or Cloned (Last $VMsNewRemovedAge Day(s))"
  459.                                 $MyReport += Get-HTMLTable $OutputCreatedVMs
  460.                         $MyReport += Get-CustomHeaderClose
  461.                 }
  462.                
  463.                 # ---- VMs Removed ----
  464.                 $OutputRemovedVMs = $VIEvent | where {$_.Gettype().Name -eq "VmRemovedEvent"}| Select createdTime, @{N="User";E={(Find-Username (($_.userName.split("\"))[1])).Properties.displayname}}, fullFormattedMessage
  465.                 If (($OutputRemovedVMs | Measure-Object).count -gt 0) {
  466.                         $MyReport += Get-CustomHeader "1" "VMs Removed (Last $VMsNewRemovedAge Day(s))"
  467.                                 $MyReport += Get-HTMLTable $OutputRemovedVMs
  468.                         $MyReport += Get-CustomHeaderClose
  469.                 }
  470.                
  471.                 # ---- VC Errors ----
  472.                 $OutputErrors = Get-VIEvent -maxsamples 10000 -Start (Get-Date).AddDays(-$VCEventAge ) -Type Error | Select createdTime, @{N="User";E={(Find-Username (($_.userName.split("\"))[1])).Properties.displayname}}, fullFormattedMessage
  473.                 If (($OutputErrors | Measure-Object).count -gt 0) {
  474.                         $MyReport += Get-CustomHeader "1" "Error Events (Last $VCEventAge Day(s))"
  475.                                 $MyReport += Get-HTMLTable $OutputErrors
  476.                         $MyReport += Get-CustomHeaderClose     
  477.                 }
  478.                
  479.                 # ---- No VM Tools ----
  480.                 $NoTools = $FullVM | Where { $_.Runtime.PowerState -eq "poweredOn" } | Select Name, @{N="ToolsVersion"; E={$_.Config.tools.toolsVersion}} | Where { $_.ToolsVersion -eq 0} | Select Name
  481.                 If (($NoTools | Measure-Object).count -gt 0) {
  482.                         $MyReport += Get-CustomHeader "1" "No VMTools"
  483.                                 $MyReport += Get-HTMLTable $NoTools
  484.                         $MyReport += Get-CustomHeaderClose
  485.                 }
  486.                
  487.                 # ---- CD-Roms Connected ----
  488.                 $CDConn = $VM | Where { $_ | Get-CDDrive | Where { $_.ConnectionState.Connected -eq "true" } } | Select Name, Host
  489.                 If (($CDConn | Measure-Object).count -gt 0) {
  490.                         $MyReport += Get-CustomHeader "1" "VM: CD-ROM Connected - VMotion Violation"
  491.                                 $MyReport += Get-HTMLTable $CDConn
  492.                         $MyReport += Get-CustomHeaderClose
  493.                 }
  494.                
  495.                 # ---- Floppys Connected ----
  496.                 $Floppy = $VM | Where { $_ |  Get-FloppyDrive | Where { $_.ConnectionState.Connected -eq "true" } } | Select Name, Host
  497.                 If (($Floppy | Measure-Object).count -gt 0) {
  498.                         $MyReport += Get-CustomHeader "1" "VM:Floppy Drive Connected - VMotion Violation"
  499.                                 $MyReport += Get-HTMLTable $Floppy
  500.                         $MyReport += Get-CustomHeaderClose
  501.                 }
  502.                
  503.                 # ---- Virtual Center Details ----
  504.                 $MyReport += Get-CustomHeader "1" "$VIServer Service Details"
  505.                         $MyReport += Get-HTMLTable (Get-VIServices)
  506.                 $MyReport += Get-CustomHeaderClose
  507.                
  508.                 # ---- Virtual Center Event Logs - Error ----
  509.                 $ConvDate = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime([DateTime]::Now.AddDays(-$VCEvntlgAge))
  510.                 If ($SetUsername -ne ""){
  511.                         $ErrLogs = Get-WmiObject -Credential $creds -computer $VIServer -query ("Select * from Win32_NTLogEvent Where Type='Error' and TimeWritten >='" + $ConvDate + "'") | Where {$_.Message -like "*VMware*"} | Select @{N="TimeGenerated";E={$_.ConvertToDateTime($_.TimeGenerated)}}, Message
  512.                 } Else {
  513.                         $ErrLogs = Get-WmiObject -computer $VIServer -query ("Select * from Win32_NTLogEvent Where Type='Error' and TimeWritten >='" + $ConvDate + "'") | Where {$_.Message -like "*VMware*"} | Select @{N="TimeGenerated";E={$_.ConvertToDateTime($_.TimeGenerated)}}, Message
  514.                 }
  515.                
  516.                 If (($ErrLogs | Measure-Object).count -gt 0) {
  517.                         $MyReport += Get-CustomHeader "1" "$VIServer Event Logs: Error"
  518.                                 $MyReport += Get-HTMLTable ($ErrLogs)
  519.                         $MyReport += Get-CustomHeaderClose
  520.                 }
  521.                
  522.                 # ---- Virtual Center Event Logs - Warning ----
  523.                 $ConvDate = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime([DateTime]::Now.AddDays(-1))
  524.                 If ($SetUsername -ne ""){
  525.                         $WarnLogs = Get-WmiObject -Credential $creds -computer $VIServer -query ("Select * from Win32_NTLogEvent Where Type='Warning' and TimeWritten >='" + $ConvDate + "'") | Where {$_.Message -like "*VMware*"} | Select @{N="TimeGenerated";E={$_.ConvertToDateTime($_.TimeGenerated)}}, Message
  526.                 } Else {
  527.                         $WarnLogs = Get-WmiObject -computer $VIServer -query ("Select * from Win32_NTLogEvent Where Type='Warning' and TimeWritten >='" + $ConvDate + "'") | Where {$_.Message -like "*VMware*"} | Select @{N="TimeGenerated";E={$_.ConvertToDateTime($_.TimeGenerated)}}, Message
  528.                 }
  529.                 If (($WarnLogs | Measure-Object).count -gt 0) {
  530.                         $MyReport += Get-CustomHeader "1" "$VIServer Event Logs: Warning"
  531.                                 $MyReport += Get-HTMLTable ($WarnLogs)
  532.                         $MyReport += Get-CustomHeaderClose
  533.                 }
  534.                        
  535.         $MyReport += Get-CustomHeader0Close
  536. $MyReport += Get-CustomHTMLClose
  537.  
  538. #Uncomment the following lines to save the htm file in a central location
  539. #$Date = Get-Date
  540. #$Filename = "C:\Temp\" + $VIServer + "DailyReport" + "_" + $Date.Day + "-" + $Date.Month + "-" + $Date.Year + ".htm"
  541. #$MyReport | out-file -encoding ASCII -filepath $Filename
  542. #Invoke-Item $Filename
  543.  
  544. send-SMTPmail $EmailTo $EmailFrom "$VISRV Daily Report" $SMTPSRV $MyReport
  545.  
  546. $VIServer | Disconnect-VIServer -Confirm:$false

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me