Advertisement
stephanlinke

Untitled

Dec 5th, 2016
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #requires -version 4.0
  2. # ___ ___ _____ ___
  3. #| _ \ _ \_   _/ __|
  4. #|  _/   / | || (_ |
  5. #|_| |_|_\ |_| \___|
  6. # SCVMM & HyperV-VM Sensors
  7. # ================================
  8. # This sensor will monitor HyperV hosts and their virtual machines using SCVMM.
  9. # It also supports metascan (https://kb.paessler.com/en/topic/68109), so you don't have
  10. # to do all the configuration work. Note that this will only work in an upcoming stable release
  11. #
  12. # Version History
  13. # ----------------------------
  14. # 1.4        [Added]   Support for Remote Probes
  15. # 1.3        [Changed] Switched to HTTP Push Sensor based system. No device templates needed, better for large environments.
  16. #            [Notes  ] It's an simple EXE/Script sensor now, no longer EXE/Script Advanced.
  17. #                      Device templates are no longer needed, as the sensor automatically creates new sensors for new hosts and VMs with each run
  18. #                      With every run, we only run Get-VMHost and Get-VM once on the SCVMM host, receiving all objects at once, not once for every VM
  19. #                      A GUID file is maintained for every SCVMM host that will prevent sensor duplicates
  20. #                      Performance wise, it should be way easier and faster. Three VMs and one host take 2s to scan.
  21. #                      Better, more verbose script output to see what the script actually does, receives and evaluates.
  22. # 1.2        [Changed] Updated device template, changed naming template of VM sensors
  23. # 1.13       [Fixed] Paramter was wrongly passed to Get-VMHost and Get-VM
  24. # 1.12       [Fixed] Values weren't retrieved correctly when multiple VMs were present.
  25. # 1.1        [Fixed] Values weren't retrieved correctly due to lookup bug
  26. # 1.0        Initial Release
  27. #
  28. # Credits
  29. # ----------------------------
  30. # RICHARD GARNER, computerservicecentre.com
  31. # For going through countless tests and bugfixing with me. And improvement ideas - Thanks! :)
  32. # # # # # # # # # # # # # # # # # # # # # # # # # #
  33.  
  34. <#
  35.    .SYNOPSIS
  36.    This sensor will monitor HyperV hosts and their virtual machines using SCVMM.
  37.    .DESCRIPTION
  38.    Installation:
  39.    1. Save the script as PRTG-SCVMM-HyperV.ps1 under <PRTG Application folder>\Custom Sensors\EXE\
  40.    2. Open up your SCVMM device in PRTG
  41.    3. Add a new HTTP Push Data (Advanced) sensor to the device, name it any way you like (e.g. "Template Sensor"), and pause it. Note it's sensor ID
  42.    4. Create a new EXE/Script sensor and select the PRTG-SCVMM-HyperV.ps1 script
  43.    5. Set the timeout to 900 seconds
  44.    6. Enter the following parameters:
  45.  
  46.    -prtgHostName <your prtg url, e.g. http://prtg.acme.com or https://prtg.acme.com>
  47.    -prtgPushPort <the push port you're using in the template sensor
  48.    -prtgProbeAddress <the address of the remote probe the sensor resides on (if so)>
  49.    -prtgUserName <a user with read/write permissions to the device, or a PRTG administrator>
  50.    -prtgPasshash <the passhash of the above user>
  51.    -prtgTemplateSensor <the ID (not token) of the HTTP Push sensor>
  52.    -prtgScvmmDeviceID %deviceid
  53.    -ComputerName %host
  54.    -Userdomain %windowsdomain
  55.    -Username %windowsuser
  56.    -Password %windowspassword
  57.  
  58.    When you enter the data in the script directly, you can also test it on the fly. Initially, it will look like the attached screenshot #1, consequential runs will look like #2.
  59.    Note that the sensors may not have data directly after the first run. This is due to the startup of the sensors taking some time and the script may push values prior to that.
  60.    .PARAMETER prtgHostName
  61.    The URL of your PRTG webinterface, e.g. http://prtg.acme.com or https://prtg.acme.com
  62.    .PARAMETER prtgPort
  63.    The port used by your PRTG webinterface, e.g. 80 or 443
  64.    .PARAMETER prtgPushPort
  65.    The push port you configured in the template HTTP Push Advanced sensor
  66.    .PARAMETER prtgProbeAddress
  67.    If your SCVMM is monitored by a remote probe, enter it's address here,  e.g. http://prtgprobe.acme.com
  68.    .PARAMETER prtgUserName
  69.    A user with read/write permissions to the device, or a PRTG administrator
  70.    .PARAMETER prtgPassHash
  71.    The passhash of the above user
  72.    .PARAMETER prtgScvmmDeviceId
  73.    This is the ID of the device that resembles your SCVMM server - use %deviceid
  74.    .PARAMETER prtgTemplateSensor
  75.    This is the ID of the HTTP Push Data (Advanced) template sensor (not the sensor token, but the PRTG ID)
  76.    .PARAMETER ComputerName
  77.    Your SCVMM host - use %host here.
  78.    .PARAMETER Userdomain
  79.    The domain of the user that will be used for remote powershell access - use %windowsdomain
  80.    .PARAMETER Username
  81.    The username of the user that will be used for remote powershell access - use %windowsuser
  82.    .PARAMETER Password
  83.    The password of the user that will be used for remote powershell access - use %windowspassword
  84.    .PARAMETER verbose
  85.    When this is set, the script will output debug messages. This can always be enabled as it doesn't bother PRTG.
  86.    .EXAMPLE
  87.    C:\PS> .\Get-Events.ps1  -ComputerName %host -Username "%windowsdomain\%windowsuser" -Password "%windowspassword" -ProviderName "Microsoft-Windows-Immersive-Shell" -Channel "Microsoft-Windows-TWinUI/Operational" -LimitEntries 1 -MaxAge 1 -EventID 1719 -Level 4
  88. #>
  89.  
  90.  
  91. param(
  92.        [string]$prtgHostName      = "",
  93.        [string]$prtgProbeAddress  = "",
  94.        [string]$prtgPort          = 80,
  95.        [int]$prtgPushPort         = 5050,
  96.        [string]$prtgUserName      = '',
  97.        [string]$prtgPasshash      = 0,
  98.        [int]$prtgScvmmDeviceId    = 0,
  99.        [int]$prtgTemplateSensor   = 0,
  100.        [string]$computername      = "",
  101.        [string]$userdomain        = "",
  102.        [string]$username          = "",
  103.        [string]$password          = "",
  104.        [switch]$verbose           = $true
  105. )
  106.  
  107. $global:counter   = 0;
  108. $scriptPath       = "C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXE";
  109. $guidFile         = [string]::Format("{0}\{1}-guidfile.dat",$scriptPath,$computername);
  110.  
  111. $global:webclient = New-Object System.Net.WebClient;
  112.  
  113.  
  114. # this will output debug messages to the console
  115. function Console-ShowMessage([string]$type,$message){
  116.     if($verbose){
  117.         Write-Host ("[{0}] " -f (Get-Date)) -NoNewline;
  118.         switch ($type){
  119.             "success"       { Write-Host "    success    "  -BackgroundColor Green      -ForegroundColor White -NoNewline; }
  120.             "information"   { Write-Host "  information  "  -BackgroundColor DarkCyan   -ForegroundColor White -NoNewline; }
  121.             "warning"       { Write-Host "    warning    "  -BackgroundColor DarkYellow -ForegroundColor White -NoNewline; }
  122.             "error"         { Write-Host "     error     "  -BackgroundColor DarkRed    -ForegroundColor White -NoNewline; }
  123.             default         { Write-Host "     notes     "  -BackgroundColor DarkGray   -ForegroundColor White -NoNewline; }
  124.         }
  125.         Write-Host (" {0}{1}" -f $message,$Global:blank)
  126.     }
  127. }
  128.  
  129. # if the guid files don't exist, create them
  130. if(!(Test-Path $guidFile))  { New-Item -ItemType File -Path $guidFile | Out-Null; Console-ShowMessage -type "information" -message "created GUID file: $($guidFile)"; }
  131.  
  132. Console-ShowMessage "information" "GUID file path: $($guidFile)";
  133.  
  134. $Stopwatch = [system.diagnostics.stopwatch]::new()
  135.  
  136. #region  xml item
  137. $channel = @"
  138. <result>
  139.       <channel>{0}</channel>
  140.       <value>{1}</value>{2}
  141.       <showChart>{3}</showChart>
  142.       {4}
  143.       {5}
  144.       {6}
  145.   </result>
  146. "@
  147. #endregion
  148.  
  149. #region Function Library
  150.  
  151.  
  152. # this will return a value only if it's an integer
  153. function This-Numeric ($Value) {
  154.     return $Value -match "^[\d\.]+$"
  155. }
  156.  
  157. # Since we need lookup files to show this properly, we'll have to convert
  158. # the states received to integers
  159. function This-StateConvert([string]$Type, [string]$CurrentStatus){
  160.  
  161.  # replacement tables
  162.  [hashtable]$States = @{
  163.         "OverallStatesUnknown"              = -1
  164.         "OverallStatesAdding "              = 1
  165.         "OverallStatesNotResponding"        = 2
  166.         "OverallStatesReassociating"        = 3
  167.         "OverallStatesRemoving"             = 4
  168.         "OverallStatesUpdating"             = 5
  169.         "OverallStatesPending"              = 6
  170.         "OverallStatesMaintenanceMode"      = 7
  171.         "OverallStatesNeedsAttention"       = 8
  172.         "OverallStateOk"                    = 9
  173.         "OverallStatesLimited"              = 10
  174.         "CommunicationStateUnknown"         = -1
  175.         "CommunicationStateResponding"      = 0
  176.         "CommunicationStateNotResponding"   = 1
  177.         "CommunicationStateAccessDenied "   = 2
  178.         "CommunicationStateConnecting"      = 3
  179.         "CommunicationStateDisconnecting"   = 4
  180.         "CommunicationStateResetting"       = 5
  181.         "CommunicationStateNoConnection"    = 6
  182.         "ComputerStateUnknown"              = -1
  183.         "ComputerStateAdding"               = 0
  184.         "ComputerStateRemoving"             = 1
  185.         "ComputerStateResponding"           = 2
  186.         "ComputerStateNotResponding"        = 3
  187.         "ComputerStateAccessDenied"         = 4
  188.         "ComputerStateUpdating"             = 5
  189.         "ComputerStateReassociating"        = 6
  190.         "ComputerStatePending"              = 7
  191.         "ComputerStateMaintenanceMode"      = 8
  192.         "ClusterNodeStatusUnknown"          = 0
  193.         "ClusterNodeStatusRunning"          = 1
  194.         "ClusterNodeStatusStopped"          = 2
  195.         "ClusterNodeStatusNoCluster"        = 3
  196.         "VirtualServerStateUnknown"         = 0
  197.         "VirtualServerStateRunning"         = 1
  198.         "VirtualServerStateStopped"         = 2
  199.         "VMStateUnknown"                    = -1
  200.         "VMStateRunning"                            = 0
  201.         "VMStatePowerOff"                   = 1
  202.         "VMStatePoweringOff"                = 2
  203.         "VMStateSaved"                      = 3
  204.         "VMStateSaving"                     = 4
  205.         "VMStateRestoring"                  = 5
  206.         "VMStatePaused"                     = 6
  207.         "VMStateDiscardSavedState"          = 10
  208.         "VMStateStarting"                   = 11
  209.         "VMStateMergingDrives"              = 12
  210.         "VMStateDeleting"                   = 13
  211.         "VMStateDiscardingDrives"           = 80
  212.         "VMStatePausing"                    = 81
  213.         "VMStateUnderCreation"              = 100
  214.         "VMStateCreationFailed"             = 101
  215.         "VMStateStored"                     = 102
  216.         "VMStateUnderTemplateCreation"      = 103
  217.         "VMStateTemplateCreationFailed"     = 104
  218.         "VMStateCustomizationFailed"        = 105
  219.         "VMStateUnderUpdate"                = 106
  220.         "VMStateUpdateFailed"               = 107
  221.         "VMStateUnderMigration"             = 200
  222.         "VMStateMigrationFailed"            = 201
  223.         "VMStateCreatingCheckpoint"         = 210
  224.         "VMStateDeletingCheckpoint"         = 211
  225.         "VMStateRecoveringCheckpoint"       = 212
  226.         "VMStateCheckpointFailed"           = 213
  227.         "VMStateInitializingCheckpointOperation" = 214
  228.         "VMStateFinishingCheckpointOperation"    = 215
  229.         "VMStateMissing"                    = 220
  230.         "VMStateHostNotResponding"          = 221
  231.         "VMStateUnsupported"                = 222
  232.         "VMStateIncompleteVMConfig"         = 223
  233.         "VMStateUnsupportedSharedFiles"     = 224
  234.         "VMStateUnsupportedCluster"         = 225
  235.         "VMStateP2VCreationFailed"          = 240
  236.         "VMStateV2VCreationFailed"          = 250
  237.     }
  238.  return $states[$Type+$CurrentStatus]
  239. }
  240.  
  241. # This will turn the metrics received from the SCVMM into PRTG channels,
  242. # with their corresponding channel settings.
  243. function This-PrtgXmlWrapper($Metrics){
  244.  
  245.     $cleanMetrics = $Metrics;
  246.  
  247.        foreach ($metric in $cleanMetrics.GetEnumerator() | sort -Property Name)
  248.        {
  249.  
  250.        $Lookup = "";
  251.        $Volume = "";
  252.  
  253.        #region Metric Properties Replacement
  254.             # get the unit of the item
  255.             If($metric.Value[1] -ne 0)
  256.             { $Unit   = [string]::Format("<unit>{0}</unit>", $metric.Value[1])}
  257.             else
  258.             { $Unit   = "<unit>Count</unit>" }
  259.  
  260.             # get the value lookup of the item
  261.             If($metric.Value[2] -ne 0)
  262.             { $Lookup = [string]::Format("<ValueLookup>{0}</ValueLookup>",$metric.Value[2]); }
  263.  
  264.             # should the metric show up in the graph?
  265.             If($metric.Value[3] -eq 0)
  266.             { $showChart = 0 }
  267.             else
  268.             { $showChart = 1; }
  269.  
  270.             # can the item fire a change trigger?
  271.             if($metric.Value[4] -ne 0)
  272.             { $notifyChanged = "<NotifyChanged></NotifyChanged>" }
  273.             else
  274.             { $notifyChanged = "" }
  275.  
  276.             if($metric.value[5])
  277.             { $Volume = "<VolumeSize>$($metric.value[5])</VolumeSize>" }
  278.  
  279.         #endregion
  280.         # replace the state strings with their corresponding IDs
  281.         if(!(This-Numeric $metric.Value[0]))
  282.         { $metric.Value[0] = (This-StateConvert -Type $metric.Name -CurrentStatus $metric.Value[0]) }
  283.  
  284.         $channels += [string]::Format($channel,$metric.Name, $metric.Value[0], $Unit,$showChart,$notifyChanged,$Lookup,$Volume)
  285.  
  286.        }
  287.        return $channels;
  288.  
  289. }
  290.  
  291. # If there's an error, only this will be outputted
  292. function This-PrtgError($Message){
  293.  
  294.     if(!($verbose)){
  295.         Write-Host "<?xml version='1.0' encoding='UTF-8' ?><prtg>"
  296.         Write-Host ([string]::Format("<error>1</error><text>{0}</text>",$Message));
  297.         Write-Host "</prtg>";
  298.     exit 0;
  299.     }
  300. }
  301.  
  302. # We need to ignore $null values, this will cleanse the metrics accordingly
  303. function This-ResultSanitize($Metrics){
  304.  
  305.     $CleanMetric = @{};
  306.  
  307.     foreach ($metric in $Metrics.GetEnumerator() | sort -Property Name)
  308.     { if($metric.Value[0] -ne $null) {$CleanMetric.Add($metric.key,$metric.value)} }
  309.  
  310.     return $CleanMetric;
  311.  
  312. }
  313.  
  314. # @Output: PSCredentialObject
  315. #
  316. # This function will generate a PowerShell Credential object for the
  317. # given username, password and domainname
  318. function This-GenerateCredential(){
  319.  
  320.     try{
  321.     # Generate credentials object for authentication
  322.     $SecPasswd   = ConvertTo-SecureString $password -AsPlainText -Force
  323.     $Credentials = New-Object System.Management.Automation.PSCredential ([string]::Format("{0}\{1}",$userdomain,$username), $secpasswd)
  324.  
  325.     return $Credentials;
  326.     }
  327.     catch{
  328.  
  329.         catch{ This-PrtgError -Message "Couldn't connect to the server or execute the given commands. Please check if WinRM is enabled and allowed." }
  330.     }
  331.  
  332. }
  333.  
  334. # @Output: Update HTTP Push (Advanced) sensors
  335. function This-UpdateHTTPPushSensors {
  336.      param([string]$type, [pscustomobject[]]$objects)
  337.  
  338.      $counter    = 0;
  339.  
  340.     # first load the GUID list to check the GUIDs against
  341.      $guidList = ( Get-Content $guidFile );
  342.  
  343.  
  344.      # add sensors that are not in our list as a HTTP Push Content sensor
  345.      foreach($object in $objects){
  346.         if(!($guidList -match $object.id))
  347.         {
  348.             if(This-AddHTTPPushSensors -sensorName $object.name -Token $object.id)
  349.             {
  350.                 Console-ShowMessage -type "success" -message "Sensor for $($object.name) created successfully.";
  351.                 # append the GUID to the file so we don't add duplicates in future scans
  352.                 $object | Select "ID" | ft -HideTableHeaders | Out-File -FilePath $guidFile -Append
  353.                 $counter++;
  354.                 $global:counter++;
  355.             }
  356.             else
  357.             {
  358.               Console-ShowMessage -type "error" -message "Could not create sensor for $($object.name).";
  359.             }
  360.         }
  361.         else
  362.         { Console-ShowMessage -type "information" -message "$($object.name) with ID $($object.id) is already existing as a sensor."; }
  363.      }
  364.      Console-ShowMessage -type "information" -message "$($counter) new $($type) have been added to PRTG.";
  365. }
  366.  
  367. # @Output: Create HTTP Push (Advanced) sensors
  368. #
  369. # This function will generate the PRTG Metascan Items for the VMs in XML format
  370. function This-AddHTTPPushSensors {
  371.      param([string]$sensorName, [guid]$token)
  372.  
  373.      try{
  374.          Console-ShowMessage "information" "Starting sensor creation for $($sensorName) (GUID: $($token))";
  375.  
  376.          # create the URL for duplicating the original sensor
  377.          $url = [string]::Format("{0}:{1}/api/duplicateobject.htm?id={2}&name={3}&targetid={4}&username={5}&passhash={6}",
  378.                           $prtgHostName, $prtgPort, $prtgTemplateSensor, $sensorName, $prtgScvmmDeviceId, $prtgUserName, $prtgPasshash);
  379.  
  380.          # call the URL and store the content, we need the actual ID of the new sensor to change the settings and unpause it
  381.          $request = [System.Net.WebRequest]::Create($url);
  382.          $request.AllowAutoRedirect = $false
  383.          $response=$request.GetResponse();
  384.  
  385.  
  386.          If ($response.StatusCode -eq "Redirect")
  387.          {
  388.  
  389.             $response.GetResponseHeader("Location") -match '\d{3,}' | Out-Null;
  390.             $newSensorID = $Matches[0];
  391.             Console-ShowMessage -type "success" -message "Sensor created successfully. New sensor ID: $($newSensorID)";
  392.          }
  393.          Else
  394.          { Console-ShowMessage "error" "Sensor creation failed. PRTG returned: $($response.StatusCode)"; }
  395.  
  396.          # modify the token to resemble the GUID of the device
  397.          $url = [string]::Format("{0}:{1}/api/setobjectproperty.htm?id={2}&name={3}&value={4}&username={5}&passhash={6}",
  398.                          $prtgHostName, $prtgPort, $newSensorID, "httppushtoken", $token, $prtgUserName, $prtgPasshash);
  399.  
  400.          $UpdateSensorResult = (Invoke-WebRequest $url)
  401.  
  402.          if($UpdateSensorResult.StatusCode -eq "200")
  403.          { Console-ShowMessage -type "success" -message "Changed sensor token to GUID of the host/vm."; }
  404.  
  405.          # start the sensors
  406.          $url = [string]::Format("{0}:{1}/api/pause.htm?id={2}&action=1&username={3}&passhash={4}",
  407.                          $prtgHostName, $prtgPort, $newSensorID, $prtgUserName, $prtgPasshash);
  408.  
  409.          $StartSensorResult = (Invoke-WebRequest $url)
  410.  
  411.          if($StartSensorResult.StatusCode -eq "200")
  412.          { Console-ShowMessage -type "success" -message "Sensor has been started succesfully."; }
  413.  
  414.          return $true
  415.      }
  416.      catch{ return $false; }
  417. }
  418.  
  419. # @Output: PowerShell Object Array with all hosts
  420. #
  421. # This function will retrieve all VM hosts available
  422. function This-GetHostsAndVms() {
  423.     Console-ShowMessage -type "information" -message "Retrieving HyperV hosts and VMs...";
  424.     try{
  425.     $objects = (Invoke-Command -ComputerName $computername -ScriptBlock {
  426.  
  427.             # load the correct snapins:
  428.             if ((new-object 'version' (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft System Center Virtual Machine Manager Server\Setup" ProductVersion | select -expandproperty productversion)) -ge (new-object 'Version' 3,0)) { Import-Module ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft System Center Virtual Machine Manager Server\Setup" InstallPath | select -ExpandProperty InstallPath) + "bin\psModules\virtualmachinemanager") } else { Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager }
  429.             if ((new-object 'version' (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft System Center Virtual Machine Manager Server\Setup" ProductVersion | select -expandproperty productversion)) -ge (new-object 'Version' 6,2)) { Get-SCVMMServer localhost | Out-Null } else { Get-VMMServer localhost | Out-Null }
  430.  
  431.             $hosts = (Get-VMHost);
  432.             $vms   = (Get-VM);
  433.  
  434.             # The cmdlets above give back a single object or an array of objects.
  435.             # For the sake of simplicity, let's convert them, so they're always arrays
  436.             if($hostList -isnot [system.array])
  437.             { $hostList = @($hosts) }
  438.             if($vmList -isnot [system.array])
  439.             { $vmList = @($vms) }
  440.  
  441.  
  442.             $objects = @($hostList,$vmList)
  443.  
  444.             return $objects;
  445.         } -Credential (This-GenerateCredential)
  446.     )
  447.     return $objects;
  448.     }
  449.     catch{
  450.     Console-ShowMessage -type "error" -message "Couldn't connect to the server or execute the given commands. Please check if WinRM is enabled and allowed.";
  451.     This-PrtgError -Message "Couldn't connect to the server or execute the given commands. Please check if WinRM is enabled and allowed."
  452.     }
  453.  
  454. }
  455.  
  456. # @Param token: the GUID of the VM/host
  457. # @Param data:  the channels of the VM/host
  458. function This-PushData([string]$token, [string]$data){
  459.  
  460.         $pushData = ([string]::Format("<prtg>{0}</prtg>",$data)).replace("`n"," ").Replace(" ",'%20');
  461.              if($prtgProbeAddress.Length -ne 0)
  462.              { $url = [string]::Format("{0}:{1}/{2}?content={3}",($prtgProbeAddress -replace "https","http"),$prtgPushPort,$token,$pushData); }
  463.              else
  464.              { $url = [string]::Format("{0}:{1}/{2}?content={3}",($prtgHostName -replace "https","http"),$prtgPushPort,$token,$pushData); }
  465.  
  466.         try   {
  467.  
  468.             Invoke-WebRequest $url -Method Get | Out-Null
  469.             Console-ShowMessage -type "success" -message "Data for host with ID $($token) pushed to corresponding sensor.";
  470.         }
  471.         catch {
  472.             Console-ShowMessage -type "error" -message "Couldn't push the data to the configured PRTG server using the specified token ($($token)).";
  473.             This-PrtgError -Message "Couldn't push the data to the configured PRTG server using the specified token ($($token))."
  474.         }
  475. }
  476.  
  477. function This-GetSCVMMObjects(){
  478.  
  479.     # lets retrieve hosts and vms first
  480.     $Objects = (This-GetHostsAndVms)
  481.  
  482.     # ... and seperate them
  483.     $VMHosts   = $objects[0];
  484.     $VMs       = $objects[1];
  485.  
  486.     Console-ShowMessage -type "success" -message "$($VMHosts.count) HyperV hosts have been found.";
  487.     Console-ShowMessage -type "success" -message "$($VMs.count) Virtual Machines have been found.";
  488.  
  489.     # let's add the sensor first, before we do anything
  490.     This-UpdateHTTPPushSensors -objects $VMHosts -type "HyperV Hosts"
  491.     This-UpdateHTTPPushSensors -objects $VMs     -type "Virtual Machines"
  492.  
  493.     # we have to wait for the sensors to become active.
  494.     if($global:counter -gt 0){
  495.     Console-ShowMessage -type "information" "Waiting for new push sensors to become active"
  496.     Start-Sleep 10;
  497.     }
  498.  
  499.     # now that the sensors are there, let's push the values to them
  500.     foreach($VMHost in $VMHosts){
  501.  
  502.           $metrics = @{
  503.                     "OverallState"         = @($VMHost.OverallState,"Custom","prtg.standardlookups.hyperv.hoststatus",1,"<NotifyChanged>");
  504.                     "CommunicationState"   = @($VMHost.CommunicationState,"Custom","prtg.standardlookups.hyperv.communicationstate");
  505.                     "CpuUtilization"       = @($VMHost.CpuUtilization,"CPU",0,1,1,0);
  506.                     "TotalMemory"          = @($VMHost.TotalMemory,"BytesMemory",0,1,0,"Kilobyte");
  507.                     "AvailableMemory"      = @(($VMHost.AvailableMemory * 1024 * 1024),"BytesMemory",0,1,0,"MegaByte");
  508.                     "ClusterNodeStatus"    = @($VMHost.ClusterNodeStatus,"Custom","prtg.standardlookups.hyperv.clusternodestatus");
  509.                     "VirtualServerState"   = @($VMHost.VirtualServerState,"Custom","prtg.standardlookups.hyperv.virtualserverstate");
  510.                     "ComputerState"        = @($VMHost.ComputerState,"Custom","prtg.standardlookups.hyperv.computerstate");
  511.                     "HostCluster"          = @($VMHost.HostCluster,"Custom","prtg.standardlookups.hyperv.clusternodestatus"); }
  512.  
  513.          # first, we'll format the data and sanatize the metrics
  514.          $channels = (This-PrtgXmlWrapper -Metrics $metrics);
  515.  
  516.          # ...then we'll push it to PRTG. Don't forget to join the array!
  517.          This-PushData -token $VMHost.id -data $channels;
  518.     }
  519.  
  520.     # The same thing again, but for the VMs
  521.     foreach($VM in $VMs){
  522.  
  523.         $metrics = @{
  524.                     "VMState"            = @($VM.Status,"Custom","prtg.standardlookups.hyperv.vmstatus",0,"<NotifyChanged>");
  525.                     "CPU Usage"          = @($VM.PerfCPUUtilization,"Percent",0,0,0,0);
  526.                     "PerfDiskBytesRead"  = @($VM.PerfDiskBytesRead,"BytesDisk",0,0,0,0);
  527.                     "PerfDiskBytesWrite" = @($VM.PerfDiskBytesWrite,"BytesDisk",0,0,0,0); }
  528.  
  529.  
  530.  
  531.         # first, we'll format the data and sanatize the metrics ...
  532.         $channels = (This-PrtgXmlWrapper -Metrics $metrics);
  533.  
  534.         # ...then we'll push it to PRTG.
  535.         This-PushData -token $VM.id -data $channels;
  536.     }
  537.  
  538.  
  539. }
  540. #
  541.  
  542. This-GetSCVMMObjects;
  543.  
  544. $objects = (((gc $guidFile) | ? {$_.trim() -ne "" } | Measure-Object).Count)
  545.  
  546. write-host ([string]::Format("{0}:Monitoring {1} objects and added {0} objects.",$global:counter,$objects));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement