ESXi Host Patching with PowerShell & Update Manager

Update Manager certainly makes host patching simple, but leaves a few things to be desired. How many times have you attempted to update a host in Update Manager only to have the host never enter maintenance mode because of a DRS rule, VMware tools installation or local ISO mapped to a VM? I wanted to find a way to check for all these things as I’m performing the patching process and be able to accomplish it at the cluster level.

For the script itself I have broken it down into the different sections along with screenshots of what you’ll see when running the script. It makes it a little busy to follow along with for this entry, but hopefully it makes sense. At the bottom of the page I have the whole script put together to make it easier to copy and run it on your own.

Let’s dig into the script.

1. While you can manually define the vCenter server in the script, I prefer being prompted as I have multiple vCenter servers that I work with. The multiple lines and color emphasis was for a customer that would forget to enter the vCenter name and instead enter the ESXi host name.

Write-Host "Enter the FQDN of the " -NoNewline
Write-Host "[vCenter Server]" -ForegroundColor Red -NoNewline
Write-Host " to connect to: " -NoNewline
$vCenterFqdn = Read-Host
Connect-viserver $vCenterFqdn

2. Here we’re going to list all the clusters. I use this menu system all the time now in my PowerShell scripts to make it easier to make selections instead of having to remember and manually enter the name of an object. This is getting all the clusters then converting the number selection that’s entered into the cluster name.

$global:i=0
Get-Cluster | Sort Name | Select @{Name="Number";Expression={$global:i++;$global:i}},Name -OutVariable menu | format-table -AutoSize
$clusterNum = Read-Host "Select the number of the Cluster to be patched"
$clusterName = $menu | where {$_.Number -eq $clusterNum}


3. Now that we have the cluster we’re going to work with we search for DRS rules. Specifically, we’re looking for “Must Run” rules. This will prevent a VM from moving to another host. While every environment is different and they have “must run” rules for a variety of reasons, I’m comfortable disabling this during patch events. If there are any rules we’re going to list the rule names in the PowerShell console and give you the option to disable or not.

a. Remember, this is only looking at “Must Run” DRS rules for the entire cluster, not for an individual host. If you’re patching, odds are you’ll be doing the entire cluster anyway so I didn’t break this down on a host-by-host basis.

$drsRules = Get-Cluster $($clusterName.Name) | Get-DrsVMHostRule | Where {$_.Type -eq "MustRunOn"} | Where {$_.Enabled -eq $True}
IF ($drsRules.Count -gt "0"){Write-Host "The following rules may prevent a host from entering Maintenance mode:" -foreground "Yellow"; $drsRules.Name; $disableRules = Read-Host "Press Y to disable these rules. Anything else to continue";
IF ($disableRules -eq "Y"){Write-Host "Disabling DRS Rules..." -foreground "Yellow";
foreach ($name in $drsRules){Set-DrsVMHostRule -rule $name -enabled:$false}} ELSE {Write-Host "Skipping disabling of DRS Rules. Continuing..." -foreground "Yellow"}} ELSE {Write-Host "No "Must Run" Rules in $($clusterName.Name). Continuing..." -foreground "Yellow"}

In the picture I have the name of the DRS rule highlighted (the VM name was in the rule so it’s been obscured).


4. Now that we’ve decided what to do with our DRS rules, we can get down to selecting the baseline. This script can be used for both patching and for Upgrades. There is a check later on in the script that will skip the “Staging” step and go right to remediation if it’s an upgrade. Once again, we’re using that menu selection function to display all upgrades/baselines and let us choose the one to use.

$global:i=0
Get-Baseline | Select Name | Sort Name | Select @{Name="Number";Expression={$global:i++;$global:i}},Name -OutVariable menu | format-table -AutoSize
$baselineNum = Read-Host "Select the number of the Baseline to be attached"
$baselineName = $menu | where {$_.Number -eq $baselineNum}
Write-Host "Attaching $($baselineName.Name) Baseline to $($clusterName.Name)..." -Foreground "Yellow"
$baseline = Get-Baseline $baselineName.Name
Attach-Baseline -Baseline $baseline -Entity $clusterName.Name


5. Here’s where we’re going to complicate things a bit. I have 2 loops in this script. Loop number 1 is for checking if a host has any patches available. We’ll check a selected host against the attached baseline, if there are no available updates/upgrades then we report that in the PowerShell console and return to the host selection screen. The second loop is when a selected host has been patched we return to the host selection screen to choose the next one in the list.

DO
{
DO
{

6. Now that we’ve opened up our loop, we can start with selecting a host in the cluster. Once again, menu selection, this time we’re getting all the hosts in the chosen cluster and we’re displaying the host name, build, esxi version, and state. This makes it easier to know what hosts have been patched, which ones are still left, and what hosts are already in maintenance mode. In a larger environment you may forget what host name you were working on so seeing if a host was in maintenance mode and ready to be upgrade may be beneficial.

$global:i=0
Get-Cluster $clusterName.Name | Get-VMhost | Sort Name | Select @{Name="Number";Expression={$global:i++;$global:i}},Name,Build,Version,State -OutVariable menu | format-table -AutoSize
$hostNum = Read-Host "Select the number of the Host to be patched"
$hostName = $menu | where {$_.Number -eq $hostNum}


7. With our first host chosen we’re going to scan its inventory to see what patches it currently has installed.

Write-Host "Scanning $($hostName.Name) patch inventory..." -foreground "Yellow"
Scan-Inventory -Entity $hostName.Name


8. Now that we’ve scanned it, we’re going to check it for compliance. If there are patches available, we’ll move on to the next step to see if there are any VMs with ISO or Vmware tools installations. If there aren’t any patches, we’re reporting that and then sending us back to the host selection screen.

a. As a note, the second ‘}’ after the “Write-Host ‘Host is out of date” command is to close the second loop from step 5.

Write-Host "Scanning $($hostName.Name) for patch compliance..." -foreground "Yellow"
$compliance = Get-Compliance $hostName.Name
IF ($compliance.Status -eq "Compliant"){Write-Host "No available patches for $($hostName.Name). Choose a different host" -foreground "Red"}ELSE{Write-Host "Host is out of date" -foreground "Yellow"}}
UNTIL ($compliance.Status -ne "Compliant")


9. Now that we have some patches to apply, we check for active VMware tools installations. We perform the lookup for VMs with tools installer mounted then we perform a count on that output. If there are more than 0, we list all the VMs. Now that you see all the VMs, you can press ‘Y’ to force the unmount and continue or you can ignore it and hope the VMs move.

a. The unmount command works most of the time, but on some Linux OS’s I’ve run into issues with it. Just keep that in mind

$vmtools = Get-VMHost $hostName.Name | Get-VM | Where {$_.ExtensionData.RunTime.ToolsInstallerMounted -eq "True"} | Get-View
IF ($vmtools.Count -gt "0"){Write-Host "The following VMs on $($hostName.Name) have VMTools Installer Mounted:";
$vmtools.Name;
$unmountTools = Read-Host "Press "Y" to unmount VMTools and continue. Anything else to skip VMTools unmounting";
IF ($unmountTools -eq "Y") {Write-Host "Unmounting VMTools on VMs..." -foreground "Yellow"; foreach ($vm in $vmtools) {$vm.UnmountToolsInstaller()}}ELSE{Write-Host "Skipping VMTools unmounting..." -foreground "Yellow"}}ELSE{Write-Host "No VMs found with VMTools Installer mounted. Continuing..." -foreground "Yellow"}


10. With all our VMware tools installations killed, we move on to ISOs. ISO’s that are stored in shared datastores won’t have an issue moving, but if ISOs have been mounted directly to a VM through a console window those can cause a hang up. Again, you know your environment better than me so use your best judgement when picking what to do.

$mountedCDdrives = Get-VMHost $hostName.Name | Get-VM | Where { $_ | Get-CdDrive | Where { $_.ConnectionState.Connected -eq "True" } }
IF ($mountedCDdrives.Count -gt "0"){Write-Host "The following VMs on $($hostName.Name) have mounted CD Drives:";
$mountedCDdrives.Name;
$unmountDrives = Read-Host "Press "Y" to unmount these ISOs and continue. Anything else to skip ISO unmounting";
IF ($unmountDrives -eq "Y") {Write-Host "Unmounting ISOs on VMs..." -foreground "Yellow"; foreach ($vm in $mountedCDdrives) {Get-VM $vm | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$False}}ELSE{Write-Host "Skipping ISO unmounting..." -foreground "Yellow"}}ELSE{Write-Host "No VMs found with ISOs mounted. Continuing..." -foreground "Yellow"}


