StorageUtility.psm1


##############################################################################
#
#.SYNOPSIS
# Get the Vms Disk foot print
#
#.DESCRIPTION
# Disk foot print is calculated below file which makes an VM
# Config files (.vmx, .vmxf, .vmsd, .nvram)
# Log files (.log)
# Disk files (.vmdk)
# Snapshots (delta.vmdk, .vmsn)
# Swapfile (.vswp)
#
# Get-View -VIObject centOs-1
# TypeName: VMware.Vim.VirtualMachineFileInfo

# FtMetadataDirectory Property string FtMetadataDirectory {get;set;}
# LogDirectory Property string LogDirectory {get;set;}
# SnapshotDirectory Property string SnapshotDirectory {get;set;}
# SuspendDirectory Property string SuspendDirectory {get;set;}
# VmPathName Property string VmPathName {get;set;}
#
#.PARAMETER vm
# VM Object returned by Get-VM cmdlet
#
#.EXAMPLE
# $vmSize = Get-VmDisksFootPrint($vm)
#
##############################################################################

Function Get-VmDisksFootPrint($vm) {
   #Initialize variables
   $VmDirs = @()
   $VmSize = 0
   $vmDsIdMap = @{}
   $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
   $searchSpec.details = New-Object VMware.Vim.FileQueryFlags
   $searchSpec.details.fileSize = $TRUE

   Get-View -VIObject $vm | % {
      #Populate the array with the vm's directories
      $VmDirs += $_.Config.Files.VmPathName.split("/")[0]
      $VmDirs += $_.Config.Files.SnapshotDirectory.split("/")[0]
      $VmDirs += $_.Config.Files.SuspendDirectory.split("/")[0]
      $VmDirs += $_.Config.Files.LogDirectory.split("/")[0]
      foreach ($dsMoref in $_.Datastore){
         $vmDsIdMap[(Get-Datastore -Id $dsMoref).Name] = $dsMoRef
      }
      #Add directories of the vm's virtual disk files
      foreach ($disk in $_.Layout.Disk) {
         foreach ($diskfile in $disk.diskfile) {
            $VmDirs += $diskfile.split("/")[0]
         }
      }

      #Only take unique array items
      $VmDirs = $VmDirs | Sort-Object | Get-Unique

      foreach ($dir in $VmDirs) {
         $datastoreObj = $vmDsIdMap[ ($dir.split("[")[1]).split("]")[0] ]
         $datastoreBrowser = Get-View (( Get-Datastore -Id $datastoreObj | get-view).Browser)
         $taskMoRef  = $datastoreBrowser.SearchDatastoreSubFolders_Task($dir,$searchSpec)
         $task = Get-View $taskMoRef
         while($task.Info.State -eq "running" -or $task.Info.State -eq "queued") {$task = Get-View $taskMoRef }
         foreach ($result in $task.Info.Result){
            foreach ($file in $result.File){
               $VmSize += $file.FileSize
            }
         }
      }
   }

   return $VmSize
}

##############################################################################
#
#.SYNOPSIS
# Get the ESX version of the Host
#
#.DESCRIPTION
# Return the ESX product version of the HostObjects supplied in parameter
#
#.PARAMETER EsxHosts
# Host Objects
#
#.EXAMPLE
# $HostObjects = Get-View -ViewType HostSystem
# $Hash = Get-HostVersion -EsxHosts $HostObjects
#
##############################################################################
Function Get-HostVersion {
   param([Object]$EsxHosts= "")
   $EsxHostVersion = @{}
   Foreach ($esx in $HostObjects) {
      $version = $esx.Config.Product.version
      $EsxHostVersion[$esx] = $version
   }

   return $EsxHostVersion
}

##################################################################################################################
#
#.SYNOPSIS
# Perform preflight check before proceeding with migration
#
#.DESCRIPTION
# Top level function calling respective preflight checks before proceeding
# with migration
#
#.PARAMETER Function
# Function to call
#
#.PARAMETER TargetObjects
# Target Object is being verified
#
#.PARAMETER ExpectedValue
# Attribute to verify
#
#.EXAMPLE
# PreFlightCheck -Function "CheckHostVersion" -TargetObjects $HostObjects -ExpectedValue $TargettedHostVersion
#
##################################################################################################################

Function PreFlightCheck {
   param(
      [parameter(Mandatory=$true)][string]$Function,
      [object]$TargetObjects,
      [object]$ExpectedValue
   )

   if(Get-Command $Function -ea SilentlyContinue) {
      #write-host $Function $TargetObjects $ExpectedValue
      & $Function $TargetObjects $ExpectedValue
   } else {
      # ignore
   }
}


##############################################################################
#.SYNOPSIS
# PreFLight check for ESX version
#
#.DESCRIPTION
# Function check the host version
#
#.PARAMETER HostObjects
# Target Object is being verified
#
#.PARAMETER Version
# Expected Version
#
#.EXAMPLE
# $status = CheckHostVersion -HostObjects $hostObject -Version $version
##############################################################################

Function CheckHostVersion {
   param(
      [parameter(Mandatory=$true)][object]$HostObjects,
      [String]$Version
   )

   $status = $true
   $targetVersion = New-Object System.Version($version)
   $Hash = Get-HostVersion -EsxHosts $HostObjects
   foreach ($host in $HostObjects) {
      $hostName = $host.Name
      $hostVersion = New-Object System.Version($host.Config.Product.version)
      if($hostVersion -ge $targetVersion) {
         $status = $status -And $true
         Format-output -Text "VM host $hostName is of version $hostVersion" -Level "SUCCESS" -Phase "Pre-Check"
      } else {
         $status = $status -And $false
         Format-output -Text "VM host $hostName is of version $hostVersion" -Level "ERROR" -Phase "Pre-Check"
      }
   }

   return $status
}

##############################################################################
#
#.SYNOPSIS
# Format the log messages
#
#.DESCRIPTION
# Format the log message printed on the screen
# Also redirect the message to a log file
#
#.PARAMETER
# Text - log message to be printed
# Level - SUCCESS,INFO,ERROR
# Phase - Different phase of commandlet, Preperation,Migration,Roll back
#
#
#.EXAMPLE
# Format-output -Text $MsgText -Level "INFO" -Phase "Migration Pre-Check phase"
#
##############################################################################

Function Format-output {
   param (
      [Parameter(Mandatory=$true)][string]$Text,
      [Parameter(Mandatory=$true)][string]$Level,
      [Parameter(Mandatory=$false)][string]$Phase
   )

   BEGIN {
      filter timestamp {"$(Get-Date -Format s) `[$Phase`] $Text" }
   }

   PROCESS {
      $Text | timestamp | Out-File -FilePath $global:LogFile -Append -Force
      if($Level -eq "SUCCESS" ) {
         $Text | timestamp | write-host -foregroundcolor "green"
      } elseif ( $Level -eq "INFO") {
         $Text | timestamp | write-host -foregroundcolor "yellow"
      } else {
         $Text | timestamp | write-host -foregroundcolor "red"
      }
   }
}

<#
.SYNOPSIS
    Wrapper Funtion to Call Storage Vmotion
.DESCRIPTION
    You may send a list of vm names
.PARAMETER VM
    Pass vmnames
.PARAMETER Destination
    PASS Destination datastore name
.PARAMETER Destination
    PASS ParallelTasks to perform
.INPUTS
.OUTPUTS
.EXAMPLE
    Storage-Vmotion -VM $vmlist -Destination 'Datastore_1' -ParallelTasks 2
#>

Function Concurrent-SvMotion {
   [CmdletBinding()]
   param (
      [Parameter(Mandatory = $true)][VMware.VimAutomation.ViCore.Util10.VersionedObjectImpl]$session,
      [Parameter(Mandatory = $true)][string[]]$VM,
      [Parameter(Mandatory = $true)][string]$SourceId,
      [Parameter(Mandatory = $true)][string]$DestinationId,
      [Parameter(Mandatory = $true)][int]$ParallelTasks
   )

   BEGIN {
       $TargetDatastoreId = $DestinationId
       $Date = get-date
       $VmsToMigrate = $VM
       $Failures = 0;
       $LoopCtrl = 1
       $VmInput = $VM
       $GB = 1024 * 1024 * 1024
       $BufferSize = 5
       $RelocateTaskList = @()
   }

   PROCESS {
      while ($LoopCtrl -gt 0) {
         $shiftedVm = shift -array ([ref]$vmInput) -numberOfElements $ParallelTasks
         $vmToMigrate = $shiftedVm
         $LoopCtrl = $vmInput.Count
         #Check the datastore contain sufficient space
         foreach ($TargetVm in $vmToMigrate) {
            $vm = Get-VM $TargetVm
            $vmSize += Get-VmDisksFootPrint $vm
         }
         $vmSize = [math]::Round(($vmSize / $GB) + $BufferSize)
         $tagetDatastoreObj = Get-Datastore -Id  $TargetDatastoreId
         if($tagetDatastoreObj.FreeSpaceGB -gt $vmSize) {
            $MsgText = "$TargetDatastore Contain FreeSpace of $($tagetDatastoreObj.FreeSpaceGB) GB to accomodate $vmToMigrate of size $vmSize GB"
            Format-output -Text $MsgText -Level "INFO" -Phase "Migration Pre-Check phase"
            $RelocateTaskList += Storage-Vmotion -session $session -Source $SourceId -VM $vmToMigrate -Destination $DestinationId
            # Iterate through has list of TaskMap and check for task failures
            foreach ($Task in $RelocateTaskList ) {
               if ( $Task["State"] -ne "Success" ) {
                  $Failure += 1
                  return $RelocateTaskList
               } else {
                  $Success += 1
               }
            }
         } else {
            #If insufficient datastore space just mark the migration task as failure
            $MsgText = "$TargetDatastore have insufficient space. FreeSpace of $($tagetDatastoreObj.FreeSpaceGB) GB to accomdate $vmToMigrate of size $vmSize GB"
            Format-output -Text $MsgText -Level "INFO" -Phase "Migration Pre-Check phase"
            $TaskMap = @{}
            $TaskMap["Name"] = $TargetVm
            $TaskMap["State"] = "Error"
            $TaskMap["Cause"] = "INSUFFICIENT_DATASTORE_SPACE"
            $RelocTaskList += $TaskMap
            return $RelocateTaskList
         }
      }
      return $RelocateTaskList
   }
}

Function MoveTheVM {
   [CmdletBinding()]
   param (
      [Parameter(Mandatory=$true)][VMware.VimAutomation.ViCore.Util10.VersionedObjectImpl]$session,
      [Parameter(Mandatory=$true)][String]$VM,
      [Parameter(Mandatory=$true)][string]$SourceId,
      [Parameter(Mandatory=$true)][string]$DestinationId
   )

   BEGIN {
      $vm = $VM
      $datastore = (Get-Datastore -id $SourceId)
      $tempdatastore = (Get-Datastore -id $DestinationId)
   }

   PROCESS {
      try {
         $vmName=Get-VM -Name $vm
         $vmId = $vmName.id
         $MsgText ="VM = $vm, Datastore = $datastore and Target datastore = $tempdatastore and id is $vmId"
         Format-output -Text $MsgText -Level "INFO" -Phase "VM migration"
         $hds = Get-HardDisk -VM $vm
         $spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
         $vmView=get-view -id $vmId
         if($vmView.Summary.Config.VmPathName.Contains($datastore)) {
            $spec.datastore = ($tempdatastore).Extensiondata.MoRef
         }

         $hds | %{
            if ($_.Filename.Contains($datastore)) {
               $disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
               $disk.diskId = $_.ExtensionData.Key
               $disk.datastore = ($tempdatastore).Extensiondata.MoRef
               $spec.disk += $disk
            } else {
               $extendedDs = $_.ExtensionData.Backing.Datastore
               $disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
               $disk.diskId = $_.ExtensionData.Key
               $disk.datastore = $extendedDs
               $spec.disk += $disk
              }
         }

         $task = $vmName.Extensiondata.RelocateVM_Task($spec, "defaultPriority")
         $task1 = Get-Task -server $session | where { $_.id -eq $task }
         return $task1
      } catch {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Moving Virtual Machines"
         Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move all the VMs from $Source to $Destination manually and then try again." -Level "Error" -Phase "Moving Virtual Machines"
         Return
      }
   }
}

