So this next post is about my experience with vSAN when using multiple storage policies and the headache that comes with managing a large vSAN environment when you have too many cooks in the kitchen!!

The environment I help manage has many clusters with many different storage policies… Unfortunately the storage policy “Compliance” status can be misleading and risky at scale especially if that’s all your depending on for desired / expected state of VM storage policy.

Recently we discovered that VM Home directories and VMDKs would end up with a mix and match of police’s if the administrators were not careful when moving, cloning and adding / changing disks! (basically BAU activities)

For example in our configuration we have 1 storage policy per vSAN cluster and depending on the requirement of the customers VM’s … they end up on a specific cluster with a specific storage policy (FTT=1, FTT=2, RAID1, RAID5/6 with Erasure Coding…etc)… now when we looked in the vCenter GUI all the VM’s were showing up as compliant with the storage policy which was great!!! but when we started to dig deeper we found out that VM’s were at risk because some disks would only tolerate 1 host failure where as others would tolerate 2 host failures some were on RAID1 and others on RAID5/6 with EC…!!!!

To manage / report correctly on the desired state and compliance of VM’s I built this report on my home lab (see below), it checks every single VM, it’s home directory and each VMDK and pumps the results out to a CSV.

So while the report above is useful… when you have 1000’s of VM’s to manage some additional logic and checking is required… Currently I visualise this data in Tableau by merging it with some inventory data…. but now I am working on improving this report further by validating against a configuration file that contains the expected policy for that Cluster / Datastore and identifying VM’s with issues (outOfDate, nonCompliant or compliant with the wrong policy for its location)

2 silly things which I discovered while on this adventure…

1). It appears there is no way to extract the current default vSAN policy via PowerCLI or the API… the only way I could do it was by creating a VM on a datastore and then checking what policy it got

2) The default vCenter Read Only role does not have sufficient permissions to run the command get-SpbmEntityConfiguration you need an additional permission for the user: Profile-driven storage view

so to the script!

To create the credentials file run the following command.

$cred = Get-Credential
$cred | Export-Clixml -Path "d:\vcenter\config\HOME-VC.xml"

To run the script..

.\getStoragePolicy.ps1 -VC -creds HOME-VC -Filename "d:\vCenter\Reports\StoragePolicyReport.csv"

Main script

#Powershell collector script for vSAN storage policy compliance
#v1.0, 28.08.2017 - Initial Version
    Run the command below to store user and pass in secure credential XML for each environment

        $cred = Get-Credential
        $cred | Export-Clixml -Path "HOME-VC.xml"


#Logging Function
Function Log([String]$message, [String]$LogType, [String]$LogFile){
    $date = Get-Date -UFormat '%m-%d-%Y %H:%M:%S'
    $message = $date + "`t" + $LogType + "`t" + $message
    $message >> $LogFile

$ScriptPath = (Get-Item -Path ".\" -Verbose).FullName
$mods = "$ScriptPath\Modules;"
$random = get-random
$RunDateTime = (Get-date)
$RunDateTime = $RunDateTime.tostring("yyyyMMddHHmmss")
$RunDateTime = $RunDateTime + '_'  + $random
$LogFileLoc = $ScriptPath + '\Log\Logfile.log'

if($creds -gt ""){

    $cred = Import-Clixml -Path "$ScriptPath\config\$creds.xml"

    echo "Environment not selected, stop hammer time!"

Log -Message "Starting Script" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc

Log -Message "Connecting to $VC with credentials $creds" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc

Connect-VIServer -server $VC -Credential $cred -Force 

$DiskPolicyReport = @()

Log -Message "Getting VM List from vCenter" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc

$vms = Get-VM

Log -Message "Running loop for VM Home Directory and VMDK Policy" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc

foreach ($vm in $vms){

    $vmCluster = Get-Cluster -VM $vm
    $vmDatastore = Get-Datastore -VM $vm

    $VMHome = $vm | get-SpbmEntityConfiguration

        Foreach ($VMH in $VMHome){

            $DiskPolicyReport += New-Object PSObject -Property @{

            VM = $vm
            Cluster = $vmCluster
            Datastore = $vmDatastore
            Entity = 'VMHome'
            Policy = $VMH.StoragePolicy
            Status = $VMH.ComplianceStatus
            DateTime = $VMH.TimeOfCheck

                Remove-Variable VMH -Force -ErrorAction SilentlyContinue

    $VMDisks = $vm | get-harddisk

        Foreach ($disk in $VMDisks){

            $VMDisk = $disk | get-SpbmEntityConfiguration

            $DiskPolicyReport += New-Object PSObject -Property @{

            VM = $vm
            Cluster = $vmCluster
            Datastore = [regex]::match($disk.Filename,'\[(.*?)\]').Groups[1].Value
            Entity = $VMDisk.Entity
            Policy = $VMDisk.StoragePolicy
            Status = $VMDisk.ComplianceStatus
            DateTime = $VMDisk.TimeOfCheck

                Remove-Variable disk -Force -ErrorAction SilentlyContinue


Log -Message "Generating report $FileName" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc

$DiskPolicyReport | select VM,Cluster,Datastore,Entity,Policy,Status,DateTime | export-csv $FileName -NoTypeInformation

Log -Message "Disconnecting from $VC" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc

Disconnect-VIServer -server $VC -Confirm:$false

Log -Message "Script Finished" -LogType "JOB-$RunDateTime" -LogFile $LogFileLoc