11. Now we check if the host is in maintenance mode. This check isn’t required and we could just try to put a host in maintenance mode that’s already in maintenance mode without any errors, I just prefer to have this called out so people know that the host will be placed in maintenance mode. Also, if you don’t want to confirm and just want the host to automatically go into maintenance mode, you can remove the “Read-Host “Press Enter to place $($hostName.Name in Maintenance mode”;” section and it will automatically place the host in maintenance mode.

$hostState = Get-VMHost $hostname.Name
IF ($hostState.State -eq "Maintenance"){Write-Host "$($hostName.Name) is already in maintenance mode. Continuing to patch Staging/Remediation" -foreground "Yellow"}ELSE{Read-Host "Press Enter to place $($hostName.Name) in Maintenance mode"; Start-Sleep 7; Write-Host "Enabling Maintenance mode for $($hostName.Name). This may take a while..." -foreground "Yellow"; Set-VMHost $hostName.Name -State "Maintenance"}


12. This was an interesting issue I ran into. I had a customer running ESXi 6.0 with PernixData installed which wasn’t compatible with ESXi 6.5 which we were upgrading to. When we attempted to upgrade we’d fail because the PernixData VIB was present. I threw this check in to see if this VIB existed on their hosts and to remove it before proceeding. I also added a second placeholder VIB name in case you have multiple VIBs to remove you can just replace the name with the appropriate VIB name and even add additional VIBs with another -OR $_.ID -eq “vibname”

$esxcli = Get-esxcli -vmhost $hostName.Name
$vibCheck = $esxcli.software.vib.list() | Where {($_.ID -eq "PernixData_bootbank_pernixcore-vSphere6.0.0_3.5.0.2-39793" -OR $_.ID -eq "Other_vib_name_xxxxxx")}
IF ($vibCheck.Count -gt "0"){Write-Host "Incompatible VIB found. Removing from host..." -foreground "Yellow"; foreach ($a in $vibCheck){$esxcli.software.vib.remove($null, $true, $false, $true, $a.Name)}}ELSE{Write-Host "No known incompatible VIBs found. Continuing..." -foreground "Green"}


13. And, of course, if removing a VIB we need to reboot so now we throw this reboot check in there as well. If there were no VIBs found in Step 12, this will be ignored. Otherwise, we prompt for reboot, enter the reboot command, check for the host to enter the NotResponding state and report on the state until it responds in vCenter and returns to Maintenance state.

IF ($vibCheck.Count -gt "0" -AND $baseline.BaselineType -eq "Upgrade"){Read-Host "VIBs were removed from host. Press enter to reboot host before attempting upgrade";Restart-VMhost $hostName.Name -confirm:$false}ELSE{$skip = "1"; Write-Host ""}
IF ($skip -ne "1"){
Write-Host "$($hostName.Name) is going to reboot..." -foreground "Yellow"
do {
Start-Sleep 3
$hostState = (get-vmhost $hostName.Name).ConnectionState
}
while ($hostState -ne "NotResponding")
Write-Host "$($hostName.Name) is currently down..." -foreground "Yellow"

#Wait for server to reboot
do {
Start-Sleep 5
$hostState = (get-vmhost $hostName.Name).ConnectionState
Write-Host "Waiting for $($hostName.Name) to finish rebooting..." -foreground "Yellow"
}
while ($hostState -ne "Maintenance")
Write-Host "$($hostName.Name) is back up..." -foreground "Yellow"}ELSE{Write-Host ""}

14. Now that all that work is done, we can start staging patches. If this is a patch baseline we run stage command. If it’s an upgrade baseline, we’ll skip this step

IF ($baseline.BaselineType -eq "Upgrade"){Write-Host "$($baseline.Name) is an Upgrade Baseline. Skipping to remediation..." -foreground "Yellow"}ELSE{Write-Host "Staging patches to $($hostName.Name) in Cluster $($clusterName.Name)..." -foreground "Yellow"; Stage-Patch -entity $hostName.Name -baseline $baseline}


15. Once patches have been staged (or upgrades ready to push) it’s time for remediation. We prompt that the host will reboot on its own once the patch has completed and we set a few advanced options. These are the defaults, but can still be environment specific so check to make sure this is what you want to use.

Write-Host "Remediating patches on $($hostName.Name) in Cluster $($clusterName.Name). Host will reboot when complete" -foreground "Yellow"
Remediate-Inventory -Entity $hostName.Name -Baseline $baseline -HostFailureAction Retry -HostNumberofRetries 2 -HostRetryDelaySeconds 120 -HostDisableMediaDevices $true -ClusterDisableDistributedPowerManagement $true -ClusterDisableHighAvailability $true -confirm:$false -ErrorAction SilentlyContinue


At the top of our PowerShell window we get the percentage of completion for our task. It’s not very accurate as it stays at 30% then goes to 92% when it’s nearly complete.

16. Once the host has been rebooted and comes back online we want to see the current status of that host to ensure updates were successful. We are comparing the build number we grabbed before we started patching against the build number after the reboot. If they are the same, something didn’t work and we need to check into it. Otherwise, we do nothing.

Write-Host "Retrieving Host build status..." -foreground "Yellow"
$hostBuild = Get-VMHost $hostName.Name
IF ($hostBuild.Build -eq $hostState.Build){Write-Host "Patch/Upgrade was not applied. Check status in vCenter and re-run the script. Exiting..." -foreground "Red";$error;Start-Sleep 20;break}ELSE{}

17. Now that the host was patched, we show a list of all the hosts in that cluster along with their build, version, and state. This gives us a full view of the cluster so we can see if there are any hosts left to be patched and then we exit maintenance mode for this host.

Get-Cluster $clusterName.Name | Get-VMhost | Select Name,Build,Version,State | Sort Name | format-table -autosize
Write-Host "Exiting Maintenance mode for Host $($hostName.Name)..." -foreground "Yellow"
Get-VMHost $hostName.Name | Set-VMHost -State Connected


18. Based on that list will determine the answer to our next question. We are being prompted to re-enable the DRS rules we previously disabled (if any). If any rules were chosen to be disabled we captured that in a variable in step 3. We can choose to re-enable just those disabled rules by pressing ‘Y’ or if there are other hosts left to patch we just press any other key to continue.

IF ($disableRules -eq "Y") {$enableRules = Read-Host "If Cluster patching is complete press "Y" to re-enable DRS rules. Anything else to continue";
IF ($enableRules -eq "Y") {Write-Host "Re-enabling DRS Must Run rules" -foreground "Yellow"; 
foreach ($name in $drsRules){Set-DrsVMHostRule -rule $name -enabled:$true}} ELSE {
Write-Host "DRS Rules not being re-enabled. Continuing..." -foreground "Yellow"}} ELSE {}


19. In this last question we’re just displaying the output from our last host patched and prompting the user to quit patching or go back to step 6 and pick the next host in the cluster to patch.

$answer = Read-Host "$($hostname.Name) patched in Cluster $($clusterName.Name). Press "1" to re-run the script. Anything else to exit"


20. Finally, to close out the first loop, we have the following lines. In step 19 we have the variable $answer which asks the user to enter ‘1’ to re-run the script and pick another host. This line at the bottom is saying until the user enters something other than 1, keep performing that loop. If anything else is entered, the script exits. Answering “1” will start the script over from Step 6. We will perform another “Get-Cluster | Get-VMHost” on the chosen cluster and retrieve the current build and state information for each of the hosts and display the updated results. As you can see from the screenshot below, vmm-04 is no in a Connected state with a Build number of 9298722,

}
UNTIL ($answer -ne "1")


Below is the script all put together to copy and test. Like all scripts pulled from the internet, make sure you test them in a lab/isolated environment until you can ensure proper functionality.

Write-Host "Enter the FQDN of the " -NoNewline
Write-Host "[vCenter Server]" -ForegroundColor Red -NoNewline
Write-Host " to connect to: " -NoNewline
$vCenterFqdn = Read-Host
Connect-viserver $vCenterFqdn

$global:i=0
Get-Cluster | Sort Name | Select @{Name="Number";Expression={$global:i++;$global:i}},Name -OutVariable menu | format-table -AutoSize
$clusterNum = Read-Host "Select the number of the Cluster to be patched"
$clusterName = $menu | where {$_.Number -eq $clusterNum}

$drsRules = Get-Cluster $($clusterName.Name) | Get-DrsVMHostRule | Where {$_.Type -eq "MustRunOn"} | Where {$_.Enabled -eq $True}
IF ($drsRules.Count -gt "0"){Write-Host "The following rules may prevent a host from entering Maintenance mode:" -foreground "Yellow"; $drsRules.Name; $disableRules = Read-Host "Press Y to disable these rules. Anything else to continue";
IF ($disableRules -eq "Y"){Write-Host "Disabling DRS Rules..." -foreground "Yellow";
foreach ($name in $drsRules){Set-DrsVMHostRule -rule $name -enabled:$false}} ELSE {Write-Host "Skipping disabling of DRS Rules. Continuing..." -foreground "Yellow"}} ELSE {Write-Host "No "Must Run" Rules in $($clusterName.Name). Continuing..." -foreground "Yellow"}

$global:i=0
Get-Baseline | Select Name | Sort Name | Select @{Name="Number";Expression={$global:i++;$global:i}},Name -OutVariable menu | format-table -AutoSize
$baselineNum = Read-Host "Select the number of the Baseline to be attached"
$baselineName = $menu | where {$_.Number -eq $baselineNum}
Write-Host "Attaching $($baselineName.Name) Baseline to $($clusterName.Name)..." -Foreground "Yellow"
$baseline = Get-Baseline $baselineName.Name
Attach-Baseline -Baseline $baseline -Entity $clusterName.Name