########################################################################################################
#
#.SYNOPSIS
# Perform Concurrent Storage VMotion
#
#.DESCRIPTION
# Perform concurrent Migration based on no of Async task to run
# Continous DS space validation before migration
#
#.PARAMETER
# VM - List of VM names to Migrate
# Destination - Destination Datastore Names
# Return the TaskMap about VC migration task
#
#
#.EXAMPLE
# $RelocTaskList = Concurrent-SvMotion -VM $vmList -Destination $TemporaryDatastore -ParallelTasks 2
#
########################################################################################################

function Storage-Vmotion {
   [CmdletBinding()]
   param (
      [Parameter(Mandatory=$true)][VMware.VimAutomation.ViCore.Util10.VersionedObjectImpl]$session,
      [Parameter(Mandatory=$true)][string[]]$VM,
      [Parameter(Mandatory=$true)][string]$SourceId,
      [Parameter(Mandatory=$true)][string]$DestinationId
   )

   BEGIN {
      $TargetDatastoreId = $DestinationId
      $VmsToMigrate = $VM
      $RelocateTaskStatus = @()
      $Failures = 0
      $Success = 0
      $TaskTab = @{}
      $GB = 1024 * 1024 * 1024
   }

   PROCESS {
      foreach ($TargetVm in $VmsToMigrate) {
         $date = get-date
         Format-output -Text "$TargetVm : Migration is in progress From:$Source To:$TargetDatastoreId" -Level "INFO" -Phase "Migration"
         $task = MoveTheVM -VM $TargetVm -session $session -SourceId $SourceId -DestinationId $TargetDatastoreId
         $TaskTab[$task.id] = $TargetVm
      }

      # Get the status of running tasks
      $RunningTasks = $TaskTab.Count
      while($RunningTasks -gt 0) {
         Get-Task | % {
            if ($TaskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
               $TaskMap = @{}
               $Success += 1
               $TaskMap["Name"] = $TaskTab[$_.Id]
               $TaskMap["TaskId"] = $_.Id
               $TaskMap["StartTime"] = $_.StartTime
               $TaskMap["EndTime"] = $_.FinishTime
               $TaskMap["State"] = $_.State
               $TaskMap["Cause"] = ""
               $TaskTab.Remove($_.Id)
               $RunningTasks--
               $RelocateTaskStatus += $TaskMap
            } elseif ($TaskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
               $TaskMap = @{}
               $Failures += 1
               $TaskMap["Name"] = $TaskTab[$_.Id]
               $TaskMap["TaskId"] = $_.Id
               $TaskMap["StartTime"] = $_.StartTime
               $TaskMap["EndTime"] = $_.FinishTime
               $TaskMap["State"] = $_.State
               $TaskMap["Cause"] = ""
               $TaskTab.Remove($_.Id)
               $RunningTasks--
               $RelocateTaskStatus += $TaskMap
            }
         }

         Start-Sleep -Seconds 15
      }
   }

   END {
      Foreach ($Tasks in $RelocateTaskStatus) {
         if ($Tasks["State"] -eq "Success") {
            $MsgText = "Migration of $($Tasks["Name"]) is successful Start Time : $($Tasks["StartTime"]) End Time : $($Tasks["EndTime"])"
            Format-output -Text $MsgText -Level "SUCCESS" -Phase "Migration"
         } else {
            $MsgText = "Migration of $($Tasks["Name"]) is failure Start Time : $($Tasks["StartTime"]) End Time : $($Tasks["EndTime"])"
            Format-output -Text $MsgText -Level "FAILURE" -Phase "Migration"
         }
      }

      return  $RelocateTaskStatus
   }
}

##############################################################################
#
#.SYNOPSIS
# Function to shift an array
#
#.DESCRIPTION
# Perform shift action similar to Perl shift
#
#.PARAMETER
# array - Array to shift
# numberOfElements - No of elements to shift
# On success Orginal array is resized
#
#
#.EXAMPLE
#
# $shiftedVm = shift -array ([ref]$array) -numberOfElements 2
#
##############################################################################

Function shift {
   param (
      [Parameter(Mandatory=$true)][ref]$array,
      [Parameter(Mandatory=$true)][int]$numberOfElements
   )

   BEGIN {
      $shiftedValue = @()
      $temp = @()
      $temp = $array.Value
   }

   PROCESS {
      if ($temp.Count -ge $numberOfElements) {
         $Iterate =  $numberOfElements
      } else {
         $Iterate = $temp.Count
      }

      for ($i = $Iterate; $i -gt 0; $i -= 1) {
         $firstElement,$temp = $temp;
         $shiftedValue += $firstElement
      }
   }

   END {
      $array.value = $temp
      return $shiftedValue
   }
}

###############################################################################
#
#.SYNOPSIS
# Get the Items in a Datastore
#
#.DESCRIPTION
# Get the list of Items in a Datastore
#
#.PARAMETER
# Datastore - UUID/ID of the Datastore
#
#.EXAMPLE
# $list = Get-DataStoreItems -Datastore "local-0"
#
##############################################################################

Function Get-DataStoreItems {
   param(
      [Parameter(Mandatory=$true)][string]$DatastoreId,
      [Parameter()][Switch]$Recurse,
      [Parameter()][string]$fileType
   )

   $childItems = @()
   $datastoreObj = Get-Datastore -Id  $DatastoreId
   if ($Recurse) {
      $childItems = Get-ChildItem -Recurse $datastoreObj.DatastoreBrowserPath | Where-Object {$_.name.EndsWith($fileType)} 
   } else {
      $childItems = Get-ChildItem $datastoreObj.DatastoreBrowserPath | Where-Object {$_.name -notmatch "^[.]"}
   }

   return $childItems 
}

###################################################################################################
#
#.SYNOPSIS
# Copy files from Source to Desintation
#
#.DESCRIPTION
# Copy Orphaned files, not registered in VC
#
#.PARAMETER
# SourceDatastore - Source
# DestinationDatastore - Destination
#
#.EXAMPLE
# $Return Status = Copy-DatastoreItems -SourceDatastore "local-0" -DestinationDatastore "local-1"
#
###################################################################################################

