PoshCode Logo PowerShell Code Repository

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