DO
{
DO
{
$global:i=0
Get-Cluster $clusterName.Name | Get-VMhost | Sort Name | Select @{Name="Number";Expression={$global:i++;$global:i}},Name,Build,Version,State -OutVariable menu | format-table -AutoSize
$hostNum = Read-Host "Select the number of the Host to be patched"
$hostName = $menu | where {$_.Number -eq $hostNum}

Write-Host "Scanning $($hostName.Name) patch inventory..." -foreground "Yellow"
Scan-Inventory -Entity $hostName.Name

Write-Host "Scanning $($hostName.Name) for patch compliance..." -foreground "Yellow"
$compliance = Get-Compliance $hostName.Name 
IF ($compliance.Status -eq "Compliant"){Write-Host "No available patches for $($hostName.Name). Choose a different host" -foreground "Red"}ELSE{Write-Host "Host is out of date" -foreground "Yellow"}}
UNTIL ($compliance.Status -ne "Compliant")

$vmtools = Get-VMHost $hostName.Name | Get-VM | Where {$_.ExtensionData.RunTime.ToolsInstallerMounted -eq "True"} | Get-View
IF ($vmtools.Count -gt "0"){Write-Host "The following VMs on $($hostName.Name) have VMTools Installer Mounted:";
$vmtools.Name;
$unmountTools = Read-Host "Press "Y" to unmount VMTools and continue. Anything else to skip VMTools unmounting";
IF ($unmountTools -eq "Y") {Write-Host "Unmounting VMTools on VMs..." -foreground "Yellow"; foreach ($vm in $vmtools) {$vm.UnmountToolsInstaller()}}ELSE{Write-Host "Skipping VMTools unmounting..." -foreground "Yellow"}}ELSE{Write-Host "No VMs found with VMTools Installer mounted. Continuing..." -foreground "Yellow"}

$mountedCDdrives = Get-VMHost $hostName.Name | Get-VM | Where { $_ | Get-CdDrive | Where { $_.ConnectionState.Connected -eq "True" } }
IF ($mountedCDdrives.Count -gt "0"){Write-Host "The following VMs on $($hostName.Name) have mounted CD Drives:";
$mountedCDdrives.Name;
$unmountDrives = Read-Host "Press "Y" to unmount these ISOs and continue. Anything else to skip ISO unmounting";
IF ($unmountDrives -eq "Y") {Write-Host "Unmounting ISOs on VMs..." -foreground "Yellow"; foreach ($vm in $mountedCDdrives) {Get-VM $vm | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$False}}ELSE{Write-Host "Skipping ISO unmounting..." -foreground "Yellow"}}ELSE{Write-Host "No VMs found with ISOs mounted. Continuing..." -foreground "Yellow"}

$hostState = Get-VMHost $hostname.Name
IF ($hostState.State -eq "Maintenance"){Write-Host "$($hostName.Name) is already in maintenance mode. Continuing to patch Staging/Remediation" -foreground "Yellow"}ELSE{
#Read-Host "Press Enter to place $($hostName.Name) in Maintenance mode"; Start-Sleep 7; Write-Host "Enabling Maintenance mode for $($hostName.Name). This may take a while..." -foreground "Yellow"; Set-VMHost $hostName.Name -State "Maintenance"}
Write-Host "Enabling Maintenance mode for $($hostName.Name). This may take a while..." -foreground "Yellow"; ; Start-Sleep 7; Set-VMHost $hostName.Name -State "Maintenance"}

$esxcli = Get-esxcli -vmhost $hostName.Name
$vibCheck = $esxcli.software.vib.list() | Where {($_.ID -eq "PernixData_bootbank_pernixcore-vSphere6.0.0_3.5.0.2-39793" -OR $_.ID -eq "Other_vib_name_xxxxxx")}
IF ($vibCheck.Count -gt "0"){Write-Host "Incompatible VIB found. Removing from host..." -foreground "Yellow"; foreach ($a in $vibCheck){$esxcli.software.vib.remove($null, $true, $false, $true, $a.Name)}}ELSE{Write-Host "No known incompatible VIBs found. Continuing..." -foreground "Green"}

IF ($vibCheck.Count -gt "0" -AND $baseline.BaselineType -eq "Upgrade"){Read-Host "VIBs were removed from host. Press enter to reboot host before attempting upgrade";Restart-VMhost $hostName.Name -confirm:$false}ELSE{$skip = "1"; Write-Host ""}
IF ($skip -ne "1"){
Write-Host "$($hostName.Name) is going to reboot..." -foreground "Yellow"
do {
Start-Sleep 3
$hostState = (get-vmhost $hostName.Name).ConnectionState
}
while ($hostState -ne "NotResponding")
Write-Host "$($hostName.Name) is currently down..." -foreground "Yellow"

#Wait for server to reboot
do {
Start-Sleep 5
$hostState = (get-vmhost $hostName.Name).ConnectionState
Write-Host "Waiting for $($hostName.Name) to finish rebooting..." -foreground "Yellow"
}
while ($hostState -ne "Maintenance")
Write-Host "$($hostName.Name) is back up..." -foreground "Yellow"}ELSE{Write-Host ""}

IF ($baseline.BaselineType -eq "Upgrade"){Write-Host "$($baseline.Name) is an Upgrade Baseline. Skipping to remediation..." -foreground "Yellow"}ELSE{Write-Host "Staging patches to $($hostName.Name) in Cluster $($clusterName.Name)..." -foreground "Yellow"; Stage-Patch -entity $hostName.Name -baseline $baseline}

Write-Host "Remediating patches on $($hostName.Name) in Cluster $($clusterName.Name). Host will reboot when complete" -foreground "Yellow"
Remediate-Inventory -Entity $hostName.Name -Baseline $baseline -HostFailureAction Retry -HostNumberofRetries 2 -HostRetryDelaySeconds 120 -HostDisableMediaDevices $true -ClusterDisableDistributedPowerManagement $true -ClusterDisableHighAvailability $true -confirm:$false -ErrorAction SilentlyContinue

Write-Host "Retrieving Host build status..." -foreground "Yellow"
$hostBuild = Get-VMHost $hostName.Name
IF ($hostBuild.Build -eq $hostState.Build){Write-Host "Patch/Upgrade was not applied. Check status in vCenter and re-run the script. Exiting..." -foreground "Red";$error;Start-Sleep 20;break}ELSE{}

Get-Cluster $clusterName.Name | Get-VMhost | Select Name,Build,Version,State | Sort Name | format-table -autosize
Write-Host "Exiting Maintenance mode for Host $($hostName.Name)..." -foreground "Yellow"
Get-VMHost $hostName.Name | Set-VMHost -State Connected

IF ($disableRules -eq "Y") {$enableRules = Read-Host "If Cluster patching is complete press "Y" to re-enable DRS rules. Anything else to continue";
IF ($enableRules -eq "Y") {Write-Host "Re-enabling DRS Must Run rules" -foreground "Yellow"; 
foreach ($name in $drsRules){Set-DrsVMHostRule -rule $name -enabled:$true}} ELSE {
Write-Host "DRS Rules not being re-enabled. Continuing..." -foreground "Yellow"}} ELSE {}

$answer = Read-Host "$($hostname.Name) patched in Cluster $($clusterName.Name). Press "1" to re-run the script. Anything else to exit"

}
UNTIL ($answer -ne "1")

Backing Up Portgroup Data with PowerShell and XML

Managing virtual standard switches (vSwitches) in a VMware environment, large or small, can cause a lot of headaches. Ensuring each portgroup is named the same, has the same VLAN and is present on each host can be a challenge. Virtual distributed switches (dvSwitches) exist to make our lives easier, but aren’t always available due to licensing or other restrictions. They have their own drawbacks, but the good generally outweighs the bad.

As I have been spending a significant amount of time in PowerShell and XML recently I wrote a script designed to backup the Portgroup configuration of all your clusters to ensure that all hosts will have the proper networking configuration during host rebuilds or additions. Let’s walk through this script and show you all the different elements.

1. Here we define and connect to the vCenter server

$vCenterFqdn = "vcenter01.domain.local"
Connect-viserver $vCenterFqdn

2. Here we are defining the path for our Portgroups.xml file. We’ll reference this variable later on.

$xmlNetworkPath="C:\Scripts\XML\Portgroups.xml"

3. Here we are checking to see if this file already exists. If it does we’ll skip ahead to the population side, but if not we’ll have to create it. $networkCheck tests the path defined in the variable $xmlNetworkPath. If that file is there, we’re writing into the console that it exists and we’re moving on. If it doesn’t exist we move on to step 4.

$networkCheck = Test-Path $xmlNetworkPath
IF ($networkCheck -eq $True){Write-Host "Portgroup file already exists. Continuing..." -foreground "Green"}
ELSE
{Write-Host "Portgroup file not created. Creating..." -foreground "Yellow"}

4. Since this is our first run, this file doesn’t exist yet so we need to create it. Populating an empty XML file is not something I ever figured out how to do. Someone much smarter than me in XML and PowerShell can figure it out, but I found a nice work around by creating an XML template. This is an outline of what our XML file will be and we’re just filling in the data as we go.

$xmlNetwork=[xml]@’ is saying everything between @’ and ‘@ will be part of this file. At the end, we’re saving this output ($xmlNetwork.Save) to the file path we defined earlier ($xmlNetworkPath).


$xmlNetwork=[xml]@'

<vSwitchConfig>
  <templates>
    <Portgroup>
      <vlanId></vlanId>
      <virtualSwitch></virtualSwitch>
      <cluster></cluster>
    </Portgroup>
  </templates>
  <Portgroups>
    <test />
  </Portgroups>
</vSwitchConfig>
‘@
$xmlNetwork.Save($xmlNetworkPath)

5. In case we run into permissions issues we want to perform an additional check to ensure that file was actually written. For the most part we’re just repeating Step 3. The difference here is we’re changing the output in “Write-Host” but also if the file isn’t created, we need to kill the script. The message is written that the file was not created, then we wait 20 seconds, then exit the script. The reason we add the “Start-Sleep” is in case this script is run by just double-clicking and not triggered from within a powershell window, the script will exit and you’ll never know why.