Function Copy-DatastoreItems {
   param(
      [Parameter(Mandatory=$true)][string]$SourceDatastoreId,
      [Parameter(Mandatory=$true)][string]$DestinationDatastoreId
   )

   $copyOrphanPhase = "Copying Orphaned data"
   $SrcChildItems = @()
   $DstChildItems = @()
   $sourceDsObj = Get-Datastore -Id  $SourceDatastoreId
   $targetDsObj = Get-Datastore -Id  $DestinationDatastoreId

   #Map Drives
   try {
      $sourceDrive = new-psdrive -Location $sourceDsObj -Name sourcePsDrive -PSProvider VimDatastore -Root "/"
      $targetDrive = new-psdrive -Location $targetDsObj -Name targetPsDrive -PSProvider VimDatastore -Root "/"
      $SrcChildItems = Get-DataStoreItems -DatastoreId $SourceDatastoreId
      $DstChildItems = Get-DataStoreItems -DatastoreId $DestinationDatastoreId
      Format-output -Text "Copying Orphaned Items: $SrcChildItems" -Level "INFO" -Phase $copyOrphanPhase
      $Fileinfo = Copy-DatastoreItem -Recurse -Item sourcePsDrive:/* targetPsDrive:/ -Force
   } catch [Exception] {
      Remove-PSDrive -Name sourcePsDrive
      Remove-PSDrive -Name targetPsDrive
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase $copyOrphanPhase
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move all the orphaned data from $SourceDatastore to $DestinationDatastore manually and then try again." -Level "ERROR" -Phase $copyOrphanPhase
      Return $false
   }

   Remove-PSDrive -Name sourcePsDrive
   Remove-PSDrive -Name targetPsDrive
   Return $true
}

####################################################################################
#
#.SYNOPSIS
# Return Success or Failure list of Tasks
#
#.DESCRIPTION
# This Function checks through the list of Task and return a list of success or
# Failure tasks based on the input
#
#.PARAMETER
# RelocateTasksList = List containing the Relocate Task Map
#
#.EXAMPLE
# $SuccessTaskList=Get-RelocTask -RelocateTasksList $migrateTaskList -State "SUCCESS"
#
####################################################################################

Function Get-RelocTask {
   param (
      [Parameter(Mandatory=$true)][hashtable[]]$TasksList,
      [Parameter(Mandatory=$true)][string]$State
   )

   BEGIN {
      $SuccessList = @()
      $FailureList = @()
   }

   PROCESS {
      # Iterate through has list of TaskMap hash and check for task failures
      foreach ($Task in $TasksList ) {
         $NumberOfMigration += 1
         if ($Task["State"] -ne "Success") {
            $FailureList += $Task
         } else {
            $SuccessList += $Task
         }
      }
   }

   END {
      if ($State -eq "SUCCESS") {
         return $SuccessList
      } else {
         return $FailureList
      }
   }
}

####################################################################################
#.SYNOPSIS
# Creats Zip file with the log folder
#
#.PARAMETER
# $logdir = Log directory to zip/archive
#
#
#
####################################################################################
Function Zip-Logs {
   param([Parameter(Mandatory=$true)][string] $logdir)

   $sourceDir = Join-Path -Path $pwd -ChildPath $logdir
   $LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
   $destination = "$sourceDir" + "_" + "$LogTime.zip"
    If (Test-path $destination) {
      Remove-item $destination
   }

   Add-Type -assembly "system.io.compression.filesystem"
   [io.compression.zipfile]::CreateFromDirectory($sourceDir, $destination) 
    Format-output -Text "Zip file is available at: $destination" -Level "INFO" -Phase "Log Zip"
}


####################################################################################
#
#.SYNOPSIS
# Unmount the datastore
#
#.DESCRIPTION
# Unmount the datastore from all connected hosts
#
#.PARAMETER
# Datastore = Datastore to unmount
#
#.EXAMPLE
#
# Unmount-Datastore -Datastore "local-0"
#
####################################################################################

Function Unmount-Datastore {
   [CmdletBinding()]
   Param ([Parameter(ValueFromPipeline=$true)][string]$DatastoreId)

   BEGIN {
      $dsObject = Get-Datastore -Id $DatastoreId
   }

   Process {
      Foreach ($eachDsObj in $dsObject) {
         if ($eachDsObj.ExtensionData.Host) {
            $attachedHosts = $eachDsObj.ExtensionData.Host
            Foreach ($VMHost in $attachedHosts) {
               $hostview = Get-View $VMHost.Key
               $mounted = $VMHost.MountInfo.Mounted
               #If the device is mounted then unmount it
               if ($mounted -eq $true) {
                  $StorageSys = Get-View $HostView.ConfigManager.StorageSystem
                  Format-output -Text "Unmounting VMFS Datastore $($eachDsObj.Name) from host $($hostview.Name)..." -Level "INFO" -Phase "Unmount Datastore"
                  $StorageSys.UnmountVmfsVolume($eachDsObj.ExtensionData.Info.vmfs.uuid);
               } else {
                  Format-output -Text "VMFS Datastore $($eachDsObj.Name) is already unmounted on host $($hostview.Name)..." -Level "INFO" -Phase "Unmount Datastore"
               }
            }
         }
      }
   }
}

####################################################################################
#
#.SYNOPSIS
# Remove a datastore
#
#.DESCRIPTION
# Remove a datastore
#
#.PARAMETER
# Datastore = Datastore to delete
#
#.EXAMPLE
#
# Delete-Datastore -Datastore "local-0"
#
####################################################################################

Function Delete-Datastore {
   [CmdletBinding()]
   Param (
      [Parameter(ValueFromPipeline=$true)] [string]$DatastoreId
   )

   BEGIN {
      $dsObjectList = Get-Datastore -Id $DatastoreId
   }

   Process {
      Foreach ($eachDsObj in $dsObjectList) {
         if ($eachDsObj.ExtensionData.Host) {
            $attachedHosts = $ds.ExtensionData.Host
            $deleted = $false
            Foreach ($VMHost in $attachedHosts) {
               $hostview = Get-View $VMHost.Key
               if($deleted -eq $false) {
                  Format-output -Text "Removing Datastore $($eachDsObj.Name) on host $($hostview.Name)..." -Level "INFO" -Phase "Delete Datastore"
                  Remove-Datastore -Datastore (Get-Datastore -Id $DatastoreId) -VMHost $hostview.Name -Confirm:$false
                  $deleted = $true
               }
            }
         }
      }
   }
}

####################################################################################
#
#.SYNOPSIS
# Create a Vmfs6 datastore
#
#.DESCRIPTION
# Create a New Vmfs6 volume on the give Lun a datastore
#
#.PARAMETER
# LunCanonical = Canonical name of lun
# hostConnected = Hostobjects
#
#.EXAMPLE
#
# $LunCanonical = Get-ScsiLun -Datastore $Datastore | select -Property CanonicalName
# $hostConnected = Get-VMHost -Datastore $Datastore
# Create-Datastore -LunCanonical $LunCanonical -hostConnected $hostConnected
#
#
####################################################################################

Function Create-Datastore {
   [CmdletBinding()]
   Param (
      [Parameter(ValueFromPipeline=$true)] $LunCanonical,
      [Parameter(ValueFromPipeline=$true)] $hostConnected
   )

   Process {
      $device = $LunCanonical
      $isCreated = $false
      $found = $True
      $DatastoreId = 0
      #check if the Datastore is still mounted or not in a busy vCenter
      $cliXmlPath = Join-Path -Path $variableFolder -ChildPath ("Vmfs6Datastore" + ".xml")
      if (Test-Path $cliXmlPath) {
         $newVmfs6Datastore = Import-Clixml $cliXmlPath
         $DatastoreId = Get-Datastore -Id  $newVmfs6Datastore.Id
         $fileSystemVersion = $DatastoreId.FileSystemVersion.split('.')[0]
      }

      $fileSystemVersion  = $Datastore.FileSystemVersion.split('.')[0]
      while ($found -and ($fileSystemVersion -eq 5)) {
         $srcDs = @()
         $srcDs  += Get-Datastore
         if (!$srcDs.contains($Datastore)) {
            $found = $False
         }
      }
      $hostScsiDisk = @()
      foreach ($mgdHost in $hostConnected) {
         $path = $null
         if ($isCreated -eq $false) { 
            if ($device -is [System.Array]) { 
               $path = $device[0]
            } else {
               $path = $device
            }

            if ($fileSystemVersion -lt 6) {
               New-Datastore -VMHost $mgdHost.Name  -Name $Datastore.Name -Path $path -Vmfs -FileSystemVersion $TargetVmfsVersion | Out-Null
               Format-output -Text "Create new datastore is done" -Level "INFO" -Phase "Datastore Create"
               #$newVmfs6Datastore | Export-Clixml $cliXmlPath
               # query the newly created datastore from the mgdHost
               $newVmfs6Datastore = Get-Datastore  -VMHost $mgdHost.Name|where{ $_.name -eq $Datastore.Name }
               $DatastoreId = $newVmfs6Datastore.Id
               $newVmfs6Datastore | Export-Clixml $cliXmlPath
            }

            # if we have more than one unique $device per datastore, we need to expand the current DS.
            if ($device.Count -gt 1) {
               $newDatastoreObj = Get-Datastore -Id $DatastoreId -ErrorAction SilentlyContinue
               $BaseExtent = $newDatastoreObj.ExtensionData.Info.Vmfs.Extent | Select -ExpandProperty DiskName
               $hostSys = Get-View -Id ($newDatastoreObj.ExtensionData.Host | Get-Random | Select -ExpandProperty Key)
               $DataStoreSys = Get-View -Id $hostSys.ConfigManager.DatastoreSystem
               $hostScsiDisk = $DataStoreSys.QueryAvailableDisksForVmfs($newDatastoreObj.ExtensionData.MoRef)
               $existingLuns = Get-ScsiLun -Datastore $newDatastoreObj |select -ExpandProperty CanonicalName|select -Unique
               $newDevList = Compare-Object  $device $existingLuns -PassThru
               foreach ($eachDevice in $newDevList) {
                  # expand the datastore.
                  $canName = Get-ScsiLun -CanonicalName $eachDevice -VmHost $mgdHost
                  $lun = $hostScsiDisk | where{ $BaseExtent -notcontains $_.CanonicalName -and $_.CanonicalName -eq $CanName }
                  $vmfsExtendOpts = $DataStoreSys.QueryVmfsDatastoreExtendOptions($newDatastoreObj.ExtensionData.MoRef, $lun.DevicePath, $null)
                     $spec = $vmfsExtendOpts.Spec
                  $DataStoreSys.ExtendVmfsDatastore($newDatastoreObj.ExtensionData.MoRef, $spec)
                  Format-output -Text "Extending of datastore is done" -Level "INFO" -Phase "Extend Datastore"
               }
            }
            $isCreated = $true
         }

         #refresh storage on this host and see if the datastore created can be fetched from $mdgHost.
         $mgdHostDatastores = Get-Datastore -VMHost $mgdHost.Name
         if($mgdHostDatastores -contains $DatastoreId ){
            Format-output -Text "The datastore $Datastore found on host: $mgdHost " -Level "INFO" -Phase "VMFS6 Verify"
         }
      }
   }
}

#.ExternalHelp StorageUtility.psm1-help.xml
Function Update-VmfsDatastore {
   [CmdletBinding(SupportsShouldProcess=$true,  ConfirmImpact='High')]
   param (
      [Parameter(Mandatory=$true)][VMware.VimAutomation.ViCore.Types.V1.VIServer]$Server,
      [Parameter(Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore]$Datastore,
      [Parameter(Mandatory=$true)][VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore]$TemporaryDatastore,
      [Parameter()][Int32]$TargetVmfsVersion,
      [Switch]$Rollback,
      [Switch]$Resume,
      [Switch]$Force
   )

   $variableFolder = "log_folder_$($Server.Name)_$($Datastore.Name)"
   if(!(Test-Path $variableFolder)) {
      New-Item -ItemType directory -Path $variableFolder | Out-Null
   }

   #check point saved for each stage
   $checkFile = "check$($Server.Name)$($Datastore.Name)"
   $LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
   $workingDirectory = (Get-Item -Path $variableFolder -Verbose).FullName
   $logFileName = "Datastore_Upgrade_" + $LogTime + ".log"
   $global:LogFile = Join-Path $workingDirectory $logFileName
   Format-output -Text "Log folder path: $workingDirectory" -Level "INFO" -Phase  "Preparation"
   Format-output -Text "Log file path: $global:LogFile" -Level "INFO" -Phase  "Preparation"
   Format-output -Text "Checkpoint file path: $checkFile" -Level "INFO" -Phase  "Preparation"
   $caption = "WARNING !!"
   $warning = "Update VMFS datastore. This operation will delete the datastore to update and will re-create the VMFS 6 datastore using the same LUN. Do yo want to continue?"
   $description = "This operation will delete the datastore to update and will re-create the VMFS 6 datastore using the same LUN."
   Format-output -Text "The datastore $Datastore will deleted and Recreated with VMFS-6." -Level "ERROR" -Phase "Preparation"
   if ($PSCmdlet.ShouldProcess($description, $warning, $caption) -eq $false) {
      Return
   }

   # Check if HBR or SRM is enabled
   $warningCaption = "WARNING !!"
   $warningQuery = "The update to VMFS-6 of VMFS-5 datastore should not be done if HBR or SRM is enabled. Do you still want to continue?"
   Format-output -Text "The datastore $Datastore Should not be part of HBR[Target/Source] / SRM config." -Level "ERROR" -Phase "Preparation"
   if (($Force -Or $PSCmdlet.ShouldContinue($warningQuery, $warningCaption)) -eq $false) {
      Return
   }

   #Workflow begins here

   # Check that target VMFS version is 6. only 6 is supported at present
   if ($TargetVmfsVersion -eq 0 -or $TargetVmfsVersion -ne 6) {
      Format-output -Text "Update to target VMFS version $TargetVmfsVersion is not supported. Only VMFS 6 is supported as target VMFS version" -Level "ERROR" -Phase "Preparation"
      Return
   }

   #Check PrimaryDatastore is present in the Datastore list from VC
   $PrimaryDsStaus = Get-Datastore |where { $_ -eq $Datastore}
   $DatastoreName = $null
   if ($PrimaryDsStaus -ne $null) {
      $PrimaryDatastore = Get-Datastore -Id $Datastore.Id
      if ($PrimaryDatastore -eq $null) {
         Format-output -Text "The datastore $Datastore does not exist or has been removed." -Level "ERROR" -Phase "Preparation"
         Return
      }
      $Datastore | Export-Clixml (Join-Path $variableFolder 'PrimaryDs.xml')
   }

   # Verify thet the specified server is vCenter server
   if (-not $server.ExtensionData.Content.About.Name.Contains("vCenter")) {
      Format-output -Text "The specified server is not a vCenter server." -Level "ERROR" -Phase "Preparation"
      Return
   }

   # Verify the vCenter server is of $targetServerVersion or higher
   $targetServerVersion = New-Object System.Version("6.5.0")
   $vcVersion = New-Object System.Version($Server.Version)
   if ($vcVersion -lt $targetServerVersion) {
      Format-output -Text "The vCenter server is not upgraded to $targetServerVersion." -Level "ERROR" -Phase "Preflight Check"
      Return
   }

   # Verify that $PrimaryDatastore and $TemporaryDatastore are in specified vCenter server
   if ($PrimaryDsStaus -ne $null) {
      $ds = Get-Datastore -Id  $PrimaryDatastore.Id -Server $Server
      if ($ds -eq $null -Or $ds.Uid -ne $PrimaryDatastore.Uid) {
         Format-output -Text "The datastore $PrimaryDatastore is not present in specified vCenter $Server." -Level "ERROR" -Phase "Preflight Check"
         Return
      }
   }
   $tempDs = Get-Datastore -Id  $TemporaryDatastore.Id -Server $Server
   if ($tempDs -eq $null -Or $tempDs.Uid -ne $TemporaryDatastore.Uid) {
      Format-output -Text "The temporary datastore $TemporaryDatastore is not present in specified vCenter $Server." -Level "ERROR" -Phase "Preflight Check"
      Return
   }

   $precheck = $null
   if ( $Resume ) {
      $precheckXml = Join-Path $variableFolder 'precheck.xml'
      if ( Test-Path $precheckXml){
         $precheck = Import-Clixml $precheckXml
      }
   }

   if ( $precheck -ne 'Done' ) {
      #Verify if first class disks are present in the primary datastore
      $vdisk = Get-VDisk -Datastore $PrimaryDatastore
      if ($vdisk -ne $null) {
         $msgText = "FCD disks can't be moved. Please migrate them then start the commandlet again."
         Format-output -Text "$msg1" -Level "ERROR" -Phase "Preflight Check"
         Return
      }

      #Verify if the Host connected to Primary datastore is part of HA
      $cluster = Get-VMHost -Datastore $PrimaryDatastore | Get-Cluster
      if($cluster) {
         if($cluster.HAEnabled){
            $msg1 = "The host connected to datastore $PrimaryDatastore is part of HA cluster"
            Format-output -Text "$msg1" -Level "INFO" -Phase "Preflight Check"
         }
      }

      # Verify that VADP is disable. If enabled quit
      Format-output -Text "checking if VADP is enabled on any of the VMs" -Level "INFO" -Phase "Preflight Check"
      if ($PrimaryDsStaus -ne $null) {
         $vmList = Get-VM -Datastore $PrimaryDatastore
         Format-output -Text "Checking for VADP enabled VM(s)" -Level "INFO" -Phase "Preflight Check"
         foreach ($vm in $vmList) {
            $disabledMethods = $vm.ExtensionData.DisabledMethod
            if ($disabledMethods -contains 'RelocateVM_Task') {
               Format-output -Text "Cannot move virtual machine $vm because migration is disabled on it." -Level "ERROR" -Phase "Preflight Check"
               Return
            }
         }

         # Verify that SMPFT is not turned ON
         Format-output -Text "checking if SMPFT is enabled on any of the VMs" -Level "INFO" -Phase "Preflight Check"
         foreach ($vm in $vmList) {
            $vmRuntime = $vm.ExtensionData.Runtime
            if ($vmRuntime -ne $null -and $vmRuntime.FaultToleranceState -ne 'notConfigured') {
               Format-output -Text "Cannot move VM $vm because FT is configured for this VM." -Level "ERROR" -Phase "Preflight Check"
               Return
            }
         }
         $precheck = 'Done'
         $precheck | Export-CliXml (Join-Path $variableFolder 'precheck.xml')
      }

      #If PrimaryDs is part of DsCluster the TempDs should be part of same DsCluster
      if( !$Resume ) {
         $primeDsCluster = Get-DatastoreCluster -Datastore $PrimaryDatastore
         $tempDsCluster  = Get-DatastoreCluster -Datastore $TemporaryDatastore
      }
      if (($primeDsCluster -ne $tempDsCluster) -and !$Resume) {
         Format-output -Text "Both Primary/Source Datastore and Temparory Datastore should be part of same sDrs-Cluster : $primeDsCluster" -Level "ERROR" -Phase "Preflight Check"
         Return
      }

      # Verify MSCS, Oracle cluster is not enabled
      Format-output -Text "checking if MSCS/Oracle[RAC] Cluster is configured on any of the VMs" -Level "INFO" -Phase "Preflight Check"
      if ($vmList -ne $null){
         $hdList = Get-HardDisk -VM $vmList
         foreach ($hd in $hdList) {
            if ($hd.ExtensionData.Backing.Sharing -eq 'sharingMultiWriter') {
               $vm = $hd.Parent
               $msg1= "The disk:$hd is in Sharing mode -Multi-writer flag is on. The virtual machine:$vm may be part of a cluster"
               $msg2= "If you want to proceed please disable the cluster settings on VM and -Resume again."
               Format-output -Text "$msg1, $msg2" -Level "ERROR" -Phase "Preflight Check"
               Return
            } else {
               $scsiController = Get-ScsiController -HardDisk $hd
               if (($scsiController.UnitNumber -ge 1) -and ($scsiController.BusSharingMode -ne 'NoSharing')) {
                  $msg1= "The scsi controller:$scsiController attached to the $vm is in sharing mode and hence the VM cannot be migrated. The VM may be part of a cluster"
                  $msg2= "If you want to proceed please disable the cluster settings on VM and -Resume again."
                  Format-output -Text "$msg1,$msg2" -Level "ERROR" -Phase "Preflight Check"
                  Return
               }
            }
         }
      }
   }

   $ErrorActionPreference = "stop"
   $checkCompleted = $null
   $ImportPrimeDs = Import-Clixml (Join-Path $variableFolder 'PrimaryDs.xml')
   $DatastoreName = Get-Datastore -Id $ImportPrimeDs.Id
   $RollBackOption = $Rollback
   if($RollBackOption -eq $true -and $Resume -eq $true) {
      write-host "Both Resume and Staging-rollback cannot be true at the same time. Returning.."
      Return
   }

   if ($Resume -eq $true -or $RollBackOption -eq $true) {
      if (Test-Path $checkFile) {
         $checkCompleted = get-content $checkFile
         $checkCompleted = $checkCompleted -as [int]
         if ($checkCompleted -eq $null -and $Resume -eq $True) {
            $datastoreFsVersion = (Get-Datastore -Id  $DatastoreName.id).FileSystemVersion.split('.')[0]
            if($datastoreFsVersion -eq 6) {
               # In case post vmfs update, if the checkpoint get corrupted then cmdlet can't proceed futher.
               Format-output -Text "Datastore is of VMFS-6 type and " -Level "ERROR" -Phase "Resume-Post Update" 
               Format-output -Text "check-point file is corrupted so cannot proceed further. Manually move back the contents from Temporary Datastore " -Level "ERROR" -Phase "Resume-Post Update" 
               Return
            }
            Format-output -Text "check-point file is corrupted/not found, proceeds from beginning" -Level "INFO" -Phase "Preparation" 
         }
      } elseif ($RollBackOption -eq $false) {
         $datastoreFsVersion = (Get-Datastore -Id  $DatastoreName.id).FileSystemVersion.split('.')[0]
         if ($datastoreFsVersion -eq 6 -and $Resume -eq $true) {
            # In case post vmfs update, if the checkpoint file removed then cmdlet can't proceed futher.
            # If checkpoint file is missing post vmfs update cmdlet don't know the progress, so throw error
            Format-output -Text "Datastore is of VMFS-6 type and " -Level "ERROR" -Phase "Resume-Post Update" 
            Format-output -Text "check-point file is not available so cannot proceed further. Manually move back the contents from Temporary Datastore " -Level "ERROR" -Phase "Resume-Post Update" 
            Return
         } 

         #pre vmfs6 update proceed the resume from beginning
         $checkCompleted = 0
         Format-output -Text "Writing checkCompleted : $checkCompleted" -Level "INFO" -Phase "Preparation"
         $checkCompleted | out-file $checkFile
      }
   } else {
      $checkCompleted = 0
      $checkCompleted | out-file $checkFile
   }

   if ($RollBackOption -eq $true) {
      if($checkCompleted -eq $null){
         Format-output -Text "check-point file is corrupted/not found cannot roll back. Manually move back the contents from Temporary Datastore " -Level "ERROR" -Phase "Roll Back" 
         Return
      } elseif ($checkCompleted -lt 5) {
         $msgText = "No action performed previously to Roll back, Rollback is not needed"
         Format-output -Text $msgText -Level "INFO" -Phase "Roll-back"
         Return
      }

      $checkCompleted = $checkCompleted + 1
      $dsCheck = Get-Datastore -Id $DatastoreName.Id
      if ($dsCheck.Type.Equals('VMFS')) {
         if (($dsCheck.FileSystemVersion).split('.')[0] -eq 6) {
            $msgText1 = "Datastore is upgraded to VMFS6.Upgrade is in post-upgrade stage,can not rollback. Returning"
            $msgText2 = "At this stage only -Resume is allowed"
            Format-output -Text "$msgText1, $msgText2" -Level "Error" -Phase "Pre-Roll Back Check"
            Return
         }
      } else {
         $msgText = "Datastore to upgrade is not of VMFS type. Returning."
         Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
         Return
      }

      if ($checkCompleted -ge 9) {
         $msgText = "Moving VMs back to original datastore, if present."
         Format-output -Text $msgText -Level "INFO" -Phase "VM Migration"
         $vmList = @()
         $vms = Get-Datastore -Id $TemporaryDatastore.Id | Get-VM

         try {
            if ($vms.Count -gt 0) {
               $RelocTaskList = Concurrent-SvMotion -session $Server -SourceId $TemporaryDatastore.Id -VM $vms -DestinationId $DatastoreName.Id -ParallelTasks 2
               foreach ($eachTask in $RelocTaskList) {
                  if ($eachTask["State"] -ne "Success") { 
                     Format-output -Text "VM failed to Migrate try running the commandlet again with -Resume option." -Level "Error" -Phase "VM Migration"
                     Return
                  }
               }
            }
         } catch {
            $errName = $_.Exception.GetType().FullName
            $errMsg = $_.Exception.Message
            Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Moving Vms during Rollback."
            Format-output -Text "Unable to proceed, try running the commandlet again. If problem persists, move all the VMs from $TemporaryDataStore to $DatastoreName manually and then try again." -Level "ERROR" -Phase "Moving VMs during rollback."
            Return
         }
      }

      if ($checkCompleted -ge 11) {
         $msgText = "Moving orphaned data back to original datastore, if present"
         Format-output -Text $msgText -Level "INFO" -Phase "Roll-back Orphan data"
         try {
            $dsItems = Get-DataStoreItems -DatastoreId $TemporaryDatastore.id
            if (($dsItems -ne $null) -and ($dsItems.Count) -gt 0 ) {
               Format-output -Text "Moving Orphaned items to $DatastoreName" -Level "INFO" -Phase "Copying Orphaned Items"
               Format-output -Text "all the contents already available in $DatastoreName; so skip copy from $TemporaryDatastore" -Level "INFO" -Phase "Copying Orphaned Items"
            }

            #Register template VM[s] back in respective hosts.
            $SrcTemplateMapXml = Join-Path $variableFolder 'SrcTemplateMap.xml'
            if (Test-Path SrcTemplateMapFilepath) {
               $SrcTemplateMap = Import-Clixml $SrcTemplateMapXml
               foreach ($templatePath in $SrcTemplateMap.Keys) {
                  try {
                     $register = New-Template ï¿½VMHost $SrcTemplateMap[$templatePath] -TemplateFilePath $templatePath
                     $esxHost= $SrcTemplateMap[$templatePath]
                     Format-output -Text "Template VM registered in host $esxHost " -Level "INFO" -Phase "Template Register" 
                  } catch {
                     $errName = $_.Exception.GetType().FullName
                     if ($errName -match  "AlreadyExists") {
                        Format-output -Text "$templatePath :Template already registered" -Level "INFO" -Phase "Template Register"
                     }
                  }
               }
            } 
         } catch {
            $errName = $_.Exception.GetType().FullName
            $errMsg = $_.Exception.Message
            Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Moving orphaned data"
            Format-output -Text "Unable to proceed, try running the commandlet again. If problem persists, move all the orphaned data from $TemporaryDataStore to $DatastoreName manually and then try again." -Level "ERROR" -Phase "Moving orphaned data."
            Return
         }
      }

      if ($checkCompleted -ge 8) {
         $msgText = "Changing back datastore cluster properties to previous State."
         Format-output -Text $msgText -Level "INFO" -Phase "SDRS Cluster"
         $sdrsClusterXml = Join-Path $variableFolder 'sdrsCluster.xml'
         if (Test-Path $sdrsClusterXml) {
            $dsCluster =  Import-CliXml $sdrsClusterXml
            if ($dsCluster.Name -ne $null) {
               $datastorecluster = Get-DatastoreCluster -Name $dsCluster.Name
            }
         }

         $oldAutomationLevelXml = Join-Path $variableFolder 'oldAutomationLevel.xml'
         if (Test-Path $oldAutomationLevelXml) {
            $oldAutomationLevel = Import-CliXml $oldAutomationLevelXml
         }

         $ioloadbalancedXml = Join-Path $variableFolder 'ioloadbalanced.xml'
         if (Test-Path $ioloadbalancedXml) {
            $ioloadbalanced = Import-CliXml $ioloadbalancedXml
         }

         if ($oldAutomationLevel) {
            Set-DatastoreCluster -DatastoreCluster $datastorecluster -SdrsAutomationLevel $oldAutomationLevel | Out-Null
         }

         if ($ioloadbalanced) {
            Set-DatastoreCluster -DatastoreCluster $datastorecluster -IOLoadBalanceEnabled $ioloadbalanced | Out-Null
         }
      }

      if ($checkCompleted -ge 7) {
         $msgText = "Changing datastore properties to previous State"
         Format-output -Text $msgText -Level "INFO" -Phase "StorageIOControl"

         $ds1iocontrolXml = Join-Path $variableFolder 'ds1iocontrol.xml'
         if (Test-Path $ds1iocontrolXml) {
            $ds1iocontrol = Import-CliXml $ds1iocontrolXml
         }

         $ds2iocontrolXml = Join-Path $variableFolder 'ds2iocontrol.xml'
         if (Test-Path $ds2iocontrolXml) {
            $ds2iocontrol = Import-CliXml $ds2iocontrolXml
         }

         if ($ds1iocontrol) {
            (Get-Datastore -Id  $DatastoreName.Id) | set-datastore -storageIOControlEnabled $ds1iocontrol | Out-Null
         }

         if ($ds2iocontrol) {
            (Get-Datastore -Id  $TemporaryDatastore.Id) | set-datastore -storageIOControlEnable $ds2iocontrol | Out-Null
         }
      }

      if ($checkCompleted -ge 6) {
         $msgText = "Changing cluster properties to previous State"
         Format-output -Text $msgText -Level "INFO" -Phase "Cluster properties"
         $drsMapXml = Join-Path $variableFolder 'drsMap.xml'
         if (Test-Path $drsMapXml) {
            $drsMap = Import-CliXml $drsMapXml
         }

         $clustersXml = Join-Path $variableFolder 'clusters.xml'
         if (Test-Path $clustersXml) {
            $tempClus = Import-CliXml $Set-DatastoreClusterXml
            if ($tempClus.Name -ne $null) {
               $clusters = Get-Cluster -Id $tempClus.Id
            }
         }

         if ($clusters -and $drsMap) {
            foreach ($clus in $clusters) {
               Set-Cluster -Cluster $clus -DrsAutomationLevel $drsMap[$clus.Id] -Confirm:$false | Out-Null
            }
         }
      }

      Format-output -Text "Rollback completed successfully" -Level "INFO" -Phase "Rollback successful"
      Zip-Logs -logdir $variableFolder
      Remove-Item $variableFolder -recurse
      Remove-Item $checkFile
      $errorActionPreference = 'continue'
      Return
   }

   #check 1
   $tempDsItems = Get-DataStoreItems -DatastoreId  $TemporaryDatastore.Id
   try {
      if ($checkCompleted -lt 1) {
         if ($tempDsItems -ne $null -and !$RollBackOption -and !$Resume) {
            Format-output -Text "$TemporaryDatastore is not Empty:$tempDsItems this operation could cause damage to files in $TemporaryDatastore. Returning" -Level "Error" -Phase "Querying Temporary datastore"
            Return
         }

         $checkCompleted = 1
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Querying Temporary datastore"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Querying Temporary datastore"
      Return
   }

   # check 2
   # Check if hosts connected to DS are upgraded
   try {
      if ($checkCompleted -lt 2) {
         $hostConnectedToDs = Get-VMHost -Datastore $Datastore
         $hostObjects = Get-View -VIObject $hostConnectedToDs
         $status = CheckHostVersion -HostObjects $hostObjects -Version $targetServerVersion
         if ($status -eq $false) {
            Format-output -Text "Hosts are not upgraded to $targetServerVersion. Returning " -Level "INFO" -Phase "Preflight Check"
            Return
         }

         # All hosts connected to DS should be also connected to temp DS
         $hostConnectedToTempDs = Get-VMHost -Datastore $TemporaryDatastore
         Format-output -Text "checking if the Target Datastore is accessbile to all the Hosts, as of Source" -Level "INFO" -Phase "Preflight Check"
         if (Compare-Object $hostConnectedToDs $hostConnectedToTempDs -PassThru) {
            $msg1= "Temporary datastore $TemporaryDatstore is not accessible from one or more host(s)"
            $msg2= "Ensure the Hosts connected to Source and Temporary Datastores are same."
            Format-output -Text "$msg1,$msg2" -Level "ERROR" -Phase "Preflight Check" 
            Return
         }

         $checkCompleted = 2
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Querying Hosts"
      $msg1= "Unable to proceed, try running the commandlet again with -Resume option"
      $msg2= "Or Source datastore might be re-created with VMFS-6 filesystem"
      Format-output -Text "$msg1, $msg2" -Level "Error" -Phase "Querying Hosts"
      Return
   }

   # Check if the Temporary DS size is >= Size of DS requiring Vmfs6 upgrade
   $tmpDs = $TemporaryDatastore
   $tmpDsSize = [math]::Round($tmpDs.CapacityMB)

   # Check 3
   try {
      if ($checkCompleted -lt 3) {
         if ($tmpDs.Type.Equals('VMFS')) {
            Format-output -Text "checking if Temporary Datastore is of VMFS-5 type" -Level "INFO" -Phase "Preflight Check"
            if ($tmpDs.FileSystemVersion -lt 6 -and $tmpDs.FileSystemVersion -gt 4.999) {
               $msgText = "$TemporaryDatastore is of VMFS 5 type"
               Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
            } else {
               $msgText = "$TemporaryDatastore is not of VMFS 5 type, Returning."
               Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
               Return
            }
         } else {
            $msgText = "$TemporaryDatastore is not of VMFS 5 type, Returning.."
            Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
            Return
         }

         $checkCompleted = 3
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Querying Temporary datastore"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Querying Temporary datastore"
      Return
   }

   # Check 4
   try {
      if ($checkCompleted -lt 4){
         $datastoreObj1 = Get-Datastore -Id  $DatastoreName.Id
         $dsSize = [math]::Round($datastoreObj1.CapacityMB)
         Format-output -Text "checking Datastores capacity" -Level "INFO" -Phase "Preflight Check"
         if ($tmpDsSize -ge $dsSize) {
            $msgText = "$TemporaryDatastore having Capacity : $tmpDsSize MB Greater or Equal than $DatastoreName capacity : $dsSize MB"
            Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
         } else {
            $msgText = "$TemporaryDatastore having Capacity : $tmpDsSize MB lesser than $DatastoreName capacity : $dsSize MB. Returning.."
            Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
            Return
         }
         $checkCompleted = 4
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Querying Temporary datastore"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Querying Temporary datastore"
      Return
   }

   $RelocTaskList = @()
   $RelocTaskList1 = @()
   $esxMap = @{}
   $esxUser = @{}
   $esxPass = @{}
   $esxLoc = @{}
   $countesx=0
   #check 5
   try {
      if ($checkCompleted -lt 5) {
         $dsCheck = Get-Datastore -Id  $DatastoreName.Id
         if ($dsCheck.Type.Equals('VMFS')) {
            if ($dsCheck.FileSystemVersion -lt 6 -and $dsCheck.FileSystemVersion -gt 4.999) {
               $msgText = "$DatastoreName to upgrade is of VMFS 5 type"
               Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
            } else {
               $msgText = "$DatastoreName to upgrade is not of VMFS 5 type, Returning."
               Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
               Return
            }
         } else {
            $msgText = "$DatastoreName to upgrade is not of VMFS 5 type, Returning.."
            Format-output -Text $msgText -Level "INFO" -Phase "Preflight Check"
            Return
         }
         $checkCompleted = 5
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Querying datastore version"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Querying datastore version"
      Return
   }

   # Setting DRS automation level to manual of cluster.
   $drsAutoLevel = $null
   try {
      # $dsCluster = Get-Datastore -IdCluster -datastore $DatastoreName
      $drsMap = @{}
      $clusters = @()
      # check 6
      if ($checkCompleted -lt 6) {
         #$clusters=get-cluster
         $clusters = Get-Datastore -Id $DatastoreName.Id |Get-VMHost|Get-Cluster
         $datastoreCluster = Get-DatastoreCluster -datastore $DatastoreName
         $msgText = "Changing DrsAutomationLevel of clusters to manual. Will be reverted to original once operation is completed."
         foreach ($clus in $clusters) {
            $drsMap[$clus.Id]=$clus.DrsAutomationLevel
         }
         if ($drsMap -ne $null) {
            $drsMap | Export-CliXml (Join-Path $variableFolder 'drsMap.xml')
         }
         if ($datastoreCluster-ne $null) {
            $datastoreCluster | Export-CliXml (Join-Path $variableFolder 'sdrsCluster.xml')
         }
         if ($clusters -ne $null) {
            $clusters | Export-CliXml (Join-Path $variableFolder 'clusters.xml')
         }
         foreach ($clus in $clusters) {
            if ($clus.DrsEnabled) {
               Format-output -Text $msgText -Level "INFO" -Phase "DRS Cluster Settings"
               Set-Cluster -Cluster $clus -DrsAutomationLevel Manual -confirm:$false | Out-Null
            }
         }
         $checkCompleted = 6
         $checkCompleted | out-file $checkFile
      } else {
         $drsMapXml = Join-Path $variableFolder 'drsMap.xml'
         if (Test-Path $drsMapXml) {
            $drsMap = Import-CliXml $drsMapXml
         } else {
            Format-output -Text "Unable to find the configuration files no changes done to DRS cluster." -Level "INFO" -Phase "Querying DRS"
         }

         $sdrsClusterXml = Join-Path $variableFolder 'sdrsCluster.xml'
         if (Test-Path $sdrsClusterXml) {
            $datastoreCluster = Import-CliXml $sdrsClusterXml
         } else {
            Format-output -Text "Unable to find the configuration files no changes will be done SDRS cluster." -Level "INFO" -Phase "Querying SDRS"
         }

         $clustersXml = Join-Path $variableFolder 'clusters.xml'
         if (Test-Path $clustersXml) {
            $tempClus = Import-CliXml $clustersXml
            if ($tempClus.Name -ne $null) {
               $clusters = get-cluster -Id $tempClus.Id
            }
         } else {
            Format-output -Text "Unable to find the DRS and SDRS configuration files, No action will be take on these clusters." -Level "INFO" -Phase "Querying DRS and SDRS config"
         }
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Capturing settings."
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Capturing settings."
   }

   #check 7 : getting and setting storageIOControlEnabled
   $ds1iocontrol = $false
   $ds2iocontrol = $false
   try {
      if ($checkCompleted -lt 7) {
         $msgText = "Changing storageIOControlEnabled to false. It will be reverted to original once operation is complete."
         $ds1iocontrol=(Get-Datastore -Id $DatastoreName.Id).StorageIOControlEnabled
         $ds2iocontrol=(Get-Datastore -Id $TemporaryDatastore.Id).StorageIOControlEnabled
         $ds1iocontrol | Export-CliXml (Join-Path $variableFolder 'ds1iocontrol.xml')
         $ds2iocontrol | Export-CliXml (Join-Path $variableFolder 'ds2iocontrol.xml')
         if ($ds1iocontrol) {
            Format-output -Text $msgText -Level "INFO" -Phase "StorageIOControl"
            (Get-Datastore -Id  $DatastoreName.Id) | set-datastore -storageIOControlEnabled $false | Out-Null
         }
         if ($ds2iocontrol) {
            Format-output -Text $msgText -Level "INFO" -Phase "StorageIOControl"
            (Get-Datastore -Id $TemporaryDatastore.Id) | set-datastore -storageIOControlEnabled $false | Out-Null
         }
         $checkCompleted = 7
         $checkCompleted | out-file $checkFile
      } else {
         $ds1iocontrolXml = Join-Path $variableFolder 'ds1iocontrol.xml'
         if (Test-Path $ds1iocontrolXml) {
            $ds1iocontrol = Import-CliXml $ds1iocontrolXml
         }

         $ds2iocontrolXml = Join-Path $variableFolder 'ds2iocontrol.xml'
         if (Test-Path $ds2iocontrolXml) {
            $ds2iocontrol = Import-CliXml $ds2iocontrolXml
         }
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "StorageIOControl."
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "StorageIOControl"
      Return
   }

   $tmpDs = Get-Datastore -Id $TemporaryDatastore.Id
   #check 8 : getting and setting stuffs related to datastore cluster
   $datastorecluster = Get-Datastorecluster -Datastore $tmpDs
   $oldAutomationLevel = 0
   $ioloadbalanced = 0
   try {
      if ($checkCompleted -lt 8) {
         if ($datastorecluster) {
            $msgText = "Save properties of datastore cluster. It will be reverted to original once operation is complete."
            Format-output -Text $msgText -Level "INFO" -Phase "DRS Cluster"
            $oldAutomationLevel = $datastorecluster.SdrsAutomationLevel
            $ioloadbalanced = $datastorecluster.IOLoadBalanceEnabled
            $oldAutomationLevel | Export-CliXml (Join-Path $variableFolder 'oldAutomationLevel.xml')
            $ioloadbalanced | Export-CliXml (Join-Path $variableFolder 'ioloadbalanced.xml')
            Set-DatastoreCluster -DatastoreCluster $datastorecluster -SdrsAutomationLevel Manual -IOLoadBalanceEnabled $false | Out-Null
         }
         $checkCompleted = 8
         $checkCompleted | out-file $checkFile
      } else {
         $sdrsClusterXml = Join-Path $variableFolder 'sdrsCluster.xml'
         if (Test-Path $sdrsClusterXml) {
            $dsClusterExists = Import-CliXml $sdrsClusterXml
         }

         if ($dsClusterExists) {
            $oldAutomationLevelXml = Join-Path $variableFolder 'oldAutomationLevel.xml'
            if (Test-Path $oldAutomationLevelXml) {
               $oldAutomationLevel = Import-CliXml $oldAutomationLevelXml
            }

            $ioloadbalancedXml = Join-Path $variableFolder 'ioloadbalanced.xml'
            if (Test-Path $ioloadbalancedXml) {
               $ioloadbalanced = Import-CliXml $ioloadbalancedXml
            } 
         }  
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Moving datastore to same cluster"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move both the datastores to same cluster manually and then try again." -Level "Error" -Phase "Moving datastore to same cluster"
      Return
   }

   # Getting list of VMs present on datastore to migrate.
   $vmList = @()

   #check 9 : Move VMs across datastores
   try {
      if ($checkCompleted -lt 9) {
         # Getting list of VMs present on datastore to migrate.
         $vms = Get-Datastore -Id $DatastoreName.Id | Get-VM
         if ($vms.Count -gt 0) {
            Format-output -Text "Moving list of VMs to temporary datastore." -Level "INFO" -Phase "Preparation"
            Format-output -Text "$vms" -Level "INFO" -Phase "Preparation"
            $RelocTaskList = Concurrent-SvMotion -session $Server -SourceId $Datastore.Id -VM $vms -DestinationId $TemporaryDatastore.Id -ParallelTasks 2 
            foreach ($eachTask in $RelocTaskList) {
               if ($eachTask["State"] -ne "Success") { 
                  Format-output -Text "VM failed to Migrate try running the commandlet again with -Resume option." -Level "Error" -Phase "Preperation"
                  Return
               }
            }

            # if there are any active VMs left , throw error
            $vms = Get-Datastore -Id $DatastoreName.Id | Get-VM
            if ($vms -ne $null) { 
               $vswapItems = Get-DataStoreItems -DatastoreId $DatastoreName.Id -Recurse -fileType $vswap
               if ($vswapItems) {
                  $msgText1 = "There are still active .vswp :$vswapItems files in $DatastoreName, which can't be migrated "
                  $msgText2 = "Please move these files to other datastore then try again with -Resume option "
                  Format-output -Text "$msgText1, $msgText2"  -Level "ERROR" -Phase "Migraton"
                  Return
               }
               Return
            }            
         } else {
            Format-output -Text "No VirtualMachine is running from $DatastoreName" -Level "INFO" -Phase "Preperation"
         }
         $checkCompleted = 9
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Moving Virtual Machines"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move all the VMs from $DatastoreName to $TemporaryDatastore manually and then try again." -Level "Error" -Phase "Moving Virtual Machines"
      Return
   }

   $tagList = $null
   # check 10 : Datastore Tag
   if ($checkCompleted -lt 10) {
      # Save Tags attached to the Source Datastore
      $msgText = "Getting list of tags assigned to datastore. These tags will be applied to final VMFS 6 datastore."
      try {
         $tagList = Get-TagAssignment -Entity $DatastoreName | Select -ExpandProperty Tag
         if ($tagList) { 
            Format-output -Text $msgText -Level "INFO" -Phase "Datastore Tagging"
            $tagList | Export-CliXml (Join-Path $variableFolder 'TagList.xml')
         }
      } catch {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Datastore Tagging"
         Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Datastore Tagging"
         Return
       } 
       $checkCompleted = 10
       $checkCompleted | out-file $checkFile
   }
    
   # check 11 : move orphaned data to temporary datastore
   $SrcTemplateMap = @{}
   if ($checkCompleted -lt 11) {
      try{
         $vswap = ".vswp"
         $snapShotDelta = "-delta.vmdk"
         $vswapItems = Get-DataStoreItems -DatastoreId $DatastoreName.Id -Recurse -fileType $vswap
         $snapShotDeltaItems = Get-DataStoreItems -DatastoreId $DatastoreName.Id -Recurse -fileType $snapShotDelta
         if ($vswapItems -or $snapShotDeltaItems ) {
            $msgText1 = "SnapShot delta disks:$snapShotDeltaItems (or) .vswp :$vswapItems files can't be moved "
            $msgText2 = "Please move these files to other datastore then try again with -Resume option "
            Format-output -Text "$msgText1, $msgText2"  -Level "ERROR" -Phase "Copying Orphaned Items"
            Format-output -Text "SnapShot delta disks:$snapShotDeltaItems (or) .vswp :$vswapItems" -Level "ERROR" -Phase "Copying Orphaned data"
            Return
         }

         $templates = Get-Template -Datastore $DatastoreName
         #Cache template VM DS PathName and respective Host
         $SrcTemplateMapXml = Join-Path $variableFolder 'SrcTemplateMap.xml'
         if ($Resume -and (Test-Path $SrcTemplateMapXml)) {
            $SrcTemplateMap = Import-Clixml $SrcTemplateMapXml
         }

         foreach ( $eachtemplate in $templates) {
            $hostId=$eachTemplate.HostId
            $hostRef = Get-VMHost -Id $hostId
            $templateVmPath = $eachTemplate.ExtensionData.Config.Files.VmPathName
            $SrcTemplateMap[$templateVmPath] = $hostRef
            Remove-Template  $eachtemplate
            Format-output -Text "Template $eachtemplate unregistered from host $hostRef" -Level "INFO" -Phase "Copying Orphaned data"
            $SrcTemplateMap | Export-CliXml (Join-Path $variableFolder 'SrcTemplateMap.xml')
         }
      } catch [Exception] {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Copying orphaned data"
         Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move all the orphaned data from $DatastoreName to $TemporaryDatastore manually and then try again." -Level "ERROR" -Phase "Copying orphaned data."
         Return
      }
      $dsItems = Get-DataStoreItems -DatastoreId $DatastoreName.Id
      if (($dsItems -ne $null) -and ($dsItems.Count  -gt 0)) {
         # Copy all the orphaned items
         Format-output -Text "copying Orphaned items to $TemporaryDatastore" -Level "INFO" -Phase "Copying Orphaned data"
         $result = Copy-DatastoreItems -SourceDatastoreId $DatastoreName.Id -DestinationDatastoreId $TemporaryDatastore.Id
         if (!$result) {
            Format-output -Text "Try again with -Resume option" -Level "ERROR" -Phase "Copying orphaned data"
            Return
         }
      }
      $checkCompleted = 11
      $checkCompleted | out-file $checkFile
   }

   $hostConnected = @()
   $LunCanonical = @()
   #check 12 : Unmount datastore
   if ($checkCompleted -lt 12) {
      $msgText = "Unmounting datastore from all Hosts"
      Format-output -Text $msgText -Level "INFO" -Phase "Unmount Datastore"
      try {
         $hostConnected = Get-VMHost -Datastore $DatastoreName
         $LunCanonical = $DatastoreName.ExtensionData.Info.vmfs.extent|select -ExpandProperty DiskName
         #ExportCLI
         $hostConnected  | Export-CliXml (Join-Path $variableFolder 'srcHosts.xml')
         $LunCanonical   | Export-CliXml (Join-Path $variableFolder 'srcLunCanonical.xml')
         # Unmount the Source datastore from all the host
         Format-output -Text "Unmounting datastore $DSName..." -Level "INFO" -Phase "Unmount Datastore"
         Unmount-Datastore $DatastoreName.Id
      } catch [Exception] {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Unmount Datastore"
         Format-output -Text "Caught the exception while unmounting the datastore. Try again with -Resume option." -Level "ERROR" -Phase "Unmount Datastore"
         Return
      }
      $checkCompleted = 12
      $checkCompleted | out-file $checkFile
   }

   #check 13 : delete datastore
   #Get the Lun
   if ($checkCompleted -lt 13) {
      $msgText = "Deleting and recreating VMFS-6 Filesystem."
      Format-output -Text $msgText -Level "INFO" -Phase "Delete Datastore"
      try {
         #Delete the Source datastore from all the host
         Format-output -Text "Deleting datastore $DSName from hosts..." -Level "INFO" -Phase "Delete Datastore"
         Delete-Datastore $DatastoreName.Id
      } catch [Exception] {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Delete Datastore"
         Format-output -Text "Caught the exception while deleting the datastore. Try again with -Resume option." -Level "ERROR" -Phase "Delete Datastore"
         Return
      }
      $checkCompleted = 13
      $checkCompleted | out-file $checkFile
   }

   #check 14 : Create datastore and create new one with VMFS 6
   #Get the Lun
   if ($checkCompleted -lt 14) {
      $msgText = " Creating VMFS-6 Filesystem"
      Format-output -Text $msgText -Level "INFO" -Phase "Create VMFS-6"
      try {
         if ($Resume) {
            #Read $host $luncan
            $hostConnected = Import-CliXml (Join-Path $variableFolder 'srcHosts.xml')
            $LunCanonical  = Import-CliXml (Join-Path $variableFolder 'srcLunCanonical.xml')
         }  
         Format-output -Text "Creating Datastore..." -Level "INFO" -Phase "Datastore Create"
         Create-Datastore -LunCanonical $LunCanonical -hostConnected $hostConnected    
      } catch [Exception] {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Datastore Create"
         Format-output -Text "Caught the exception creating new datastore. Try again with -Resume option." -Level "ERROR" -Phase "Datastore Create"
         Return
      }
      $checkCompleted = 14
      $checkCompleted | out-file $checkFile
   }

   $DatastoreName = Import-CliXml (Join-Path $variableFolder 'Vmfs6Datastore.xml')

   #check 15 : move the created datastore to cluster
   #Move Ds to its respective cluster
   try {
      $msgText = "Moving newly created datastore to its original datastore cluster."
      if ($checkCompleted -lt 15) {
         $sdrsClusterXml = Join-Path $variableFolder 'sdrsCluster.xml'
         if ($Resume -and (Test-Path $sdrsClusterXml)) {
            $datastorecluster = Import-CliXml $sdrsClusterXml
         }
         if ($datastorecluster) {
            Format-output -Text $msgText -Level "INFO" -Phase "SDRS Cluster"
            $datastoreObj = Get-Datastore -Id $DatastoreName.Id
            $datastorecluster = Get-DatastoreCluster -Id $datastorecluster.Id
            Move-Datastore $datastoreObj -Destination $datastorecluster | Out-Null
         }  
         $checkCompleted = 15
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Moving datastore"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move the newly created datastore to the same cluster as $TemporaryDatastore" -Level "Error" -Phase "Moving datastore."
      Return
   }

   Format-output -Text "Entering restoration phase.." -Level "INFO" -Phase "Restoring VMs"
   # Getting list of VMs present on temporary datastore.
   $dsArray = @()
   $vms = Get-Datastore -Id $TemporaryDatastore.Id | Get-VM

   # check 16 : move the vms back to original datastore.
   try {
      $msgText = "Moving VMs back to original datastore, if present"
      $msgText = "Moving VMs back to original datastore, if present"
      if ($checkCompleted -lt 16) {
         Format-output -Text $msgText -Level "INFO" -Phase "Migration"
         if ($vms.Count -gt 0) {
            $RelocTaskList = Concurrent-SvMotion -session $Server -SourceId $TemporaryDatastore.Id -VM $vms -DestinationId $DatastoreName.Id -ParallelTasks 2
            foreach ($eachTask in $RelocTaskList) {
               if ($eachTask["State"] -ne "Success") { 
                  Format-output -Text "VM failed to Migrate try running the commandlet again with -Resume option." -Level "Error" -Phase "Migration"
                  Return
               }
            }
         }
         # if there are any active VMs left , throw error
         $vms = Get-Datastore -Id $TemporaryDatastore.Id | Get-VM
         if($vms -ne $null){ 
            Format-output -Text "VM(s)-$vms still left in Datastore $TemporaryDatastore,Try w/ Resume again" -Level "Error" -Phase "Migraton"
            Return
         }
         $checkCompleted = 16
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Moving Virtual Machines"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move all the VMs from $TemporaryDataStore to $DatastoreName manually and then try again." -Level "Error" -Phase "Moving Virtual Machines"
      Return
   }

   # Attaching tags back to original datastore
   if ($checkCompleted -lt 17) {
      # Attach Tags to the datastore
      $TagListXml = Join-Path $variableFolder 'TagList.xml'
      if ($Resume -and (Test-Path $TagListXml)) {
         $tagList = Import-CliXml $TagListXml
      }
 
      $msgText = "Attaching Tags back to original datastore."
      try {
         foreach ($tag in $tagList) {
            $tagObj = $null
            $tagObj = Get-Tag -Name $tag.Name -Category $tag.Category.Name
            $msgText = "Adding back the Tags to Datastore :$DatastoreName.Name"
            Format-output -Text $msgText -Level "INFO" -Phase "Datastore Tags"
            $newTag = New-TagAssignment -Tag $tagObj -Entity $DatastoreName
         }
      } catch {
         $errName = $_.Exception.GetType().FullName
         $errMsg = $_.Exception.Message
         Format-output -Text "$errName, $errMsg" -Level "Error" -Phase "Datastore Tag"
         Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "Error" -Phase "Datastore Tag"
         Return
      }
      $checkCompleted = 17
      $checkCompleted | out-file $checkFile
   }

   # check 17 : move the orphaned data back to original datastore.
   try {
      $msgText = "Moving orphaned data back to original datastore, if present."
      $dsItems = Get-DataStoreItems -DatastoreId $TemporaryDatastore.Id
      if ($checkCompleted -lt 18) {
         Format-output -Text $msgText -Level "INFO" -Phase "Restoring Orphan data"
         if (($dsItems -ne $null) -and ($dsItems.Count) -gt 0) {
            Format-output -Text "Copying Orphaned items to $DatastoreName" -Level "INFO" -Phase "Copying Orphaned Items"
            $result = Copy-DatastoreItems -SourceDatastoreId $TemporaryDatastore.Id -DestinationDatastoreId $DatastoreName.Id
            if (!$result) {
               Format-output -Text "Try again with -Resume option" -Level "ERROR" -Phase "Copying orphaned data"
               Return
            }
            $tempds = Get-Datastore -Id $TemporaryDatastore.Id
            New-PSDrive -Location $tempds -Name tempds -PSProvider VimDatastore -Root "/" | Out-Null
            # Remove contents from temporary Datastore
            Remove-Item tempds:/* -Recurse
         } 

         # Register templateVM(s) back in the respective hosts
         $SrcTemplateMapXml = Join-Path $variableFolder 'SrcTemplateMap.xml'
         if ($Resume -and (Test-Path $SrcTemplateMapXml)) {
            $SrcTemplateMap = Import-Clixml $SrcTemplateMapXml
         }

         foreach ($templatePath in $SrcTemplateMap.Keys) {
            try {
               $register = New-Template ï¿½VMHost (Get-VMHost -Name $SrcTemplateMap[$templatePath]) -TemplateFilePath $templatePath
               $esxHost= $SrcTemplateMap[$templatePath]
               Format-output -Text "Template VM registered in host $esxHost " -Level "INFO" -Phase "Template Register"
            } catch {
               $errName = $_.Exception.GetType().FullName
               if ( $errName -match  "AlreadyExists") {
                  Format-output -Text "$templatePath :Template already registered" -Level "INFO" -Phase "Template Register"
               } else {
                  throw  $_.Exception
               }
            }
         }
         $checkCompleted = 18
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Moving orphaned data"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option. If problem persists, move all the orphaned data from $TemporaryDataStore to $DatastoreName manually and then try again." -Level "ERROR" -Phase "Moving orphaned data."
      Return
   }

   # check 18 : Update SRDS properties of cluster.-SDRS
   try {
      if ($checkCompleted -lt 19) {
         $sdrsClusterXml = Join-Path $variableFolder 'sdrsCluster.xml'
         if ($Resume -and (Test-Path $sdrsClusterXml)) {
            $datastorecluster = Import-CliXml $sdrsClusterXml
         }

         if ($datastorecluster) {
            $msgText = "Setting datastore-cluster properties to previous State."
            Format-output -Text "$msgText : $oldAutomationLevel" -Level "INFO" -Phase "SDRS Cluster"
            if ($Resume) {
               $oldAutomationLevel = Import-CliXml (Join-Path $variableFolder 'oldAutomationLevel.xml')
               $ioloadbalanced = Import-CliXml (Join-Path $variableFolder 'ioloadbalanced.xml')
            }
            $datastorecluster = Get-DatastoreCluster -Id $datastorecluster.Id
            Set-DatastoreCluster -DatastoreCluster $datastorecluster -SdrsAutomationLevel $oldAutomationLevel -IOLoadBalanceEnabled $ioloadbalanced | Out-Null
         }
         $checkCompleted = 19
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Reverting to original datastore settings"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "ERROR" -Phase "Reverting to original datastore settings."
      Return
   }
    
   try { 
      # check 20 : set datastore storageIOControlEnabled to previous value.
      if ($checkCompleted -lt 20) {
         $msgText = "Setting datastore properties to previous State."
         $ds1iocontrolXml = Join-Path $variableFolder 'ds1iocontrol.xml'
         if ($Resume -and (Test-Path $ds1iocontrolXml)) {
            $ds1iocontrol = Import-CliXml $ds1iocontrolXml
         }

         $ds2iocontrolXml = Join-Path $variableFolder 'ds2iocontrol.xml'
         if ($Resume -and (Test-Path $ds2iocontrolXml)) {
            $ds2iocontrol = Import-CliXml $ds2iocontrolXml
         }

         Format-output -Text $msgText -Level "INFO" -Phase "Datastore Settings"
         (Get-Datastore -Id  $DatastoreName.Id) | set-datastore -storageIOControlEnabled $ds1iocontrol | Out-Null
         (Get-Datastore -Id  $TemporaryDatastore.Id) | set-datastore -storageIOControlEnable $ds2iocontrol | Out-Null

         $checkCompleted = 20
         $checkCompleted | out-file $checkFile
      }

      # check 21 : set cluster DrsAutomationLevel to previous value. -DRS
      if ($checkCompleted -lt 21) {
         $msgText = "Setting cluster properties to previous State."
         Format-output -Text $msgText -Level "INFO" -Phase "DRS Cluster"
         foreach ($clus in $clusters) {
            if ($clus.DrsEnabled) {
               $drsMapXml = Join-Path $variableFolder 'drsMap.xml'
               if ($Resume -and (Test-Path $drsMapXml)) {
                  $drsMap = Import-Clixml $drsMapXml
               }

               Set-Cluster -Cluster $clus -DrsAutomationLevel $drsMap[$clus.Id] -Confirm:$false | Out-Null
            }
         }
         $checkCompleted = 21
         $checkCompleted | out-file $checkFile
      }
   } catch {
      $errName = $_.Exception.GetType().FullName
      $errMsg = $_.Exception.Message
      Format-output -Text "$errName, $errMsg" -Level "ERROR" -Phase "Reverting to original datastore and datastore cluster settings"
      Format-output -Text "Unable to proceed, try running the commandlet again with -Resume option." -Level "ERROR" -Phase "Reverting to original datastore and datastore-cluster settings."
      Return
   }

   Format-output -Text "Datastore upgraded successfully" -Level "INFO" -Phase "Upgrade successful"
   Format-output -Text "Zip the log directory " -Level "INFO" -Phase "Upgrade successful"
   Zip-Logs -logdir $variableFolder
   Remove-Item $variableFolder -Recurse
   Remove-Item $checkFile
   $errorActionPreference = 'continue'
}
# SIG # Begin signature block
# MIIpvwYJKoZIhvcNAQcCoIIpsDCCKawCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDMaSkaPmTZxUkk
# a0tk1fQG1z4kRCD9WEhPcxiseqVfE6CCDnQwggawMIIEmKADAgECAhAIrUCyYNKc
# TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z
# NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg
# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0
# JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr
# Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF
# LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F
# LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh
# 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ
# wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay
# g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI
# YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp
# QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro
# OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB
# WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+
# YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED
# MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql
# +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF
# UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h
# mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw
# YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld
# AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw
# 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP
# LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE
# QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn
# KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji
# WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq
# yK+p/pQd52MbOoZWeE4wgge8MIIFpKADAgECAhAGQAJb/wxIlzKZ1GMgg8N7MA0G
# CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg
# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjQwMzI4MDAwMDAwWhcNMjcwMzMw
# MjM1OTU5WjCBxDETMBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysGAQQBgjc8AgEC
# EwhEZWxhd2FyZTEdMBsGA1UEDwwUUHJpdmF0ZSBPcmdhbml6YXRpb24xEDAOBgNV
# BAUTBzY2MTAxMTcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREw
# DwYDVQQHEwhTYW4gSm9zZTEVMBMGA1UEChMMQnJvYWRjb20gSW5jMRUwEwYDVQQD
# EwxCcm9hZGNvbSBJbmMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6
# 8C+jJxKfxp9c1A6fghwSNjnvV+Y1my2XmTHEPmk7COFTWw1VRBZBtv/zUXrSStlW
# 9Qqqp48wk+H+H5oM0qL9jsUQ6wAJpmjt33F3xvKqc8ehzVZLXUEACQBXTo30Hnbh
# bcacKAyX9sGByGqKlR6cHHrEebSWMoxOO6TOgYg06xfeYzxpx8HqMQjOKgNEbh4c
# m1Yx+ER/4BmWmYcvVHR9KtXwJWxmzUJCaS5OB9lp8JqO5+uAHvpGtQEAb39/h/vy
# 290isCYw16/uaLOz5Epchv5fogTBTh4o6SXWHam03FfMNVbmbMVuciTzfPSDt0i5
# xQWYtVkwVU+NGE4XUutX4zbaing53QYKNAa+NW9FiWcaoEwE1qTvk7ilsucPzdqC
# ikQpHyaaGCzHoDhveSLiJKgKRiDqee8KXfa/hkCoat9AtCihyd899kJ1kSlTO9fk
# ci5/CdKwmwXQIKh6OPueKr+OJ69XPx0V+RaaMAkkVtFb7/VwecFmFgsXFkAK8ulP
# aGYyIFOFqLMqH8ZuKiLVP5HkxDgSitJcWbaSf89TJuxNqh0vV1k4iwaQpcmQZhPK
# 49pNlj5j0cyw8B+xTYNDwnKvyoWgqKAb2cfzc6pCLk2GJLBwakKZ5YKC50XdhPlS
# yrqlLTb5otZRoYWFGKL1SqxxrBjRqg4qp1RvuxRcBQIDAQABo4ICAjCCAf4wHwYD
# VR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFL9ZTMS/Phgv
# GnXZm3XOrmDoJSIfMD0GA1UdIAQ2MDQwMgYFZ4EMAQMwKTAnBggrBgEFBQcCARYb
# aHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNV
# HSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3Js
# My5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQw
# OTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAy
# MUNBMS5jcmwwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8v
# b2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI
# QTM4NDIwMjFDQTEuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBAMLk
# M/5BZB1j2xjjR9IkyDYtLrqS9IztErzl4ogf2dXuAgBJP1EKm/EN4oOi/BHxLW0T
# VuclGZ3aEa3/n3UlHxqmvKm+4elD5oh4sEOm7+J7ECV0HobeZhRiLmdyla1Mqbxw
# xp56AVvhG/++nf+AVzw95c671a3kb+6VXMDzZK1qcUh6zyLklZ/vfjKipry9KgMR
# sXd81I+PRr+99iRI+5pUsF7ixmS4vTldNh2r/VRFKLtXtTefZ20Q55Efu/8NefJf
# fD/+LLmHszB3LRlguFYOUGon7q8eQKi20PMW6PQb8az4mn6MfA1Y2x+L7HFDiy//
# VMOy5DqcKOHWqz/NZr7/VEPtywoLbHlUwNJyFY0wnQhzvPCg67YpDEYERDnggtpe
# OchKlJoqLKQInq6xDLTtco+ynR6IHnWRcz+oYhm6TdvRcmP7giiqObKEFXQwLsjS
# HsqRluk2FQ4DhG63+8gyD4rKQVoybP0obE7Gi2RYHOT0qwPos6GklZraht/capa7
# wos1gNKXJL7G6BaCXQWCyakT76ZOJOdHzHjJ2n+yBgKWWGBv186nrP5nfuRu0vJE
# HG74cy5oRwe3vme6ztPQy9VSgSrP+g67bZ6yPe+z09T7NczW4aXrXbMUdTb02zKQ
# sK8WEKfcvzBmZ115SwMuf3g34C5yRhOsWInfosmAMYIaoTCCGp0CAQEwfTBpMQsw
# CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERp
# Z2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIw
# MjEgQ0ExAhAGQAJb/wxIlzKZ1GMgg8N7MA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYB
# BAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGC
# NwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIPqN+Trg/KLl3q8R
# etJjAcGduA6iCE39/hSYi42PkpM+MA0GCSqGSIb3DQEBAQUABIICAKzlcvltIIW9
# AsqiVuDqn9VZakdT4ogvADHLkrjqIsQbedD+nSnQrZBH7hzzDIgH6m9GKT5zCN5U
# UvpVC7xNXhpRCHIgbmYZ/Ia7AaNT/HqfOtG1mpuEAAA9MifPyZQTA/zbq6YZ4UTD
# tVgNpdlNK2i+8i2DCusxWgTjXkLBFXB7B28/ZpX8i0MdESeLQegjTZw2sVP+Mz1W
# yABOQS6eDmBtkGlscxCuQxV0dadXkWdbWjao8eQwU8yrj82Yb28IFmMvELMObRkJ
# /eA4qgnP+/HzVutjLs362oaijXbQzgeZosr6Lwp7rKOXZVo71xKCM5FP8FKfSbAN
# 2lovTFtiJtTwHMqz+Pl7QAyC5kUCY5fNTgCUBFGpm9NQKsT9UbnknEaMmrMnzXWi
# 37BoGi1g3P0puQ1jYXQ0BmUBFEc/fm/DzQvxdFSfiZbFDeW6L/2IAIYfBFTjdwy7
# t90UHSLINSW5u92Yn+Ydm9uoMfoHb8bQ+O4xvWNPLBvrIAhBL/65F59vsP5/Lb6T
# PQEYLraoJl7B0aloyK53lMKAG54bvjg/VyEj//0TkVbRhh0bEuKAlTE8r+dZ+q8J
# /o+dtlEN4Mmw6ls4b7tPWW2BLFMgcwx+HIHT/8WrygFAMe24vMfMxq13/iOFtkp4
# QEVQT9T9ckRtqY9lWzU6lJRXMZQM5pUGoYIXdzCCF3MGCisGAQQBgjcDAwExghdj
# MIIXXwYJKoZIhvcNAQcCoIIXUDCCF0wCAQMxDzANBglghkgBZQMEAgEFADB4Bgsq
# hkiG9w0BCRABBKBpBGcwZQIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAE
# IPUrPnCNlWV4Ig8CJVD9pvJdVWV3IlI09K05KlR5jDLVAhEA2VFuHdEKttTPRKQ0
# TNAA+hgPMjAyNTA2MTcwODE5MTJaoIITOjCCBu0wggTVoAMCAQICEAqA7xhLjfEF
# gtHEdqeVdGgwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoT
# DkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRp
# bWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2MDQwMDAw
# MDBaFw0zNjA5MDMyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGlt
# ZXN0YW1wIFJlc3BvbmRlciAyMDI1IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQDQRqwtEsae0OquYFazK1e6b1H/hnAKAd/KN8wZQjBjMqiZ3xTWcfsL
# wOvRxUwXcGx8AUjni6bz52fGTfr6PHRNv6T7zsf1Y/E3IU8kgNkeECqVQ+3bzWYe
# sFtkepErvUSbf+EIYLkrLKd6qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4vEjoT1FpS54d
# NApZfKY61HAldytxNM89PZXUP/5wWWURK+IfxiOg8W9lKMqzdIo7VA1R0V3Zp3Dj
# jANwqAf4lEkTlCDQ0/fKJLKLkzGBTpx6EYevvOi7XOc4zyh1uSqgr6UnbksIcFJq
# LbkIXIPbcNmA98Oskkkrvt6lPAw/p4oDSRZreiwB7x9ykrjS6GS3NR39iTTFS+EN
# TqW8m6THuOmHHjQNC3zbJ6nJ6SXiLSvw4Smz8U07hqF+8CTXaETkVWz0dVVZw7kn
# h1WZXOLHgDvundrAtuvz0D3T+dYaNcwafsVCGZKUhQPL1naFKBy1p6llN3QgshRt
# a6Eq4B40h5avMcpi54wm0i2ePZD5pPIssoszQyF4//3DoK2O65Uck5Wggn8O2klE
# TsJ7u8xEehGifgJYi+6I03UuT1j7FnrqVrOzaQoVJOeeStPeldYRNMmSF3voIgMF
# tNGh86w3ISHNm0IaadCKCkUe2LnwJKa8TIlwCUNVwppwn4D3/Pt5pwIDAQABo4IB
# lTCCAZEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU5Dv88jHt/f3X85FxYxlQQ89h
# jOgwHwYDVR0jBBgwFoAU729TSunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQD
# AgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAC
# hlFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRU
# aW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBU
# oFKgUIZOaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0
# VGltZVN0YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcw
# CAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAZSqt8Rwn
# BLmuYEHs0QhEnmNAciH45PYiT9s1i6UKtW+FERp8FgXRGQ/YAavXzWjZhY+hIfP2
# JkQ38U+wtJPBVBajYfrbIYG+Dui4I4PCvHpQuPqFgqp1PzC/ZRX4pvP/ciZmUnth
# fAEP1HShTrY+2DE5qjzvZs7JIIgt0GCFD9ktx0LxxtRQ7vllKluHWiKk6FxRPyUP
# xAAYH2Vy1lNM4kzekd8oEARzFAWgeW3az2xejEWLNN4eKGxDJ8WDl/FQUSntbjZ8
# 0FU3i54tpx5F/0Kr15zW/mJAxZMVBrTE2oi0fcI8VMbtoRAmaaslNXdCG1+lqvP4
# FbrQ6IwSBXkZagHLhFU9HCrG/syTRLLhAezu/3Lr00GrJzPQFnCEH1Y58678Igmf
# ORBPC1JKkYaEt2OdDh4GmO0/5cHelAK2/gTlQJINqDr6JfwyYHXSd+V08X1JUPvB
# 4ILfJdmL+66Gp3CSBXG6IwXMZUXBhtCyIaehr0XkBoDIGMUG1dUtwq1qmcwbdUfc
# SYCn+OwncVUXf53VJUNOaMWMts0VlRYxe5nK+At+DI96HAlXHAL5SlfYxJ7La54i
# 71McVWRP66bW+yERNpbJCjyCYG2j+bdpxo/1Cy4uPcU3AWVPGrbn5PhDBf3Frogu
# zzhk++ami+r3Qrx5bIbY3TVzgiFI7Gq3zWcwgga0MIIEnKADAgECAhANx6xXBf8h
# mS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0z
# ODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcg
# UlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGP
# NRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1I
# pYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5A
# vftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDRe
# b6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBUR
# Jg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/ao
# fEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQ
# skBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJ
# lIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev
# +7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6B
# aaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IB
# XTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQ
# VvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9
# vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwb
# SI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTL
# xLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD
# 8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVk
# o43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRa
# Ps+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8
# cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRz
# W6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KC
# LPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau
# 1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPS
# xyZsq8WhbaM2tszWkPZPubdcMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAY
# WjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdp
# Q2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5
# MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVz
# dGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBz
# aN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbr
# VsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTR
# EEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJ
# z82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyO
# j4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6R
# AXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k
# 98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJ
# tppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUa
# dmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZB
# dd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVf
# nSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0T
# AQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0j
# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsG
# AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9j
# cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYD
# VR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3Qb
# PbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5
# +KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+n
# BgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc
# /RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVr
# zyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o
# 4rmUMYIDfDCCA3gCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl
# cnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1w
# aW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExAhAKgO8YS43xBYLRxHanlXRoMA0G
# CWCGSAFlAwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkq
# hkiG9w0BCQUxDxcNMjUwNjE3MDgxOTEyWjArBgsqhkiG9w0BCRACDDEcMBowGDAW
# BBTdYjCshgotMGvaOLFoeVIwB/tBfjAvBgkqhkiG9w0BCQQxIgQg5wW2iHWzEfDR
# t/4DuB+IJv2m/5kSewoyO+gU3NGqzLAwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg
# SqA/oizXXITFXJOPgo5na5yuyrM/420mmqM08UYRCjMwDQYJKoZIhvcNAQEBBQAE
# ggIAsSjttMmDLqM/rHXxkT58AMZ1A6emi9Xuylr/fUkdDNcN2QxmbMdms3SR10U6
# kbzOuv/X74Z2whPCqSUy5JvlgG/YkJVruJfdrwxL9zSyIaF/DuCS9HFhoCxXpbZC
# qJ7dRU4hAHXCxtqEYj69p2bLqh+LB2tICfX65y9/fHSIN2wRH80lINGNTmj04iml
# +EmbWtDJn19BAs3XzciQ9mQPg+1NWCDhn73zlv07e9CQsHbyZlsdySWQB7aLZI3A
# R0S2grWmuup0H6YglFucJusfu3cPs+8Ts99sXAZq98R/9iF2DdK3lQX/uGY9XwTa
# Jn+WM0VJqDupWcpAUafg8A0RZs/8pYmCI9tpddiUBq1+FlbzV1+F0mIyVT8dogZe
# R7k5uiKosBX0XyeqCqrdbeN7rtcq9apLA8dhTulqJqsQIUTHrd5PKvZYh1qFzLN7
# Zd8OCXEXqED2q63Oz80jRBJKohxntspnNqJfd2mF+qw12q7qdMpGDSWErLPtR0W3
# xOLoIPyKViEQsXo4oMNrOOBCKtDyD0mMNL/59n9eylp9WgdVKpwCUsZTLV0mceeQ
# ehQoz17THKXSusEPMYjRYowT1mqShXmXNR/vpqMvpSnBjfQH5EgltmSPBohSjAHe
# b/DkwlUOneDOPjzg5KgnT5em2fmMa2VjTXMOEPU8v7qI7FM=
# SIG # End signature block