$networkCheck = Test-Path $xmlNetworkPath
IF ($networkCheck -eq $True){Write-Host "Portgroup file created successfully. Continuing..." -foreground "Green"}
ELSE
{Write-Host "Portgroup file not created. Exiting..." -foreground "Red"; Start-Sleep 20; Break}}

6. Now we need to read the contents of that XML file we created in XML format. The [XML] denotes that this is an XML file. $xmlNetwork is just the variable name I chose (this can be anything you want) and $xmlNetworkPath is the path to the file we defined in step 2

[XML]$xmlNetwork = Get-Content $xmlNetworkPath

7. Now comes the fun part where we actually start pulling data from vCenter. We’re going to get all the clusters in the vCenter we’re connected to. The ForEach command says that for every cluster we need to run this same command. So in each cluster we’re looking for an ESXi host that is currently connected, then we choose a random host from the cluster (get-random) and on that random host we get all the virtual portgroups that aren’t on dvSwitches.

$getClusters = Get-Cluster
ForEach ($cluster in $getClusters) {
$getPortgroups = $cluster | Get-VMHost | Where {$_.ConnectionState -ne "NotResponding"} | Get-Random | Get-VirtualPortGroup | Where {$_.key -notlike "*dvportgroup*"}

8. Now that we have all these portgroups let’s get all the data we need in them. We perform another ForEach on every Portgroup that was on that host. The $testPg variable is used to see if the current Portgroup name ($pgName.Name) is present in the XML file. What we don’t want is to re-add the same Portgroup name over and over again, we just want a single reference to the portgroup name and we’ll add another entry for the clusters that contain it. $testPg -eq $null means if the portgroup name isn’t there, we’ll create a new entry.

foreach ($pgName in $getPortGroups) {
$testPg = $xmlNetwork.vSwitchConfig.Portgroups.Portgroup|Where {$_.name -eq $pgName.Name}
IF ($testPg -eq $null)

9. If the Portgroup isn’t there we need to create a new entry. Looking at the XML file outline we created in Step 4 you see the tag. This is used to work around my inability to create new entries in XML. We copy the section below and then fill out the data as we go


<Portgroup>
  <vlanId></vlanId>
  <virtualSwitch></virtualSwitch>
  <cluster></cluster>
</Portgroup>

The variable “$xmlNetwork” was defined in Step 6 and is the name of our XML file. The addition of “.vSwitchConfig” is the top level tag in our XML file from Step 4.
The variable “$parentNode” defines the top-level of the XML file we’ll be using from our template.
The variable “$destinationNode” defines where this copied data is going to be placed.
The variable “$cloneNode” defines what tag we’re copying from $parentNode.
The variable “$addNameAttribute” is creating an attribute called “name” and the name we’re giving it is the name of the portgroup we’re pulling from vCenter. Adding “.Value = ” to the end of this variable gives us the ability to define the name when we’re creating the new portgroup tag.
The variable $newNode is used to create the new Portgroup tag and then “.InnerXML =” allows us to chose the template tag from the XML file.
(The use of [void] is something I don’t fully grasp. This is the only way it works, but I can’t tell you why.)
Using $destinationNode.AppendChild is saying place this new tag into the $destinationNode location. $newNode is the data that’s being added. “.Attributes” allows us to assign the new name Attribute we defined and “.Append($addNameAttribute)” places that attribute tag.
The variable $updateNetwork is a lookup in the XML file to find a portgroup with the tag we just created.
Once we find that portgroup, $updateVLAN, $updateVirtualSwitch, and $updateCluster are used to assign the values to these empty tags that were created.


{
$parentNode = $xmlNetwork.vSwitchConfig.templates
$destinationNode = $xmlNetwork.vSwitchConfig.Portgroups
$cloneNode = $parentNode.SelectSingleNode("Portgroup")
$addNameAttribute = $xmlNetwork.CreateAttribute("name")
$addNameAttribute.Value = $pgName.Name
$newNode = $xmlNetwork.CreateElement("Portgroup")
$newNode.InnerXML = $cloneNode.InnerXML
[void]$destinationNode.AppendChild($newNode).Attributes.Append($addNameAttribute)
$updateNetwork = ($xmlNetwork.vSwitchConfig.Portgroups.Portgroup|Where {$_.name -eq $pgName.Name})
$updateVLAN = $updateNetwork.vlanId = $pgName.VLanId.ToString()
$updateVirtualSwitch = $updateNetwork.virtualSwitch = $pgName.VirtualSwitchName
$updateCluster = $updateNetwork.cluster = $cluster.Name
}

10. In the event this portgroup already exists, we have the ELSE portion of our IF statement we started in Step 8. Here we’re referencing the portgroup in question and checking to see if the cluster tag has already been added. We look up the portgroup name “$testPg” and search for a cluster that matches the cluster we’re currently working with. If that cluster doesn’t exist, we add a new element ($xmlNetwork.CreateElement(“cluster”)) and populate its value ($addCluster.InnerText = $cluster.Name)

If that cluster tag already exists for that Portgroup, we don’t do anything “{}”


ELSE {($testCluster = $testPg|Where {$_.cluster -eq $cluster.Name});
IF ($testCluster -eq $null) {
$addCluster = $xmlNetwork.CreateElement("cluster");
$addCluster.InnerText = $cluster.Name
$testPg.AppendChild($addCluster) | Out-Null }ELSE{}}
}}

11. Once all of our clusters and Portgroups have been looped through. We need to save that data to the XML file we created.

$xmlNetwork.Save($xmlNetworkPath)

12. Now that the file has been saved, we want to see what data has been written. This isn’t required, but just adds a nice little output to the screen so you can see that the data has been populated as expected.

We perform the same Get-Content command with our [XML] tag. Then we write the output of every portgroup, sorted by name, into a table so we can see all the data.


[XML]$xmlNetwork = Get-Content $xmlNetworkPath
Write-Host "The following Portgroup configuration exists in $($xmlNetworkPath)" -foreground "Yellow"
$xmlNetwork.vSwitchConfig.Portgroups.Portgroup | Sort name | Format-Table

I have obscured some of the networks and VLANs in use in my environment, but this is the output you can expect.

All together this is what the script looks like:


#Connect to the defined vCenter Server
$vCenterFqdn = "vcenter01.domain.local"
Connect-viserver $vCenterFqdn

#Define XML File Path
$xmlNetworkPath="C:\Scripts\XML\Portgroups.xml"

#Check for Portgroup XML File
$networkCheck = Test-Path $xmlNetworkPath
IF ($networkCheck -eq $True){Write-Host "Portgroup file already exists. Continuing..." -foreground "Green"}
ELSE
{Write-Host "Portgroup file not created. Creating..." -foreground "Yellow"

#Create XML Portgroup File

$xmlNetwork=[xml]@'

<vSwitchConfig>
  <templates>
    <Portgroup>
      <vlanId></vlanId>
      <virtualSwitch></virtualSwitch>
      <cluster></cluster>
    </Portgroup>
  </templates>
  <Portgroups>
    <test />
  </Portgroups>
</vSwitchConfig>
'@
$xmlNetwork.Save($xmlNetworkPath)

$networkCheck = Test-Path $xmlNetworkPath
IF ($networkCheck -eq $True){Write-Host “Portgroup file created successfully. Continuing…” -foreground “Green”}
ELSE
{Write-Host “Portgroup file not created. Exiting…” -foreground “Red”;Start-Sleep 20; BREAK}}

#Get contents of XML file
[XML]$xmlNetwork = Get-Content $xmlNetworkPath

#Gather all hosts in each cluster
$getClusters = Get-Cluster
foreach ($cluster in $getClusters) {
$getPortgroups = $cluster | Get-VMHost | Where {$_.ConnectionState -ne “NotResponding”} | Get-Random | Get-VirtualPortGroup | Where {$_.key -notlike “*dvportgroup*”}
foreach ($pgName in $getPortGroups) {
$testPg = $xmlNetwork.vSwitchConfig.Portgroups.Portgroup|Where {$_.name -eq $pgName.Name}
IF ($testPg -eq $null) {
$parentNode = $xmlNetwork.vSwitchConfig.templates
$destinationNode = $xmlNetwork.vSwitchConfig.Portgroups
$cloneNode = $parentNode.SelectSingleNode(“Portgroup”)
$addNameAttribute = $xmlNetwork.CreateAttribute(“name”)
$addNameAttribute.Value = $pgName.Name
$newNode = $xmlNetwork.CreateElement(“Portgroup”)
$newNode.InnerXML = $cloneNode.InnerXML
[void]$destinationNode.AppendChild($newNode).Attributes.Append($addNameAttribute)
$updateNetwork = ($xmlNetwork.vSwitchConfig.Portgroups.Portgroup|Where {$_.name -eq $pgName.Name})
$updateVLAN = $updateNetwork.vlanId = $pgName.VLanId.ToString()
$updateVirtualSwitch = $updateNetwork.virtualSwitch = $pgName.VirtualSwitchName
$updateCluster = $updateNetwork.cluster = $cluster.Name
} ELSE {($testCluster = $testPg|Where {$_.cluster -eq $cluster.Name});
IF ($testCluster -eq $null) {
$addCluster = $xmlNetwork.CreateElement(“cluster”);
$addCluster.InnerText = $cluster
$testPg.AppendChild($addCluster) | Out-Null }ELSE{}}
}}
$xmlNetwork.Save($xmlNetworkPath)

#Display Results
[XML]$xmlNetwork = Get-Content $xmlNetworkPath
Write-Host “The following Portgroup configuration exists in $($xmlNetworkPath)” -foreground “Yellow”
$xmlNetwork.vSwitchConfig.Portgroups.Portgroup | Sort name | Format-Table

vSAN – Check VM Storage Policy & Compliance

As I continue to work with vSAN I discover there’s way more to do than just move some VMs over and you’re on your way. With multiple vSAN clusters each with different configurations I needed a way to monitor the current setup and check for changes. While creating a simple script to check which VM Storage Policy is assigned to each VM isn’t very difficult, a creating a script to check the storage policy of VMs across multiple vSAN datastores proved to be a little more difficult.

We run multiple PowerCLI scripts to check health and configuration drift (thanks to a special tool created by Nick Farmer) in our environment. In the event that a new vCenter is added or new vSAN datastore is deployed, we needed a simple script that can be run without any intervention or modification. Now we can be alerted when the proper VM storage policies isn’t assigned or the current policy is out of compliance.

To further complicate things in our setup, we create a new VM Storage Policy that contains the name of the cluster in which it’s assigned. Due to the potential differences in each vSAN cluster (stripes, failures to tolerate, replication factor, RAID, etc) having a single Storage Policy does not work for us. In the event a VM is migrated from one vSAN cluster to another we need to check that the VM storage policy matches vSAN datastore cluster policy.

What this script does is grab all the clusters in a vCenter that have vSAN enabled. For each cluster that is found with vSAN enabled, it is filtering only the VMs that live on vSAN storage (with the name of “-vsan”. Then we get the storage based policy management (Get-SpbmEntityConfiguration) of those VMs. The script then filters for a storage policy that doesn’t contain the cluster name OR a compliance status that is compliant.

$vsanClusters = Get-cluster | Where-Object {$_.vsanenabled -eq "True"}
foreach ($cluster in $vsanClusters)
{
$Cluster | get-vm |?{($_.extensiondata.config.datastoreurl|%{$_.name}) -like "*-vsan*"} |
Get-SpbmEntityConfiguration | Where-Object {$_.storagepolicy -notlike "*$Cluster*" -or $_.compliancestatus -notlike "*compliant*"} |
Select-Object Entity,storagepolicy,compliancestatus
}

Once this is run we can see the output below. I’ve obscured the names of the VMs, but we can see that there are still 12 VMs that are using the default vSAN Storage Policy instead of the cluster-specific storage policy they should be using. In addition, we see that the compliance status is currently out of date on most of these VMs. These VMs reside on 2 separate clusters and there are also 2 VMs that were filtered because they are on local storage in these clusters instead of vSAN.

storagepolicy01-12202016

Cohesity – DataPlatform in the Cloud

cohesityWhat separates vendors is focus and execution. In a crowded market, finding the right backup provider is no easy task. While each product has its pros and cons, finding the differentiator can be a daunting task. While Cohesity is relatively new to this space (founded in 2013), they have that focus and execution necessary to be a leader in the backup space.

But Cohesity is more than just backups. The Cohesity storage appliance not only handles your backup storage needs, but can also run your dev and test workloads. Cohesity is focused on your secondary storage needs. That secondary storage consists of any workloads or data that isn’t production. By avoiding the draw of being another primary storage vendor, Cohesity is listening to customers, learning their needs and creating a solution that can fit any size business.

storageiceberg

The Cohesity solution was built for a virtualized (VMware-only) environment. Connecting directly to your vCenter servers and pulling your inventory allowing administrators to create backup jobs and policies. While their start was in virtualization, there are still many physical workloads in the datacenter. Creating agents for physical Windows, Linux, and SQL server all backing up to the same storage system and with the same policies prove no workloads can’t be protected by Cohesity.

But wait, there’s more!

While data protection is important, that’s only a small portion of the Cohesity offering. Running these backups directly from the Cohesity storage arrays allows you to free up primary storage resources and (potential) bottlenecks when running multiple instances of the same VM on a single array. Leveraging the SSDs that come in each Cohesity node as a cache tier, testing software patches and deployments from your backed up production VMs means that your performance doesn’t suffer. And with a built in QoS engine your dev/test workloads don’t have to affect the speed of your backups.

Cohesity provides a scale-out solution, meaning as storage demand increases so can your secondary storage space. Operating under a single namespace, as new nodes are added, your space increases without needing to reconfigure jobs to point to a new array or manually re-striping data. Cohesity has customers that have scaled up to as much as 60 nodes with over a petabyte of storage.

To the cloud!

Policy-based backups and replication ensures that your data will be available. Cohesity has the ability to distribute data across the nodes in a cluster, replicate to clusters in another locations, and also replicate your data to a cloud provider in order to satisfy offsite backup requirements. The latest addition to the Cohesity software portfolio is the DataPlatform Cloud Edition. This gives you the ability to run Cohesity in the cloud.

DataPlatform CE is more than just replicating data to the cloud. Your VMs can be backed up to your on-premises cluster and that data can be replicated to your cloud-based array. From that cloud-based array, you can then clone virtual machines to a native cloud format. This means your servers can be run in the cloud in their native format and available to test or even run in the event of migrations or datacenter outages.

Many backup and data protection software vendors are doing replication to the cloud such as Veeam and Zerto. While the features isn’t new, its addition makes Cohesity a serious contender in this space. DataPlatform CE is available currently in tech preview in the Microsoft Azure Marketplace, but Cohesity hopes to release it in the first half of 2017 with support for Azure as well as AWS.

Wrapping Up

Data protection and availability is never going to be exciting. Swapping tapes and deploying agents is tedious work. A fully integrated software solution that not only protects your data, but also helps solve the problem of data sprawl, a platform for developers to test against production data in an isolated environment and the ability to migrate workloads to the cloud. That’s about as exciting as it gets in data protection and that is just the tip of the (storage) iceberg.

________________________________________

Take a look at posts by my fellow delegates from Tech Field Day 12 and watch the videos here.

First Look at Cohesity Cloud Edition
The Silent Threat of Dark Data
Cohesity Provides All of Your Secondary Storage Needs
Secondary Storage is Cohesity’s Primary Goal

________________________________________

Disclaimer: During Tech Field Day 12, my expenses (flight, hotel, transportation) were paid for by Gestalt IT. Cohesity provided each delegate with a gift bag, but I am under no obligation to write about any of the presented content nor am I compensated for such writing.

VSAN – Compliance Status is Out of Date

Occasionally the Compliance status of the performance service will go to the “out of date” status. This is not an alert that is thrown anywhere within vCenter. You will have to check this status by logging into the vSphere web client, locating your vCenter, choose the cluster, clicking on “Manage” then choosing “Health and Performance” under “Virtual SAN”
ComplianceStatus-a

As I have recently fixed this issue the above screenshot shows the “Compliant” status. Below are the steps to get to that point.

1. In the box for “Performance Service” click “Edit storage policy”
ComplianceStatus-01

2. If there is a storage policy available in the drop down, select it and click “OK”. This will apply that policy and perform the compliance check.
ComplianceStatus-02

For the lucky few where that works, that’s all you need to do. If the storage policy list is empty you’ll need to restart the vsanmgmtd service on each of the hosts.

3. Enable SSH on each of the hosts in the VSAN cluster and using an SSH client (like putty), SSH to a host and run the following command to restart the vsanmgmtd service (this is a non-impactful operation and should be able to be performed during production hours with no impact)
a. /etc/init.d/vsanmgmtd restart

4. Repeat that command on each of the hosts in the cluster until they have all restarted their services
ComplianceStatus-04

5. Wait 5 minutes and then check to see if you are able to select a storage policy for the performance service. If not, move on to step 6

6. Now we’ll need to restart the vSphere Profile-Driven Storage Service on the vCenter server. This is also non-impactful and should be able to be performed in the middle of the day. If you’re using vCenter on windows, connect to the Windows server and restart the “Vmware vSphere Profile-Driven Storage Service”. If using VCSA (like this example) you’ll need to SSH to the VCSA and run the command below
a. Service vmware-sps restart

7. After the vmware-sps service restarts, log out of the web client and wait for 5 minutes while the storage profile service completes its restart.

8. Log back in to the web client, navigate to the vCenter server, click “Manage” then choose the “Storage Providers” tab
ComplianceStatus-08

9. Click the Synchronize Providers button to resync the state of the environment
ComplianceStatus-09

10. Wait another 5 minutes while these synchronize completes. After 5 minutes, navigate to the VSAN cluster in the web client. Click on “Manage” then choose “Settings” and locate “Health and Performance” under the “Virtual SAN” section
ComplianceStatus-10

11. In the Performance Service box, click the “Edit Storage Policy” button
ComplianceStatus-11

12. From the drop down list you should be able to select the appropriate VSAN storage policy and then click “OK”
ComplianceStatus-12

13. After this is selected the compliance status should change to “Compliant” and you should be all set.

So far these are the only steps that I have needed to follow in order to fix this issue. Let me know if there are any other fixes available.

Change IP of vCSA

While changing the IP address of my vCenter Server is not something I’ve ever had to do before that changed this week. In my quest to separate networks into more logical groupings instead of everything living on the same subnet I had to change the IP address of my vCenter Server Appliance to place it on a new network along with the hosts it was managing. There is apparently a right way and a wrong way to do this.

I logged into the vCSA web interface (vCenterIP:5480), clicked on the “Network” tab and then click on “Address” and assumed this would be the correct place. So I changed the IP address and clicked “Save Settings” then rebooted the appliance.

changeip012315-step1

Yeah…that wasn’t right. As I watched the appliance boot from the console I saw a lot of errors being thrown trying to access services running on the old address and failing. Then I decided to shut down (not reboot) the vCSA and try a different method. This is a pretty simple process, but in case you’re looking for the right way of doing it, this is what worked for me.

Once the appliance is powered off, right click and choose “Edit Settings”
changeip012315-step2

Click the “Options” tab then choose “Properties” under “vApp Options”
changeip012315-step3

Enter the new IP address, gateway, and any other information that is changing. If you’re moving it to a new portgroup, update that now as well and click “OK”
changeip012315-step4

Once the changes have been made, power on the appliance and you should see the new addresses being referenced during start up.
changeip012315-step5

And now that start up is complete, we see the new IPs listed for managing the appliance and you should be able to connect on the new IP.
changeip012315-step6

Like I said, this is a very simple process. Once the vCSA was running, my hosts were notified of the change and were still in their cluster. Nothing bad happened and the lab continued to function as expected.

Restore Files & AD Objects From NetApp & Veeam v8

With the release of Veeam Backup & Replication v8 we can restore directly from NetApp Snapshots. Whether it’s an entire VM, individual files, or just some objects in Active Directory, you can do it all from the Veeam console. For a guide on installing and configuring Veeam v8 with NetApp storage, click here

We’ll be testing the restore of individual files and some Active Directory objects for this blog post. In this scenario we have a couple Domain Controllers (2008 R2) and a couple of member servers with some files that we’ll delete. We also have an OU with a couple users, a member server, and a group.

Each of these VMs sit on either of these two volumes, Win_2008 and Win_2012. If you click on “Storage Infrastructure” in the Veeam Backup and Replication console, then expand your NetApp storage you’ll see a list of all the volumes available and their snapshots.
veeamrest120114-part1

1. I’ve taken a snapshot in NetApp System Manager of these volumes. To list these snaps, refresh the volume by right-clicking on the volume and choosing “Rescan volume” or right click on the storage array and choose “Rescan Storage” (Since we have 2 volumes to refresh, we’ll rescan storage.
veeamrest120114-step1
2. A new window will popup showing the progress
veeamrest120114-step2
3. Once completed, we now see the new snapshot I created called “Pre-delete”
veeamrest120114-step3
4.I’m going to delete a file from the server “Lab2008” (on the Win_2008 datastore) and “Lab2012” (on the Win_2012 datastore) that are sitting on my desktop.
veeamrest120114-step4a
veeamrest120114-step4b
5. And let’s also delete the OU “Delete Test” which contains a couple test users, a group they are apart of and the VM “Lab2008”
veeamrest120114-step5
6. Now that those files and OU\objects have been delete, let’s go back to the Veeam console and see what we can recover. We’ll start with the files for the “Lab2012” VM.
7. Expanding “Win_2012” datastore in “Storage Infrastructure” view, click on the name of the snapshot I created earlier and we see the “Lab2012” VM
veeamrest120114-step7
8. We right-click on “Lab2012”, hover over “Restore guest files” and then choose “Microsoft Windows”
veeamrest120114-step8
9. Under the “File Level Restore” screen, click “Customize” in the bottom right corner
veeamrest120114-step9
10. As long as you’re restoring to a vCenter/Host that’s already been added to Veeam, choose the host, resource pool (if any) and folder. Click “OK” then click “Next”
veeamrest120114-step10
11. Enter a reason for the restore and click “Next”
veeamrest120114-step11
12. Click “Finish”
veeamrest120114-step12
13. The restore session will open and mount the snapshot/VM to the chosen host
veeamrest120114-step13
14. In vCenter, we see these 2 tasks of creating a datastore and registering the virtual machine.
veeamrest120114-step14
15. On the host, we see a new powered off VM with the name of “Lab2012” followed by a GUID.
veeamrest120114-step15
16. Back at the Veeam console, the Backup Browser window appears and we can browse to the location of the deleted file
veeamrest120114-step16
17. From here, we can copy the file to our local machine or restore it directly to the Virtual Machine. Right click on the file and choose “Restore” then “Overwrite”
veeamrest120114-step17
18. We’ll pick “Use the following account” and choose my Lab Domain credentials and click “OK”
veeamrest120114-step18
19. The restore process will start and you’ll see this output if you click “Show Details”
veeamrest120114-step19
20. Logging back in to “Lab2012” we can see the file has been restored
veeamrest120114-step20
21. Close the “Restoring files” window in the Veeam console and the “Backup Browser” window. After they’re closed, the VM will be unregistered on the host and the datastore will be unmounted.
22. I’m doing a restore from “Lab2008” but this time I will just copy the file to my local computer instead of restoring to the guest VM. After browsing the datastore snapshots and choosing “Restore Guest Files”, we’ll browse the directory structure, locate the file, right-click and choose “Copy To”
veeamrest120114-step22
23. A window will pop up to choose the folder location on your machine and whether to preserve permissions and ownership. Then click “OK”
veeamrest120114-step23
24. Now in the root of the C: drive we have the “Lab2008-txt” file
veeamrest120114-step24
25. Let’s look at the “Lab2008” VM now. It was in that OU we deleted and after rebooting it and trying to login we receive the message “The security database on the server does not have a computer account for this workstation trust relationship”. We can fix that.
veeamrest120114-step25
26. Back in the Veeam console and the “Pre-delete” snapshot for the “Win_2008” datastore, we’ll locate the “Lab-DC01” VM. Right click on the VM, hover over “Restore application items” and then click “Microsoft Active Directory objects”
veeamrest120114-step26
27. Our host settings are saved from the last restore we did, so click “Next”
veeamrest120114-step27
28. Enter a restore reason and click “Next”
veeamrest120114-step28
29. Review the summary and click “Finish”
veeamrest120114-step29
30. The Veeam Explorer for Microsoft Active Directory window will appear
veeamrest120114-step30
31. Then the VM will be mounted in vCenter
veeamrest120114-step31
32. Once the Veeam Explorer window for AD opens, you’ll be able to browse your Domain object. We’ll expand the “LabOU” object where we see “Delete Test” with the same 2 test users, “Lab2008” server and the group those users belong to.
veeamrest120114-step32
33. Right click the “Delete Test” OU and choose “Restore container to LabDC.local”
veeamrest120114-step33
34. Enter the credentials for the account with access to add objects to the domain and click “OK”
veeamrest120114-step34
35. You’ll see the progress of the restore and then the summary of how many objects were restored
veeamrest120114-step35

(In order for this to work your Veeam server will need network access to the live domain controller)

36. If we refresh the screen for Active Directory Users and Computers on “Lab-DC01” we’ll see the OU is back with all of it’s objects
veeamrest120114-step36
37. In the properties for the users, we can see that group membership was retained. The group “Email Group” is located in another OU and that membership was restored as well
veeamrest120114-step37
38. And now when we try to login to “Lab2008” with domain credentials it works with no issues.

 

How fast can this restore happen? From the time I opened the Veeam console until the time the OU reported as being restored took 3 minutes and 34 seconds. In an emergency where someone accidentally deletes an entire OU, a user account, a server, or anything else, they can all be restored in under 5 minutes time without the need to reset any passwords and everything will work without anyone ever noticing. Veeam is awesome and just keeps getting better and better.

Veeam v8 Install With NetApp Config

Veeam has released v8 of it’s Backup and Replication software. As a long time Veeam user this is a release I have been waiting for. Previously, Veeam had released support for storage snapshots on HP storage arrays, but with my environments being primarily NetApp over the last few years I wasn’t able to take advantage. Now in v8, we can restore and backup directly from snapshot. This speeds up the process and limits the impact on the Virtual Machines in the environment.

This guide walks you through a brand new installation of Veeam Backup & Replication v8 on Server 2012 and how to add your NetApp storage array as an object to browse existing snapshots. This is a high-level guide and in the future I’ll do a more in-depth backup/restore from Storage. For my guide on installing Veeam v7 with Windows 2012 R2 Data Deduplication, click here.

If you’re not interested in a custom SQL Express installation as well, pick up the guide at step 15. Steps 1-15 show how to install SQL Express to the secondary drive to prevent growing databases from affecting the main OS partition.

Prerequisites:

1. Dedicated server for installing Veeam
2. License file for Veeam (copied out to the server)
3. Latest version of Veeam v8 downloaded and mounted on the server (the installer is in an .ISO)
4. A service account for running the Veeam services (Optional, but my preferred method)
5. Username/password with admin rights to vCenter
6. Username/password for NetApp array (for this post I’ll be using the ‘root’ account)

Steps:

1. Right click the DVD drive and click “Open”
veeamv8111714-step1
2. Navigate to Redistr -> x64. Locate SQLEXPRx64.exe, right click and choose “Run as administrator”
veeamv8111714-step2
3. Click “Yes” to run the installer if prompted
veeamv8111714-step3
4. Under the “Installation” section, click “New SQL Server stand-alone installation”
veeamv8111714-step4
5. Click the check box for “I accept the license terms” and decide if you want to send feature usage data to Microsoft then click “Next”
veeamv8111714-step5
6. Ensure the check box for “Include SQL Server product updates” is checked and click “Next”
veeamv8111714-step6
7. Updates and setup files will install…
veeamv8111714-step7
8. Choose the features to install (Database Engine Services is the only thing required). Choose the install directory (I always choose the secondary drive of the machine and click “Next”
veeamv8111714-step8
9. Choose a name for the instance or leave as default (SQLExpress), choose the instance root directory (secondary drive again) and click “Next”
veeamv8111714-step9
10. Enter a service account for running the SQL DB engine (or leave it as local system) and click “Next”
veeamv8111714-step10
11. Choose “Mixed mode” for the authentication type then enter a password for the “sa” account (Immediately save this password somewhere). Choose the groups/users that will be SQL Server administrators
veeamv8111714-step11a

a. Be default, only users/groups added here will have access to the Veeam console. If you don’t want to grant permissions to the SQL instance, you can grant access to these users/groups for the Veeam database after it has been created

12. Click on the “Data Directories” tab and ensure all the directories are pointing to the secondary drive and click “Next”
veeamv8111714-step12
13. Choose whether to send error reports and click “Next” and the installation will begin
veeamv8111714-step13
14. Once the installation completes, click “Close”
veeamv8111714-step14
15. Close the “SQL Server Installation Center” window. Navigate back to the root of the DVD drive. Right click on “Setup.exe” and choose “Run as administrator”
veeamv8111714-step15
16. Click “Yes” to run the installer if prompted
veeamv8111714-step16
17. Click “install” for “Veeam Backup & Replication”
veeamv8111714-step17
18. Click “Next”
veeamv8111714-step18
19. Read and accept the license terms and click “Next”
veeamv8111714-step19
20. Click “Browse” and locate your license file then click “Next”
veeamv8111714-step20
21. Choose the features to install and the install directory then click “Next”

a. To install to a different location (like a secondary drive), the folders need to be created ahead of time
veeamv8111714-step21

22. If any features are missing, click “Install”
veeamv8111714-step22
23. Once the system configuration check passes, click “Next”
veeamv8111714-step23
24. Review the default configuration and if no changes need to be made, click “Install”
veeamv8111714-step24
25. Once the install completes, click “Finish”
veeamv8111714-step25
26. Close the setup window and restart the server
27. After the server finishes rebooting, login and view the services to ensure the Veeam and SQL services that are “Automatic” have started
veeamv8111714-step27
28. Open “Veeam Backup & Replication”
veeamv8111714-step28
29. Click “Managed servers” on the left side and then click “VMware vSphere”
veeamv8111714-step29
30. Enter the name or IP of the vCenter Server and click “Next”
veeamv8111714-step30
31. Click the “Add” button and then enter the username/password of an account with permissions on the vCenter server. Click “OK” then click “Next”
veeamv8111714-step31
32. Click “Finish”
veeamv8111714-step32
33. To add your NetApp storage systems to Veeam, click on “Storage Infrastructure” and then click the “Add Storage” button
veeamv8111714-step33
34. Click “NetApp Data ONTAP”
veeamv8111714-step34
35. Enter the Name or IP of the storage system and click “Next”
veeamv8111714-step35
36. Click “Add” to add credentials to connect to the NetApp then choose the protocol and port. Click “Next”
veeamv8111714-step36
37. If the name/IP and credentials work, click finish and discovery of VMs and LUNs/Volumes will begin.
veeamv8111714-step37
38. Once storage and VMs have been discovered, click “Close”
veeamv8111714-step38
39. In the “Storage Infrastructure” view, expand “NetApp”, then the storage system. Choose a volume with virtual machines and current volume snapshots. Expand the volume, choose a snapshot and see what VMs are inside.
veeamv8111714-step39

a. From this view you can delete existing snapshots, create new storage snapshots, and rescan the volume for new snapshots. At the VM-level, you can instantly recover the VM from snapshot, restore guest-OS files, and even restore objects from Active Directory, Exchange, SQL or SharePoint.
veeamv8111714-step39a

40. Click on “Backup & Replication” then expand “Backups” and click on “Storage snapshots.” You’ll see a list of all the volumes that have snapshots, what VM’s are in those snapshots, and how many restore points are available.
veeamv8111714-step40

This is the basics of installing Veeam v8 and connecting to your vCenter Server and NetApp Storage. The process is incredibly simple and like every else from Veeam it just works. In the future I intend to add more restore scenarios such as application item recovery and VM recovery from storage snapshots.

Tegile Array Replication and Restore

These days most of my replication is handled at the VM-level by software design for virtualization. While that is the case for most of my evironment, I still have a few non-virtualized workloads that run on shared storage that need to be replicated in the event of a disaster at my primary location. This process has never been too complex from my days of working with NetApp and now as I continue exploring the Tegile I’m happy to say that it’s just as easy through the GUI.

Documenting this process for my non-virtual workloads would be a little difficult so I’ve decided to document this process using an NFS datastore containing a few virtual machines. The first half of this guide is setting up the replication relationship and replicating the data. The second-half is the process to actually restore that data and make it usable at your DR site.

 

1. Login to the web interface of the Tegile that is the replication source
2. Click on “Settings” then “App-Aware”
tegiledr111214-step2
3. Click on “Zebi Replication” on the left column
tegiledr111214-step3
4. Under the tab “Replication Target” click the “Add” button (This is adding the DR Tegile as the target array)
tegiledr111214-step4
5. Enter the name or IP of the array (the shared Management IP address) and the username/password (Optionally you can specify a port range for replication which we won’t be doing for this documentation) and click “Add”
tegiledr111214-step5
6. Once it has been successfully added it will appear in the “Replication Target” list
tegiledr111214-step6
7. Login to the web interface of the DR target Tegile, click on “Settings” then “App-Aware”, choose “Zebi Replication” on the left column and then click on “Replication Source” tab. You should see your other array listed here (The IP address will be the “management” IPs of each controller, not the shared management IP for both arrays)
tegiledr111214-step7
8. Back on the Primary Tegile (Replication source) click on “Data”
tegiledr111214-step8
9. Click on the disk pool then then project that will be replicated
tegiledr111214-step9
10. For this documentation I’ve created a Project named “NFS_Replication” with a volume named DR_Windows with 4 VMs inside. Click on the project that will be replicated and click on the “Edit” button
tegiledr111214-step10
11. Click on “Replication” on the left column
tegiledr111214-step11
12. Click the “Add Replication” button
tegiledr111214-step12

a. Select the Target System and click “Next”
tegiledr111214-step12a
b. Select the “Target Pool” and enter a name for the “Replication Project”. Click “Next”
tegiledr111214-step12b
c. Choose what options are required and which volumes will be replicated (This test only has one volume, DR_Windows, but you can include or exclude any volumes that exist in this project. We’ll choose quiesce which will perform a VMware snapshot to put the OS in a consistent state. Click “Next”
tegiledr111214-step12c
d. Choose your schedule (manual or automatic), frequency, and how many additional snapshots (restore points) will be saved on the target array. For this example we’ll do daily replication that happens at 10:49 am and we’ll keep 14 snapshots. Click “Finish”
tegiledr111214-step12d
e. Once it’s all setup, you’ll see your target array, the target pool, and the target project
tegiledr111214-step12e

13. I have 4 VMs in that datastore (DR-Test01-04). Once the time hits, we can see that snapshots are taken, then removed, for each of the VMs in that datastore.
tegiledr111214-step13
14. On the DR target array, we can see we now have snapshots available for this project. (The reason there are 2 is because I initiated a manual replication sync for testing first)
tegiledr111214-step14

a. To manually kick off a replica snapshot, on the source array, find the project, click on “Replication” and then click the “Play” button that says “Replicate”
tegiledr111214-step14a

 

That is how simple it is to setup replication. Now let’s imagine we need to spin up those replicated VMs in this volume. Here is how we do that.

 

1. On the DR target array, click on Data, select the pool, then click on “Replica (1)” to view the replica project
tegilerest111214-step1
2. Click the “Edit” button for the NFS volume
tegilerest111214-step2
3. Click on “Snapshots” and find the snapshot you want to bring live (We’ll choose the latest version). Click the “Clone” button
tegilerest111214-step3

a. Cloning the snapshot will allow us to create a new project and NFS Volume from this snapshot and spin up these VMs in DR. By doing a clone, we’re able to continue to replicate data in the event you are testing replication instead of having an actual DR event.

4. Enter a name for the new Project (DR_NFS_Replication for this writing) and a name for the mount point (/export/DR_NFS_Replication for this writing) and click “Clone”
tegilerest111214-step4
5. If successful, you’ll receive this message about the new project being created. Click “OK”
tegilerest111214-step5
6. Close the window for “Share Configuration” and click on “Local (1)” under “Projects”
tegilerest111214-step6
7. Click on the “DR_NFS_Replication” project then view the Mountpoint of the Share (/export/DR_NFS_Replication/DR_Windows). Note the “c” before the share name which denotes it was a clone from another projects
tegilerest111214-step7
8. Click the “Edit” button for the project and then click on “Sharing”
tegilerest111214-step8
9. This is where you will add the IP addresses or range of IPs that need read/write and root access to the shares in this project. The IP addresses/ranges will carry over from the source array. Our IP range is the same in DR as our lab so we’ll leave this alone.
tegilerest111214-step9
10. Connect to your DR vCenter server or ESXi hosts. Click on the host, then “Configuration”, then “Storage”
tegilerest111214-step10
11. Click “Add Storage” towards the top right
tegilerest111214-step11
12. Choose “Network File System” and click “Next”
tegilerest111214-step12
13. Enter the NFS IP address of the DR Tegile, enter the folder path (/export/DR_NFS_Replication/DR_Windows) and then enter the name of the Datastore (DR_Windows). Click “Next”
tegilerest111214-step13
14. Review the summary info and click “Finish”
tegilerest111214-step14
15. Repeat for each host that needs access to this datastore. Afterwards, right click the datastore and click “Browse Datastore”
tegilerest111214-step15
16. Inside you’ll see the 4 VMs we that were located in here before. Open each folder, right click the VM name.vmx file and choose “Add to inventory”
tegilerest111214-step16
17. Enter the name and location for the VM and click “Next”
tegilerest111214-step17
18. Choose the Cluster or host and click “Next”
tegilerest111214-step18
19. Review the settings and click “Finish.” Repeat for each VM that needs to be added.
tegilerest111214-step19
20. Power on all the VMs and now you can run any validation tests or bring these VMs live in a DR event
tegilerest111214-step20

 

Obviously, the process of mounting the datastore in your DR vCenter Server and re-adding the VMs one by one would be time consuming and tedious. When developing your DR plans, having this process scripted (easy enough in something like PowerCLI) ahead of time on the vCenter side of things would ease that burden. From the standpoint of the Tegile, this process is fairly intuitive and simple to setup. One of the things I love is that by default the data you are bringing live on the DR site is a clone and replication continues running without being affected.

Deploy NetApp OnCommand Balance 4.2

OnCommand Balance is a virtual appliance deployed within vCenter that allows you to monitor the health of your VMware environment at the Virtual Machine, vCenter and Storage level. Having a single place that displays end-to-end performance allows you to spend less time troubleshooting performance issues and trying to correlate data and address potential issues in your environment.

I’ve been using OnCommand Balance (formerly OnCommand Insight Balance) for a few years now and it has saved countless hours finding issues in the environment. We’ve had historical data available to look at growth and performance trends, as well as increased demand on individual servers after code releases/updates. Having access to the information within the VMs (such as drive space filling up) also makes this an invaluable tool.

The following documentation will take you through the deployment process of the Virtual Appliance and initial setup. You will go through adding your vCenter hosts, storage controllers, creating saved credentials, connecting to Active Directory for authentication and provision a Windows proxy service for monitoring Windows Servers.

Prerequisites:
1. A user account with appropriate permissions to vCenter for OnCommand Balance to use
2. A domain account with permissions to access all monitored Windows machines (preferrably a Domain Admin account)
3. A separate Windows Server/VM that will be used as the Proxy service to monitor Windows machines
a. Must have latest version of Java 6 installed and User Account Control disabled
4. Username/password for the NetApps that will be monitored

Steps:
1. Download the latest version of OnCommand Balance (4.2) for this writing from the NetApp website
balance101414-step1
2. Connect to the vSphere web interface, click on “vCenter”, “Hosts and Clusters”, expand the Datacenter, and click on the Cluster/Host that will host OnCommand Balance. Right click and choose “Deploy OVF Template”
balance101414-step2
3. Click “Local file” and then “Browse”
balance101414-step3
4. Locate the OnCommand Balance OVA and click “Open” then click “Next”
balance101414-step4
5. Review the details of the OVF then click “Next”
balance101414-step5
6. Accept the EULA then click “Next”
balance101414-step6
7. Give the appliance a name and choose the folder location of the appliance (if any) and click “Next”
balance101414-step7
8. Set the virtual disk format (I prefer Thin since one of the drives is 220GB) and choose the datastore. Click “Next”
balance101414-step8
9. Choose the appropriate network and then click “Next”
balance101414-step9
10. Review the settings then click “Finish”
balance101414-step10
11. After deployment completes, locate the appliance, right click and choose “Power On”
balance101414-step11
12. Open the console of the VM (Right-click and choose “Open Console”) where you’ll see this countdown to install VMware tools prior to configuring the Balance virtual appliance (If you miss your chance to do this at this point, I was unable to install VMware tools at all on the appliance)
balance101414-step12
13. Right-click on the VM, go to “All vCenter Actions”, then “Guest OS” and then click “Install VMware Tools”
balance101414-step13
14. After the VMware tools dialog box is displayed, click “Mount”
balance101414-step14
15. The Balance virtual appliance should recognize VMware tools ISO has been mounted and proceed with the installation
balance101414-step15
16. After VMware tools install completes, press “y” then enter to configure static Network connection for the management interface
balance101414-step16
17. Enter the following information:

a. Host name
b. Host IP address
c. Netmask
d. Gateway
e. Primary DNS address
f. Secondary DNS address
g. Search domains
balance101414-step17g

18. Review the settings and then press “y” and enter if everything is correct
balance101414-step18
19. Default OnCommand Balance console login is netapp/netapp. Login to the console
balance101414-step19
20. After a few minutes (5-10) the web service will be up and running. Connect to the https://IPofAppliance/bp to begin configuration
21. Enter the name of your organization and click “Continue”
balance101414-step21
22. Choose if you want to participate in AutoSupport and click “Submit”
balance101414-step22
23. Enter the time zone, NTP Server address, the address of the primary Balance admin (preferably a distribution group), and the SMTP server address. Click “Continue” (You can choose to change the password at this time)
balance101414-step23
24. Sit around and wait a couple minutes…
balance101414-step24
25. A blank screen may appear during this time, but eventually should take you to the OnCommand Balance login page. Login with the default credentials of admin/password or whatever password was set in step 23.
balance101414-step25
26. Click the link for “Configure you storage arrays & appliances”
balance101414-step26
27. Choose the type of storage (NetApp FAS in this case), enter the management address for one of the nodes, Enter the name of the filer, enter the credentials (root in my case) and enter a nickname of these credentials as they can be modified later on during password changes. Click “Save”
balance101414-step27
28. Even though DNS is configured correctly, I usually receive this error about the other filer of this HA system not being resolvable. Click “Enter IP address instead” and then enter the IP of the other filer and click “Resolve”
balance101414-step28
29. Click the “Refresh” link on the right side of the page a few times until “Discovery Collection” status changes to “OK”
balance101414-step29
30. Click the “Add storage system” button to add additional storage arrays (Including the HA partners). Click on “Dashboard” then choose “Configure your vCenter Server”
balance101414-step30
31. Enter the FQDN/IP Address of the vCenter server. Click “Add new” next to Credentials to add the credentials for the vCenter server
balance101414-step31
32. Enter the username, password, and nickname for these credentials. Click “Next”
balance101414-step32
33. Choose what you want monitored (though I can’t imagine why you’d choose not to monitor everything) and click “Save”
balance101414-step33
34. Click the “refresh” link until “Discovery Collection” status changes to “OK”
balance101414-step34
35. Click “Add vCenter Server” button to add any additional vCenter servers. Otherwise, hover over “Discovery” and choose “Credentials”
balance101414-step35
36. To monitor the OS’s of your VMs and physical servers, you can add those credentials on this page. I’ll add domain admin credentials for monitoring my Windows domain VMs. Click “Add credentials” button
balance101414-step36
37. Choose the login method, login name (domain\username), password, nickname for the credentials, and a description. Click “Save”
balance101414-step37
38. Once added they will appear on this screen
balance101414-step38
39. Hover over “Discovery” and choose “Proxies”
balance101414-step39
40. A proxy is required to monitor the guest OS status of Windows VMs and Physical servers. This proxy runs on a windows server. Once you’ve determined (or built) the appropriate server for the proxy, enter it’s FQDN or IP address and click “Continue”. Much like the picture below says, UAC MUST be disabled. You’ll beat your head against the wall for hours trying to figure out why it fails without that.
balance101414-step40
41. Download and install the latest 32-bit Java 6 runtime on this proxy server. Then navigate to the link listed on that proxy VM to begin the installation
balance101414-step41
42. Once the Balance Proxy Installer screen appears, click “Next”
balance101414-step42
43. Locate the folder path for the 32-bit java install and click “Next”
balance101414-step43
44. Enter an admin account for the service to be run under. Check the box for “Start service immediately after install” and click “Next”
balance101414-step44
45. Select any additional components you might need for other vendors and click “Next”
balance101414-step45
46. Review the information and click “Install”
balance101414-step46
47. Click “Finish”
balance101414-step47
48. Back at the Balance web interface, click “Validate proxy setup” and if successful, click “Continue”
balance101414-step48a
balance101414-step48b
49. Hover over “Discovery” and click on “Servers”
balance101414-step49
50. Click the link on the right side for “Unmonitored Servers”
balance101414-step50
51. Click the link next the vCenter server for “# guests are not being monitored”
balance101414-step51
52. Check the box next to the VMs you wish to monitor, choose your Credentials from the dropdown box in the center and click “Monitor guest(s)”
balance101414-step52
53. Hover over “Admin” and choose “Configuration”
balance101414-step53
54. Click “Email”. In here you can set authentication for your SMTP server, choose the “From” address for Balance emails. Click “Enable alerts” and then check all the boxes for Critical, Warning, and all categories (I prefer as many alerts as I can get). Click “Update”
balance101414-step54
55. Click on “Active Directory” and click the check box for “Enable Active Directory”
balance101414-step55
56. Enter the IP/hostname of your AD server, enter the Distinguished name of the account used to search Active Directory, and enter the password for that account. Click “Test”
balance101414-step56
57. Once successful, enter the Distinguished Name of the of the OU for the user/group that will have access to login. Enter the Distinguished name of the Group that will be able to login. Enter “sAMAccount” for the search attribute. Click “Update”
balance101414-step57
58. Hover over “Admin” and click “Users”
balance101414-step58
59. Click “Add User”
balance101414-step59
60. Change “Authentication” to “Active Directory”. Enter the username and click “Lookup”. If successfully, configured, it should populate the e-mail address. Choose the appropriate user type (Admin or User) and click “Save”
balance101414-step60

You’re all setup and ready to let OnCommand Balance start collecting data in your environment. You start to receive some information within about 30 minutes, but after 3-5 days you start to get a better understanding of what is going on in your environment and have more useful metrics.