#This script file is intended to provide an example script of how vDisk replication can be performed.

#This script was created by Rob Zylowski Citrix CCS with help from many folks
#It should be used as an example of how to perform PVS Disk replication.
#
#Although every effort has been made to ensure that these sample scripts work properly, 
#Citrix disclaims any responsibility for any and all liability or responsibility for any 
#damages that may result from using these scripts. 
#The sample scripts are provided to you as is, with no warranty or guarantees.
#

#Version 2.1 7-10-2018
#Version 2.2 7-18-2018
#version 2.4 11-12-2018
#	Just updated the version to match changes in the getstore.ps1 and getmanstores.ps1
#version 2.5 11-25-2018
#	Fixed issue with importing vDisk versions before importing the vDisk when the vDisk and versions were both new.
#	Added an area at the end of the log to show all errors encountered
#
#Version 3.0 12/29/2018
#   Added ability to have an agnostic password for the psexec user
#   Added a call at the end to run the new replication status report and add it to the email.
#Version 3.1 1-16-2019
#	Fixed bug with adding vDisks into secondary Farms and Sites
#	Fixed bug when a disk was chosen to replicate from a store not included in replication
#	Added more logging
#Version 3.2 1-20-109
# Added bandwidth limiting with robocopy /ipg
# Fixed a bug where vhdx files would not import correctly into secondary farms and sites becasue a -vhdx
# flag had to be set on the import options
# Fixed an array addition issue when processing a single vhd or vhdx file.
#Version 3.2.1 1-21-2019 Modified code to open processrows.txt when IPG value is null or blank
#Version 3.2.2
# Fixed Error with code that checked for if vDisks were in the right state to include.
#  Added versions in test mode to import
#Version 3.2.3 2-2-2019 Added significant error logging and control.  Added system documenting to log file.
#        Changed how versions were identified to fix issue importing merged bases.
#Version 3.3 3-2-2019
#		Updated script to include running the script on an alternate path like d:\vdiskreplicator
#   Made several fixes to code structure    
#Version 3.4 (never released changes were rolled into 3.5)
#
#Version 3.5 6-2-2019
#  Modified to allow copying between stores on the master server as well as remote servers to support
#  a dev store on the master server.  If this is used the master server itself will also have new vdisks added.
#  
#  Changed where the filename is obtained to handle the issue when a vdisk is copied with its pvp
#  in the original version it used internal name on the vdisklocator.  It now uses the filename from the 
#  the vDisk version.
#
#  Added running GetStorageStatus.ps1
#
#  Added routines to delete vDisks from the PVS consoles if delete is enabled.
#
#  Fixed issues with test mode

# Version 3.5.2 6-24-2019
#Fixed issue when calling the GetStorageSpace.ps1 it would not handle suppressing the email message in that script properly.
#I had to call the script differently and rename the sendmail function in that script so the sendmail function in this script
#would not call that one after being run.

#Version 3.5.3 6-27-2019
#Only to match the version of the UI where there was a small update.

#Version 3.5.4 7-10-2019
#Only to match the version of the UI where there was a small update.

#Version 3.6 12-1-2019
#This version fixes two issues pointed out to me by Craig Ohler from Intrasystems who also provided fixes for the issues.
# Issue 1 - Merged bases would not be added to secondary master servers
# Issue 2 - Fixed logic for deleting unused vDisks


#Version 3.61 2-14-2020
#This version adds code to clean up unused lok, pvp and xml files in all stores.  It does this by comparing all lok, pvp and xml files looking for an 
#associated VHD,VHDX,AVHD, or AVHDX file.  If not is found the file is deleted.  This runs at the end of the script.

#This version also adds the source and destination paths for the rovopy to the status email tables.

#Version 3.70 5-21-2020
#
#Fixed bug where if avhdx files were used the lok,pvp, and xml cleanup would think every avhdx file was missing and get deleted if not in use.
#There was a spurious pvp entry created in the excluded files for every robocopy rcj file.  This has no impact but it was fixed.
#The cleanup of unused lok, pvp and xml files would happen even in test mode.  This was changed to just log what files would be removed.

#Version 3.8 8-23-2020
#
#Fixed Issue where jobs could be skipped if two jobs finished in the same minute that both had jobs that ran after them.  
#The change was to use the status field in the table to define a RunNextTime status for the jobs that needed to be started
#rather than relying on a variable.

#Also fixed an issue where robocopy would write over an active vDisk if the slave server disk was different (usually newer) 
#than the Master Server version.  The script now checkls to see if any of the Slave Server vDisks have active connections.
#If they do they are added to the robocopy Exclusion list.

#Version 3.8.1 8-28-2020 - Fixed robocopy log for amounts in terabytes

#Version 3.8.2 12-5-2020 - Noticed that the code to figure out if a vdisk was in use was wrong.  It would exclude files 
#when in use by any server in the Farm not just the slave server being checked.  Updated the code to get all targets for the server
#then exclude any files in use by those targets.

#Version 4.0.0 5-28-2021 - Modified to allow for using PowerShell Remoting and Deleting Versions.
#Version 4.1.0 1-20-2022 - Fixed bug in script path for copying the runrobocopy/ps1 file to the remote server
#version 4.2.0 7-29-2024 - Added a -i to the psexec call becasue newer versions of PSExec limit connecting as an admin remotely without this flag

Param (
	[string]$RunMode = "Prod",
	[string]$DelMode = "NoDelete"
)

function Get-ScriptDirectory
{
  $Invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $Invocation.MyCommand.Path
}

Function LogLine($strLine)
{
	Write-Host $strLine
	$global:StrTime = Get-Date -Format "MM-dd-yyyy-HH-mm-ss-tt"
	"$global:StrTime - $strLine " | Out-file -FilePath $global:LogFile -Encoding ASCII -Append
}

Function RoboOutline ($strline){
	$global:roboOut += "$strline `r`n"
}

Function FormatErrors()
{
	$NumToProcess = $Error.Count - 1
	$global:ErrorCount = $NumToProcess
	For ($i = $NumToProcess; $i -gt -1; $i-- )
	{
		$global:FormatedErrors += "vDisk Replicator Error:`r`n"
		$global:FormatedErrors += $Error[$i].InvocationInfo.PositionMessage
		$global:FormatedErrors += "`r`n`r`n"
		$global:FormatedErrors += "Exception:`r`n"
		$global:FormatedErrors += $Error[$i]
		$global:FormatedErrors += "`r`n"
		$global:FormatedErrors += "------------------------------------------------------------------------------------`r`n"
	}
}

Function ModRoboJobFile($MasterStore, $SlaveStore, $SlaveServer, $MasterPath, $SlavePath, $ExcludeFiles, $ExcludeFiles2, $IPG)  {
	#This creates the rcj file used to tell robocopy what to copy and what to exclude.
	$global:roboOut = ""	
	RoboOutline "::"
	RoboOutline ":: Robocopy Job $filename.RCJ"
	RoboOutline "::"
	RoboOutline ":: Created by vDiskReplicator Script"
	RoboOutline "::"
	RoboOutline ""
	RoboOutline "::"
	RoboOutline ":: Source Directory :"
	RoboOutline "::"
	RoboOutline "	/SD:$MasterPath\	:: Source Directory."
	RoboOutline ""
	RoboOutline "::"
	RoboOutline ":: Destination Directory :"
	RoboOutline "::"
	RoboOutline "	/DD:$SlavePath\	:: Destination Directory."
	RoboOutline ""
	RoboOutline "::"
	RoboOutline ":: Include These Files :"
	RoboOutline "::"
	RoboOutline "	/IF		:: Include Files matching these names"
	if ($bIncludeFilesOnly)
	{
		foreach ($Includefile in  $IncludeFiles)
		{
			$IFArray = $Includefile -split ";"
			$IFStore = $IFArray[0]
			if ($DelMode -eq "delete")
			{
				$IFFile = $IFArray[3]
			}
			else
			{
				$IFFile = $IFArray[1]
			}
			if ($IFFile.endswith(".avhdx"))
			{
				$IFPVPFileLeftSide=$IFFile  -replace ".{6}$"
			}
			if ($IFFile.endswith(".avhd"))
			{
				$IFPVPFileLeftSide=$IFFile  -replace ".{5}$"
			}
			if ($IFFile.endswith(".vhdx"))
			{
				$IFPVPFileLeftSide=$IFFile  -replace ".{5}$"
			}
			if ($IFFile.endswith(".vhd"))
			{
				$IFPVPFileLeftSide=$IFFile  -replace ".{4}$"
			}
			$IFPVPFile = "$IFPVPFileLeftSide.pvp"
			
			if ($IFStore -eq $MasterStore)
			{
				RoboOutline "`t`t$IFFile" 
				RoboOutline "`t`t$IFPVPFile"
			}
		}
	}
	else
	{
		RoboOutline "::   *.*	:: Include all names (currently - Command Line may override)"
	}
	RoboOutline ""
	RoboOutline "::"
	RoboOutline ":: Exclude These Directories :"
	RoboOutline "::"
	RoboOutline "	/XD		:: eXclude Directories matching these names"
	RoboOutline "		System Volume Information"
	RoboOutline "		Backup"
	RoboOutline "		Temp"
	RoboOutline "		WriteCache"
	RoboOutline "		'`$RECYCLE.BIN'"
	RoboOutline ""
	RoboOutline "::"
	RoboOutline ":: Exclude These Files :"
	RoboOutline "::"
	RoboOutline "	/XF		:: eXclude Files matching these names"
	RoboOutline "		*.lok"
	RoboOutline "		*.xml"
	#Add in our exclusions note these will be the same for all replications
	foreach ($file in  $ExcludeFiles)
	{
		#skip blanks
		if ($file.trim() -eq ""){continue}
		#4-3-2019 We need to exclude the vhd(x) and the pvp  file that goes with it.
		$FileBase = ""
		$arfile = $file.split(".")
		$NumSegments = $arfile.Count
		for ($i=0;$i -lt $NumSegments-1;$i++)
		{
			$FileBase += $arfile[$i]+"."
		}
		$PVPfile = "$FileBase"+"pvp"
		RoboOutline "`t`t$file"
		RoboOutline "`t`t$PVPfile"
	}
	#Now we will exclude all files used on active targets
	foreach ($file in  $ExcludeFiles2)
	{
		#skip blanks
		if ($file.trim() -eq ""){continue}
		#12-5-2020 We need to exclude all files in use
		$arfile = $file.split(".")
		$NumSegments = $arfile.Count
		$vDiskLocatorName = $arfile[0]
		$fileExtension = $arfile[$NumSegments-1]
		for ($i=0;$i -lt $NumSegments-1;$i++)
		{
			$FileBase += $arfile[$i]+"."
		}
		#Exclude file in use
		$PVPfile = "$FileBase" + "pvp"
		RoboOutline "`t`t$file"
		RoboOutline "`t`t$PVPfile"
		#Noew deal with versions if we have any
		if ($NumSegments -gt 2)
		{
			#Figure out version number
			[int]$VersionNumber = $arfile[1]
			#We want to exclude all lower versions
			for ($i=1;$i -lt $VersionNumber;$i++)
		`	{
				$filename = "$vDiskLocatorName" + "." + "$i" + "." + "$fileExtension"
				$PVPfile = "$vDiskLocatorName" + "." + "$i" + "." + "pvp"
				RoboOutline "`t`t$filename"
				RoboOutline "`t`t$PVPfile"
			}
			#Also exclude the base file
			$filename = "$vDiskLocatorName" + "." + "$fileExtension"
			$PVPfile = "$vDiskLocatorName" + "." + "pvp"
			RoboOutline "`t`t$filename"
			RoboOutline "`t`t$PVPfile"
		
		}
	}
	RoboOutline "::"
	RoboOutline ":: Copy options :"
	RoboOutline "::"
	RoboOutline "	/S		:: copy Subdirectories, but not empty ones."
	RoboOutline "	/E		:: copy subdirectories, including Empty ones."
	if ($CopyMethod -eq "Unbuffered")
	{
		RoboOutline "	/J		:: copy using unbuffered I/O."
	}
	if ($IPG -ne "0")
	{
		RoboOutline "	/IPG:$IPG		:: limit bandwidth by Adjusting the Inter packet Gap"
	}
	RoboOutline "	/PURGE		:: delete dest files/dirs that no longer exist in source."
	RoboOutline "	/MIR		:: Mirror a directory tree (equivalent to /E plus /PURGE)."
	RoboOutline "::"
	RoboOutline ":: Retry Options :"
	RoboOutline "::"
	RoboOutline "	/R:5		:: number of Retries on failed copies: default 1 million."
	RoboOutline "	/W:10		:: Wait time between retries: default is 30 seconds."
	RoboOutline "::"
	RoboOutline ":: Logging Options :"
	RoboOutline "::"
	if ($RunMode -eq "Test")
	{
		RoboOutline ":: Running in Test Mode will only log changes"
		RoboOutline "  /L"
	}
	RoboOutline "  /Log:$LocalScriptFolderPath\logs\robocopy-$SlaveStore-$SlaveServer.log"
	#RoboOutline "   /NP"
}

Function SendMail($Attachments,$BodyHTML)
{
	#This scripting is used to email the status of the replication job
	If ($global:chkUseMailAuth -eq "Use Auth")
	{
		If ($global:chkUseMailSSL -eq "Use SSL")
		{
			$SMTPClient = New-Object Net.Mail.SmtpClient($txtMailRelay, 465)
			$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($txtMailAcct, "$global:MyPassword")
			$SMTPClient.EnableSsl = $true
		}
		ElseIf ($global:chkUseMailTLS -eq "Use TLS")
		{
			$SMTPClient = New-Object Net.Mail.SmtpClient($txtMailRelay, 587)
			$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($txtMailAcct, "$global:MyPassword")
			$SMTPClient.EnableSsl = $true
		}
		else
		{
			$SMTPClient = New-Object Net.Mail.SmtpClient($txtMailRelay, 25)
			$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($txtMailAcct, "$global:MyPassword")
			$SMTPClient.EnableSsl = $false
		}
	}
	Else
	{
		$SMTPClient = New-Object Net.Mail.SmtpClient($txtMailRelay, 25)
	}

	logline "Sending Email To $txtMailTo at mail relay $txtMailRelay ...."

	$message = New-Object Net.Mail.MailMessage($txtMailFrom, $txtMailTo, $txtMailSubject, $BodyHTML)
	If ($Attachments -ne $null)
	{
		Foreach ($fileAttachment in $Attachments)
		{
			$myFile = $fileAttachment.FullName
			$mailAttach = new-object Net.Mail.Attachment($myFile)
			$message.Attachments.Add($mailAttach) 
		}
	}
	$message.IsBodyHtml = $true;
	$SMTPClient.Send($message)	
	$message.Dispose()
}

Function ConvertToLocalPath ($NetworkPath)
{
	if ($NetworkPath.Contains("`$"))
	{
		#This is good to convert
		$arrNetPath = $NetworkPath.Split("`$")
		$DriveLetterNum = $arrNetPath[0].length
		$DriveLetterPart = $arrNetPath[0]
		$FolderPart = $arrNetPath[1]
		$DriveLetter = $DriveLetterPart.Substring($DriveLetterNum-1,1)
		$Path = $DriveLetter + ":" + $FolderPart
	}
	else
	{
		$Path = $NetworkPath
	}
	$Path
}

$ScriptSource = Get-ScriptDirectory
$ProcessStartTime = Get-Date

#Create a log folder and file
$LogFolderName = Get-Date -Format "MM-dd-yyyy-HH-mm-tt"
$LogTopFolder = "$ScriptSource\..\Logs"
If (!(Test-Path "$LogTopFolder"))
{
	mkdir "$LogTopFolder" >$null
}
$LogFolder = "$LogTopFolder\$LogFolderName"
mkdir "$LogFolder" >$null
$global:LogFile = "$LogFolder\vDiskReplicator_log.txt"

#Add Header to logs

Logline "=============================================="
Logline "      Running vDisk Replicator"
Logline "      Version 4.2.0"
Logline "=============================================="
Logline ""

#---------------------------------------------------------------
#            Get Email Settings 
#---------------------------------------------------------------

$SendEmail = $false
$EmailConfigFile = "$ScriptSource\..\config\emailconfig.txt"
If (Test-Path $EmailConfigFile)
{
	$SendEmail = $true
	$EmailConfig = Get-Content $EmailConfigFile 

	$global:txtMailRelay = $EmailConfig[0]
	$global:txtMailFrom = $EmailConfig[1]
	$global:txtMailTo = $EmailConfig[2]
	$global:chkUseMailAuth = $EmailConfig[3]
	$global:chkUseMailSSL = $EmailConfig[4]
	$global:chkUseMailTLS = $EmailConfig[5]
	$global:txtMailAcct = $EmailConfig[6]
	$global:txtMailSubject = $EmailConfig[7]
	$global:txtMailBody = $EmailConfig[8]
	
	If ($global:chkUseMailAuth -eq "Use Auth")
	{
		$CredFile = "$ScriptSource\..\config\credemail.txt"
		If (Test-Path $CredFile)
		{
			$passwordback = Get-Content $CredFile | ConvertTo-SecureString
			$credentialmail = New-Object System.Management.Automation.PsCredential("mailman",$passwordback)
			$MailmanPW = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($credentialmail.Password))
			$global:MyPassword = $MailmanPW
		}	
		else
		{
			Logline "No Credentials defined.  Email cannot be sent."
			Logline ""
		}
	}
}

if ($DelMode -ne "delete")
{
	#Check to see if this is an Include Files Only Run
	$FilesToProcessfile="$ScriptSource\..\config\FilesToProcess.txt"
	if (Test-Path $FilesToProcessfile)
	{
		$bIncludeFilesOnly = $true
		#Now get the file list
		$IncludeFiles = Get-Content -Path $FilesToProcessfile
		Logline ""
		Logline "########## Running in Selected Files Only Mode ##########"
		Logline ""
	}
	else
	{
		Logline ""
		Logline "########## Running in Normal Mode ##########"
		Logline ""
		$bIncludeFilesOnly = $false
	}
}

#Get the Remoting Method.  PSEXEC is the default method if one was not defined.
$RemotingMethod = "PSEXEC"
$RemotingMethodConfigFile = "$ScriptSource\..\config\RemotingMethod.txt"
if (Test-Path $RemotingMethodConfigFile)
{
	$RemotingMethod = Get-Content $RemotingMethodConfigFile
}
Logline "Remoting Method Set to [$RemotingMethod]"

#Get Time limit if it exists
$TimelimitFile="$ScriptSource\..\config\timelimit.txt"
if (Test-Path $TimelimitFile)
{
	[int]$TimeLimit = Get-Content -Path $TimelimitFile -Encoding ASCII
	Logline "Processing Time Limit set to $TimeLimit Hours"
}
else
{
	[int]$TimeLimit = 24
}

#Get the copy method.  If there is a file in config called SaveBufCopy.txt then buffered copies will be used.
$CopyMethodFile="$ScriptSource\..\config\SaveBufCopy.txt"
if (Test-Path $CopyMethodFile)
{
	$CopyMethod = "Buffered"
}
else
{
	$CopyMethod = "Unbuffered"
}

#Get setting for including vDisk deletes.  If the config folder has a file called deletevDisks.txt VDisks 
#that are missing in the store file system will be removed from the PVS console.
$deleteFile="$ScriptSource\..\config\DeletevDisks.txt"
if (Test-Path $deleteFile)
{
	$RunDelete = $true
}
else
{
	$RunDelete = $false
}
#CleanupLPX Flags file
$CleanLPXFile="$ScriptSource\..\config\CleanLPX.txt"
if (Test-Path $CleanLPXFile)
{
	$CleanupLPX = $true
}
else
{
	$CleanupLPX = $false
}

#Set time limit time
$LoopTimeLimit = $ProcessStartTime.AddHours($TimeLimit)

#For Saved Credentials
$credfile = "$ScriptSource\..\config\cred.xml"
$CredFile2 = "$ScriptSource\..\config\cred2.xml"
if (Test-Path $credfile)
{
	$credential = Import-CliXml -Path "$ScriptSource\..\config\cred.xml"
	$PsexecCred=$credential.GetNetworkCredential()
	$PSAccount = $credential.UserName
	$PSPassword = $PsexecCred.Password
}
elseIf (Test-Path $CredFile2)
{
	$PSAccount = get-content -Path "$ScriptSource\..\Config\credacc2.txt"
	$PSPasswordEnc = get-content $Credfile2 | ConvertTo-SecureString -Key (Get-Content "$ScriptSource\..\Config\cred2.txt")
	$credential = New-Object System.Management.Automation.PsCredential("$PSAccount",$PSPasswordEnc)
	$PSPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($credential.Password))
}	
else
{
	$credential = Get-Credential
	$PsexecCred=$credential.GetNetworkCredential()
	$PSAccount = $PsexecCred.Domain + "\" + $PsexecCred.UserName
	$PSPassword = $PsexecCred.Password
}

#Get the remote path entry for the script to run

$LocalScriptFile = "$ScriptSource\..\config\LocalScriptPath.txt"
If (Test-Path $LocalScriptFile)
{
	$LocalScriptFolderPath = Get-Content $LocalScriptFile 
}
else
{
	$LocalScriptFolderPath = "c:\vDiskReplicator"
}

#=========================================================================
#Import PowerShell Snapin
#=========================================================================

try{
    Import-Module 'C:\Program Files\Citrix\Provisioning Services console\Citrix.PVS.SnapIn.dll' -ErrorAction Stop
} catch {
    Logline "PVS PowerShell Snap-In Not Found on $env:computername.  Script terminated."
	
    if ($SendEmail)
	{
		Logline "Email has been enabled.  Sending Status Email"
		
		$EmailAttach = "<p>The vDisk Replication script has failed because the PVS PowerShell Snapin could not be loaded</p>"
		$global:txtMailSubject = "vDisk Replicator Status ***Script Failed***"
		#Get Attachments
		$myLogDir = Get-Item -Path $LogFolder
		$arrAttachments = Get-ChildItem -Path $myLogDir
		Sendmail $arrAttachments $EmailAttach
	}
	exit
}

logline "RunMode:$runmode"
Logline "DelMode:$DelMode"

#=========================================================================
#Get Stores to Replicate
#=========================================================================

#We Need to track which stores are included
$arStoresToInclude = New-Object System.Collections.ArrayList
$RowsToProcess = New-Object System.Collections.ArrayList
#set up a datatable to track each remote job through the process
#this is very cool :)
$PVSRunTable = New-Object system.Data.DataTable "PVSRunTable"
[array]$Columns = $("Number","MasterFarm","MasterSite", "MasterServer", "MasterStore","MasterPath", "SlaveFarm", "SlaveSite", "SlaveServer", "SlaveStore", "SlavePath", "Include", "RunAfter", "IPG", "Status","RunSpaceId","vDiskImported","vDiskSettingsMatch")

#Get the ProcessRows.txt file created by the UI.  This includes the source and destination stores that have been selected to process.
$PVSSchedule = Get-Content -Path "$ScriptSource\..\Config\ProcessRows.txt"
ForEach ($Column in $Columns) {$PVSRunTable.Columns.Add($(New-Object system.Data.DataColumn $Column,([string])))}

#Now add the jobs into our datatable
ForEach ($Column in $PVSRunTable.Columns) {$Column.DataType = [string]}
$FirstLine = $true
Logline "Loading process Rows into Working Table"
foreach ($line in $PVSSchedule)
{
	if($line.Trim() -eq ""){continue}
	$arrLine = $line.split(";")
	$TableRow = $PVSRunTable.NewRow() 
	$TableRow.Number = $arrLine[0]
	$TableRow.MasterFarm = $arrLine[2]
	$TableRow.MasterSite = $arrLine[3]
	$TableRow.MasterServer = $arrLine[4]
	$TableRow.MasterStore = $arrLine[5]
	$TableRow.MasterPath = $arrLine[6]
	$TableRow.SlaveFarm = $arrLine[7]
	$TableRow.SlaveSite = $arrLine[8]
	$TableRow.SlaveServer = $arrLine[9]
	$TableRow.SlaveStore = $arrLine[10]
	$TableRow.SlavePath = $arrLine[11]
	$TableRow.Include=$arrLine[12]
	$TableRow.RunAfter=$arrLine[13]
	$ValueIPG = $arrLine[14]
	[string]$strValeIPG = $arrLine[14]
	if ($ValueIPG -eq $null){$ValueIPG=0}
	if ($strValeIPG.trim() -eq ""){$ValueIPG=0}
	$TableRow.IPG = $ValueIPG
	#Set all rows where runafter = 0 to RunNextTime so they will start initially.
	if ($arrLine[13] -eq 0)
	{
		$TableRow.Status = "RunNextTime"
	}
	else
	{
		$TableRow.Status = "Pending"
	}
	
	$TableRow.RunSpaceId = ""
	$PVSRunTable.Rows.Add($TableRow)	
	if ($arStoresToInclude -notcontains $TableRow.MasterStore){$arStoresToInclude.Add($TableRow.MasterStore)>$null}
	$RowsToProcess.Add("$Line")>$null
}

if ($bIncludeFilesOnly)
{
	 Logline "Checking Files to Process to make sure they include files in the stores we are including."
	 $arStoresWithFiles = New-Object System.Collections.ArrayList
	 foreach ($myFileInfo in $IncludeFiles)
	 {
	    $myinfoArray = $myFileInfo -split ";"
	    $myStoreNameCheck =  $myinfoArray[0]
	    $myFileNameCheck = $myinfoArray[1]
		if ($DelMode -eq "delete")
		{
			#Need to translate the disklocator to a file name
			$myFileNameCheck = $myinfoArray[3]
		}
	    if($myFileNameCheck.trim() -ne "")
	    {
	       $arStoresWithFiles.Add($myStoreNameCheck)>$null
	       Logline "Store [$myStoreNameCheck] was found in Files to Process"       
	        #now lets see if there are slave stores that are different than the master store and add those in for this master store
	       foreach ($TableRow in $PVSRunTable.Rows)
	       {
	        
			    $MasterStore = $TableRow.MasterStore
			    $SlaveStore = $TableRow.SlaveStore
			    if ($MasterStore -eq $myStoreNameCheck)
	            {
	                #Add slave store if its different
	                if ($SlaveStore -ne $myStoreNameCheck)
	                {
	                    $arStoresWithFiles.Add($SlaveStore)>$null
	                    Logline "Translated Store [$myStoreNameCheck] was added in place of [$MasterStore] in Files to Process"    
	                }

	            }
	       }
	   }
	}
}

if ($bIncludeFilesOnly)
{
	#Lets make sure we have some files to process
	if ($arStoresWithFiles.count -eq 0)
	{
	    Logline "No Files were found to Process - Exiting Script"
	    if ($SendEmail)
	    {
	        Logline "Email has been enabled.  Sending Status Email"
		    $global:txtMailSubject = "vDisk Replicator Status ***Script Failed***"
			$EmailAttach = "<p>The vDisk Replication script has failed because no files were found to Process</p>"

	        #Get Attachments
	        $myLogDir = Get-Item -Path $LogFolder
	        $arrAttachments = Get-ChildItem -Path $myLogDir  -Exclude *.rcj
	        Sendmail $arrAttachments
	    }
	    exit
	}
}

#=========================================================================
#Get File Exclusions
#=========================================================================
#Get the Master master Server.  This is the source of all the replications.
$Masters = Get-Content "$ScriptSource\..\config\masters.txt"
if ($Masters -is [System.Array])
{
	$FirstMaster = $Masters[0].ToLower()
	$PrimaryMaster = $Masters[0]

}
else
{
	$FirstMaster = $Masters.ToLower()
	$PrimaryMaster = $Masters

}

Set-PvsConnection -Server $PrimaryMaster -ErrorAction:SilentlyContinue
if (!$?)
{
	Logline "**** Warning Connection to Primary Master Server [$PrimaryMaster] Failed"
	Logline "**** The Script Cannot Continue"
	
	if ($SendEmail)
	{
		Logline "Email has been enabled.  Sending Status Email"
		$EmailAttach = "<p>The vDisk Replication script has failed because the Primary Master Server could not be contacted</p>"
		$global:txtMailSubject = "vDisk Replicator Status ***Script Failed***"
		#Get Attachments
		$myLogDir = Get-Item -Path $LogFolder
		$arrAttachments = Get-ChildItem -Path $myLogDir
		
		Sendmail $arrAttachments $EmailAttach
	}
	exit
}
$PVSVersion = Get-PvsVersion
$MasterServerPVSVersion = $PVSVersion.MapiVersion
$PrimarySiteServer = Get-PvsServer -ServerName $PrimaryMaster
$PrimaryMasterSite = $PrimarySiteServer.SiteName

# Creating global list
logline "Analyzing Master Server vDisks for Exclusions"

[array]$AllSites = Get-PvsSite
[array]$AllStores = Get-PvsStore



#=========================================================================
#Delete Selected vDisks from Master Server if Enabled
#=========================================================================

if ($DelMode -eq "delete")
{
	if (!$RunDelete)
	{
		Logline "You have chosen to delete vDisks but Delete is not enabled in Setup."
		Logline "Exiting the script"
		Sleep 20
		exit
	}
	Logline "Checking for vDisks in Master Server to Delete"
	
	#Check to see if this is an Include Files Only Run
	$FilesToDeletefile="$ScriptSource\..\config\vDisksToDelete.txt"
	if (Test-Path $FilesToDeletefile)
	{
		$bIncludeFilesOnly = $true
		#Now get the file list
		$DeleteFiles = Get-Content -Path $FilesToDeletefile
		Logline ""
		Logline "########## Running in Selected Files Only Mode to Delete Files ##########"
		Logline ""
		$IncludeFiles = $DeleteFiles
	}
	else
	{
		Logline "***Error no files were selected to delete - Exiting Script"
		if ($SendEmail)
		{
			Logline "Email has been enabled.  Sending Status Email"
			
			$EmailAttach = "<p>***Error no files were selected to delete</p>"
			$global:txtMailSubject = "vDisk Replicator Status ***Script Failed***"
			#Get Attachments
			$myLogDir = Get-Item -Path $LogFolder
			$arrAttachments = Get-ChildItem -Path $myLogDir
			Sendmail $arrAttachments $EmailAttach
		}
		exit
	}
	
	
	#Ok now Lets delete some vDiskLocators
	Set-PvsConnection -Server $PrimaryMaster -ErrorAction:SilentlyContinue
	if (!$?)
	{
		Logline "***Cannot connect to Primary Master - Exiting Script"
		if ($SendEmail)
		{
			Logline "Email has been enabled.  Sending Status Email"
			
			$EmailAttach = "<p>***Error Cannot connect to Primary Master</p>"
			$global:txtMailSubject = "vDisk Replicator Status ***Script Failed***"
			#Get Attachments
			$myLogDir = Get-Item -Path $LogFolder
			$arrAttachments = Get-ChildItem -Path $myLogDir
			Sendmail $arrAttachments $EmailAttach
		}
		exit
	
	}
	foreach ($DelDiskLocator in $DeleteFiles)
	{
		$arrLocator = $DelDiskLocator.Split(";")
		$StoreName = $arrLocator[0]
		$diskLocatorName = $arrLocator[1]
		$DiskLocatroId = $arrLocator[2]
		$DiskFileName = $arrLocator[3]
		
		if ($RunMode -ne "Test")
		{
		
			#Test for versions
			#$DLTest = Get-PvsDiskLocator -DiskLocatorId $DiskLocatroId
			$DLVersions = Get-PvsDiskVersion -DiskLocatorId $DiskLocatroId
			if ($DLVersions.count -gt 1)
			{
				foreach($Diskfile in $DLVersions)
				{
					$VersionFileName = $Diskfile.DiskFileName
					$DLVersion = $Diskfile.Version
					#If our file is this version filename
					if ($DiskFileName -eq $VersionFileName)
					{
						Remove-PvsDiskVersion -DiskLocatorId $DiskLocatroId -Version $DLVersion
						if ($?)
						{
								Logline "DiskLocator [$diskLocatorName] Version [$DLVersion] in Store [$StoreName] with Filename [$DiskFileName] Was deleted"
						}
						else
						{
							Logline "***Error: DiskLocator [$diskLocatorName] Version [$DLVersion] in Store [$StoreName] with Filename [$DiskFileName] Was NOT deleted"
						}
					}
				}
			}
			else
			{
				Remove-PvsDiskLocator -DiskLocatorId $DiskLocatroId -DeleteDiskFile:$true -SiteName $PrimaryMasterSite -StoreName $StoreName 
				if ($?)
				{
					Logline "DiskLocator [$diskLocatorName] in Store [$StoreName] with Filename [$DiskFileName] Was deleted"
				}
				else
				{
					Logline "***Error: DiskLocator [$diskLocatorName] in Store [$StoreName] with Filename [$DiskFileName] Was NOT deleted"
				}
			}
		}
		else
		{
			Logline "Test Mode:Running in Test Mode: DiskLocator [$diskLocatorName] in Store [$StoreName] with Filename [$DiskFileName] would have been deleted"
		}
	}
}

#Now we cycle through all the stores and look for any vDisks that are in Private Mode 
#or versions that are not in production mode and capture them for exclusions
$skipText = ""
foreach ($Site in $AllSites)
{
	Foreach ($Store in $AllStores)
	{
		$mySiteName = $Site.Name
		$myStoreName = $Store.name
		#Lets make sure this store master is included in the replication
		if ($arStoresToInclude -notcontains $myStoreName){Continue}
		Logline "Getting DiskLocators for Site [$mySiteName] Store [$myStoreName]"
		$AllDiskLocators = Get-PvsDiskLocator -SiteName $mySiteName -StoreName $myStoreName 
		foreach ($DiskLocator in $AllDiskLocators)
		{
			$diskLocatorName = $DiskLocator.Name
			Logline "Geting Disk Info for vDisk [$diskLocatorName]"
			#Make sure the Disk is in standard Mode
			$myDiskIno = Get-PvsDiskInfo -DiskLocatorId $DiskLocator.DiskLocatorId
			#this is on diskinfo
			#uint WriteCacheType: 0 (Private), 
			#(other values are standard image) 
			#1 (Cache on Server), 
			#3 (Cache in Device RAM), 
			#4 (Cache onDevice Hard Disk), 
			#6 (Device RAM Disk), 
			#7 (Cache on Server, Persistent), or 
			#9(Cache in Device RAM with Overflow on Hard Disk). 
			#Min=0, Max=9, Default=0
			if ($myDiskIno.WriteCacheType -eq 0)
			{
				#This disk is in private mode and will be skipped
				#changed 4-22-2019 based on recommendation from Craig
				$DiskVersion = Get-PvsDiskVersion -DiskLocatorId $DiskLocator.DiskLocatorId
        		$filename = $DiskVersion.DiskFileName													
				#$file = $myDiskIno.InternalName
				#$arrFile = $file -split "\\"
				#$numBS = $arrFile.count
				#$filename = $arrFile[$count-1]
				$version = ""
				logline "     This disk [$filename] is in private mode and will be skipped"
				$skipText = $skipText + "`r`n" + "$filename" 
			}
			Logline "     Getting disk versions vDisk [$diskLocatorName]"
			$AllDiskVersions = Get-PvsDiskVersion -DiskLocatorId $DiskLocator.DiskLocatorId
			foreach($DiskVersion in $AllDiskVersions)
			{
				#We only want production vDisks os anything other than zero we will skip
				#these are the possible choices
				#uint Access: Read-only access of the Disk Version.Values are: 
				#0 (Production), 1 (Maintenance), 
				#2 (MaintenanceHighestVersion), 
				#3(Override), 4 (Merge), 
				#5 (MergeMaintenance), 
				#6 (MergeTest), and 
				#7 (Test) 
				#Min=0,Max=7, Default=0
				$file = $DiskVersion.DiskFileName
				$version = $DiskVersion.Version

				if ($DiskVersion.Access -ne 0) 
				{
					if (($DiskVersion.Access -eq 3) -or ($DiskVersion.Access -eq 7))
					{
						logline "     This disk [$file] version [$version] will not be excluded."
						continue
					}
					$version = $DiskVersion.Version
					logline "     This disk [$file] version [$version] is not in production mode and will be excluded."
					$skipText = $skipText + "`r`n" + "$file" 
				}
				else
				{
					logline "     This disk [$file] version [$version] will not be excluded."
				}
			}
		}
	}
}

##Store the exclusions in a file
if (Test-Path "$ScriptPath\..\config\excludefiles.txt"){Del "$ScriptPath\..\config\excludefiles.txt"}
$skipText | Out-File -LiteralPath "$ScriptSource\..\config\excludefiles.txt" -Encoding ASCII

#Setup to use runspaces (https://blogs.technet.microsoft.com/heyscriptingguy/2015/11/26/beginning-use-of-powershell-runspaces-part-1/
#This allows us to manage backgrouns jobs easier
$pool = [RunspaceFactory]::CreateRunspacePool(1, [int]$env:NUMBER_OF_PROCESSORS+1)
$pool.ApartmentState = "MTA"
$pool.Open()
$runspaces = @()

#We need to define our background job
$scriptblock = {
	Param($SlaveStore,$PVSSlaveServer,$LocalPath,$ScriptSource,$PSAccount,$PSPassword,$Credential,$RemotingMethod)
	Write-Host "Robocopy Script Called for Slave Store:$SlaveStore Slave Server:$PVSSlaveServer Source:$ScriptSource Acct:$PSAccount"     
	$arrRemoteScriptFilePath = $LocalPath.split(":")
	$RemoteDrive = $arrRemoteScriptFilePath[0]
	$RemoteFolder = $arrRemoteScriptFilePath[1]
	if ("$PVSSlaveServer" -eq "$PrimaryMaster")
	{
		$FolderPath = $LocalPath
	}
	else
	{
		$FolderPath = "\\$PVSSlaveServer\$RemoteDrive`$$RemoteFolder"
	}
	$TestFolder= Test-Path "$FolderPath"
	if (!$TestFolder)
	{
		#Create Folder
		mkdir "$FolderPath"
		#Disabe Inheritance on Folder otherwise we have trouble writting to the folders
		$acl = Get-Acl "$FolderPath"
		$acl.SetAccessRuleProtection($True, $True)
		Set-Acl $FolderPath $acl | Out-Null
	}
	
	copy "$ScriptSource\..\robofiles\$SlaveStore-$PVSSlaveServer.rcj" $FolderPath
	Set-Location $ScriptSource
	$ScriptFilePath = "$LocalPath\RunRobocopy.ps1"
	$ScriptFilePathPR ="$ScriptSource\RunRobocopy.ps1" 
	if ($RemotingMethod -eq "PSEXEC")
	{
		#If using PSEXEC we need to copy the robocopy script to the slave server
		copy "$ScriptSource\RunRobocopy.ps1" $FolderPath
		$RemoteJob = ./PSEXEC.exe  "\\$PVSSlaveServer" -u "$PSAccount" -p "$PSPassword" -h -i -accepteula powershell.exe -ExecutionPolicy Bypass -file "$ScriptFilePath" "$PVSSlaveServer" "$SlaveStore" "$FolderPath"
	}
	else
	{
		$RemoteJob = Invoke-Command -ComputerName  $PVSSlaveServer -Credential $credential -Authentication CredSSP -FilePath "$ScriptFilePathPR" -argumentlist ("$PVSSlaveServer","$SlaveStore","$LocalPath") -EnableNetworkAccess
	}
	# return whatever you want, or don't.
    $RemoteJob
}

#Get our files to exclude
$ExcludeFiles = Get-Content -Path "$ScriptSource\..\config\excludefiles.txt" -Encoding ASCII


#============================================================================================
#  Main Job Loop
#============================================================================================

$i=1
if ($IPG -gt 0)
{G
	Logline "Limiting Bandwidth - IPG Set to [$IPG]"
}

Do 
{
	Logline ""
	Logline "Try Number $i"
	Write-Host "Job Status"

	$NotDone = $false
	#Cycle through our Datatable to process the jobs in the correct order starting with 0
	Foreach ($TableRow in $PVSRunTable.Rows)
	{
		$LineNumber=$TableRow.Number
		$MasterFarm = $TableRow.MasterFarm
		$MasterSite = $TableRow.MasterSite
		$MasterServer = $TableRow.MasterServer
		$MasterStore = $TableRow.MasterStore
		$MasterPath = $TableRow.MasterPath
		$SlaveFarm = $TableRow.SlaveFarm
		$SlaveSite = $TableRow.SlaveSite
		$SlaveServer = $TableRow.SlaveServer
		$SlaveStore = $TableRow.SlaveStore
		$SlavePath = $TableRow.SlavePath
		$IPG = $TableRow.IPG
		$Status=$TableRow.Status
		$RunAfter=$TableRow.RunAfter
		
		#Lets list the Status of All jobs each cycle
		#If its done skip it
		if ($Status -eq "Done")
		{
			Write-Host -ForegroundColor Magenta "SrcSrvr:$MasterServer SrcStore:$MasterStore DestSrvr:$SlaveServer DestStore:$SlaveStore Status:$Status"
			continue
		}
		elseIf ($Status -eq "Pending")
		{
			Write-Host -ForegroundColor Blue "SrcSrvr:$MasterServer SrcStore:$MasterStore DestSrvr:$SlaveServer DestStore:$SlaveStore Status:$Status"
			continue
		}
		elseif ($Status -eq "Running")
		{
			#Lets see if its complete
			foreach ($runspace in $runspaces) 
			{
				$SlaveServer = $runspace.Pipe.Commands.Commands.parameters[1].value
				$RunSpaceId=$runspace.Pipe.InstanceId
				
				#Check the runspace for this row 
				If ($TableRow.RunspaceId -eq "$RunSpaceId")
				{
					#If the job has completed
					If ($runspace.Status.IsCompleted)
					{
						Write-Host -ForegroundColor Magenta "SrcSrvr:$MasterServer SrcStore:$MasterStore DestSrvr:$SlaveServer DestStore:$SlaveStore Status:Done"

						$arrRemoteScriptFilePath = $LocalScriptFolderPath.split(":")
						$RemoteDrive = $arrRemoteScriptFilePath[0]
						$RemoteFolder = $arrRemoteScriptFilePath[1]
						$FolderPath = "\\$SlaveServer\$RemoteDrive`$$RemoteFolder"

						$mySlaveLog="$FolderPath\Logs\$SlaveStore-$SlaveServer" + "_log.txt"
						$mySlaveRoboLog="$FolderPath\Logs\robocopy-$SlaveStore-$SlaveServer.log"
						$mySlaveRoboFile="$FolderPath\$SlaveStore-$SlaveServer.rcj"

						#Lets do post processing
						Logline "Job is complete for Server:$SlaveServer Farm:$SlaveFarm Site:$SlaveSite Store:$SlaveStore"
						$TableRow.Status = "Done"
						$runspace.Pipe.Dispose()

						Logline "Start Post Processing for Server:$mySlaveServer Site:$mySite Store:$myStore"
						
						#Copy log files from slave and clean up log files on remote pvs server
						If (Test-Path $mySlaveLog)
						{
							Logline "copy $mySlaveLog $LogFolder"
							Copy "$mySlaveLog" "$LogFolder"
							Logline "Del $mySlaveLog"
							del "$mySlaveLog"
						}
						else
						{
							Logline "*** Warning File $mySlaveLog not found in $LogFolder.  This normally indicates that the remote script did not run."
						}
						if (Test-Path $mySlaveRoboLog)
						{
							Logline "Copy $mySlaveRoboLog $LogFolder"
							Copy "$mySlaveRoboLog" "$LogFolder"
							logline "del $mySlaveRoboLog"
							del "$mySlaveRoboLog"
						}
						else
						{
							Logline "*** Warning File $mySlaveRoboLog not found in $LogFolder.  This normally indicates that the remote robocopy did not run."
						}
						If (Test-Path $mySlaveRoboFile)
						{
						 	Logline "Del $mySlaveRoboFile"
							del "$mySlaveRoboFile"
						}
						else
						{
							Logline "*** Warning File $mySlaveRoboFile not found in $LogFolder.  This normally indicates that the remote robocopy did not run."
						}
						#This job finished.  Lets see if there are other jobs waiting on this to run
						Logline "Check for new jobs to run"
						foreach ($row2 in $PVSRunTable.Rows)
						{
							#First we need to create the robocopy file for this slave
							$LineNumber2=$row2.Number
							$MasterServer2=$row2.MasterServer
							$SlaveServer2 = $row2.SlaveServer
							$Source2 = $row2.Source
							$Destination2 = $row2.SlaveStore
							$Status2=$row2.Status
							$RunAfter2=$row2.RunAfter
						
							if ($RunAfter2 -eq "$LineNumber")
							{
								#Then set the status to RunNetxTime
								Logline "Job for MasterSrver [$MasterServer2] Store [$Source2] SlaveServer [$SlaveServer2] Store [$Destination2] will be started during the next loop"
								$row2.Status = "RunNextTime"
							}
						}
					} #Is job complete
					else
					{
						#Its not complete lets say its running still
						Write-Host -ForegroundColor Green "SrcSrvr:$MasterServer SrcStore:$MasterStore DestSrvr:$SlaveServer DestStore:$SlaveStore Status:$Status"
					}
				}
			}
		} #If status is running
		elseIf ($Status -eq "RunNextTime")
		{
			#Change Status to running
			Write-Host -ForegroundColor Green "SrcSrvr:$MasterServer SrcStore:$MasterStore DestSrvr:$SlaveServer DestStore:$SlaveStore Status:Running"
		
	        #Let check to see if we are only copying certain files we need to make sure the files we are copying are in 
	        #the store we are processing here.  Otherwise we want to skip this.

	        if ($bIncludeFilesOnly)
	        {
	          if($arStoresWithFiles -notcontains $SlaveStore)
	          {
	            Logline "Slave Store [$SlaveStore] is not included in any of the Files To process therefore this store will be skipped."
	            $TableRow.Status="Done"
				#This job finished.  Lets see if there are other jobs waiting on this to run
				Logline "Check for new jobs to run"
				foreach ($row2 in $PVSRunTable.Rows)
				{
					#First we need to create the robocopy file for this slave
					$LineNumber2=$row2.Number
					$MasterServer2=$row2.MasterServer
					$SlaveServer2 = $row2.SlaveServer
					$Source2 = $row2.Source
					$Destination2 = $row2.Destination
					$Status2=$row2.Status
					$RunAfter2=$row2.RunAfter
				
					if ($RunAfter2 -eq "$LineNumber")
					{
						#Then set the status to RunNetxTime
						Logline "Job for MasterSrver [$MasterServer2] Store [$Source2] SlaveServer [$SlaveServer2] Store [$Destination2] will be started during the next loop"
						$row2.Status = "RunNextTime"
					}
				}
	            continue
	          }
	          else
	          {
	            Logline "Slave Store [$SlaveStore] is included in the Files To process therefore this store will be processed."
	          }

	        }

			#If it is lets run the job and set the status to Running
			$TableRow.Status="Running"
			Logline "Adding Job for MasterFarm:$MasterFarm  MasterSite:$MasterSite MasterStore:$MasterStore MasterServer:$MasterServer SlaveFarm:$SlaveFarm SlaveSite:$SlaveSite SlaveStore:$SlaveStore SlaveServer:$SlaveServer"
			$robofile = "$ScriptSource\..\RoboFiles\$SlaveStore-$SlaveServer.RCJ"
			Logline "Creating Robocopy file named $robofile"
			
			if ("$SlaveServer" -eq "$MasterServer") 
			{
				$MasterPath = ConvertToLocalPath $MasterPath
				$SlavePath = ConvertToLocalPath $SlavePath
				
				Logline "Copying vDisks within the same server.  Using Local Paths MasterPath [$MasterPath] SlavePath [$SlavePath]"
			}
			
			#We need to check all the vdisks to exclude becasue they have active targets.
			#We determine this if the devicecount is > 0
			$ExcludeFiles2 = New-Object System.Collections.ArrayList
			
			Logline "Connecting to Slave Server [$SlaveServer] to find Active vDisks to remove from sync"
			Set-PvsConnection -Server $SlaveServer -ErrorAction:SilentlyContinue 
			#Get all targets in the server and see which disks they have mounted
			Logline "Getting Server [$SlaveServer] Target Inventory"
			$ServerTargetList = Get-PvsDeviceInfo -ServerName "$SlaveServer"
			$serverTargetCount = $ServerTargetList.count
			Logline "[$serverTargetCount] Targets found on server [$SlaveServer]"
			foreach ($Target in $ServerTargetList)
			{
				$DiskName = $Target.DiskFileName
				Logline "vDisk [$DiskName] found in use.  It will be added to the exclude list."
				Logline "Checking vDisk [$DiskName]"
				if ($ExcludeFiles2 -notcontains $DiskName)
				{
					$ExcludeFiles2.Add("$DiskName") > $null
				}
			}
			
			ModRoboJobFile $MasterStore $SlaveStore $SlaveServer $MasterPath $SlavePath $ExcludeFiles $ExcludeFiles2 $IPG
			if (Test-Path "$robofile"){del "$robofile"}
			$global:roboOut | Out-File -LiteralPath "$robofile" -Encoding ASCII
			
			$arrRemoteScriptFilePath = $LocalScriptFolderPath.split(":")
			$RemoteDrive = $arrRemoteScriptFilePath[0]
			$RemoteFolder = $arrRemoteScriptFilePath[1]
			$FolderPath = "\\$SlaveServer\$RemoteDrive`$$RemoteFolder"
			
			$runspace = [PowerShell]::Create()
			$null = $runspace.AddScript($scriptblock)
			$null = $runspace.AddArgument($SlaveStore)
			$null = $runspace.AddArgument($SlaveServer)
			$null = $runspace.AddArgument($LocalScriptFolderPath)
			$null = $runspace.AddArgument($ScriptSource)
			$null = $runspace.AddArgument($PSAccount)
			$null = $runspace.AddArgument($PSPassword)
			$null = $runspace.AddArgument($credential)
			$null = $runspace.AddArgument($RemotingMethod)

			$runspace.RunspacePool = $pool
		 	$TableRow.RunSpaceId=$runspace.InstanceId
		    $runspaces += [PSCustomObject]@{ Pipe = $runspace; Status = $runspace.BeginInvoke() }
			logline "Robocopy Script Called for store:$SlaveStore SlaveServer:$SlaveServer Acct:$PSAccount RemotingMethod:$RemotingMethod "     
			}
	}
	
	#Exit if all the rows are Done
	foreach ($rowTest in $PVSRunTable.Rows)
	{
		if ($rowTest.Status -ne "Done"){$NotDone=$True}
	}
	
	#Exit if we past the time limit
	$CurDateTime = Get-Date
	$bTimeLimitReached = $false
	if ($CurDateTime -gt $LoopTimeLimit)
	{
		$NotDone=$false
		Logline "Time Limit Reached!  Processing complete."
	}
	#Sleep for a minute
	Logline "Sleeping for one minute"
	Sleep 60
	$i++
} While ($NotDone)

#copy the rcj files to the log folder
$rcjfilepath = "$ScriptSource\..\robofiles\*"
Logline "Copy all robocopy setup files to the log folder"
copy $rcjfilepath $LogFolder
logline "Delete the robocopy setup files in the robofiles working folder"
del $rcjfilepath

Logline "Cleanup jobs from memory"
$pool.Close() 
$pool.Dispose()

#Lets get the body for email and log file by interrogating the robocopy logs

$robologs = Get-ChildItem -Path $LogFolder robocopy*.log
$outputHTML+="<style>table th, td {border: 1px solid black;}</style>"
$MailBody = $global:txtMailBody
$outputHTML+="<p>$MailBody</p>"
$outputHTML+="<p></p>"
$outputHTML+="<h2>Robocopy Status</h2>"
$outputHTML+="<p></p>"
$outputHTML+="<p>The following tables show the robocopy status of each store in the replication</p>"
$outputHTML+="<p>Black entries have no failed copies.  Red entries have failed copies.</p>"
$outputHTML+="<p></p>"
$outputHTML+="<p></p>"

$j=1

foreach ($rlog in $robologs)
{
	Logline "Processing log $rlog"
	$myLogPath = "$LogFolder\$rlog"
	$mylog = get-content -Path $myLogPath
	$i=0
	foreach ($line in $mylog)
	{
		if ($i -eq 6){$SourceText = $line}
		if ($i -eq 7){$DestText = $line}
	    if ($line -match "Total")
	    {
			#Files
	        $files= $mylog[$i+2]
	        $arrFiles = $files -split '\s+'
	        $Total = $arrFiles[3]
	        $Copied = $arrFiles[4]
	        $Skipped = $arrFiles[5]
	        $Mismatched = $arrFiles[6]
	        $Failed = $arrFiles[7]
			#group header
			if ([int]$Failed -gt 0){$turnRed=$true}else{$turnRed=$false}
			#heading line
			if ($turnRed)
			{
				$outputHTML+="<table class='redtable'>"
				$outputHTML+="<tr style='color:red'><td colspan='6'>$rlog</td></tr>"
				$outputHTML+="<tr style='color:red'><td colspan='6'>$SourceText</td></tr>"
				$outputHTML+="<tr style='color:red'><td colspan='6'>$DestText</td></tr>"
				$outputHTML+="<tr style='color:red'><td>Type</td><td>Total</td><td>Copied</td><td>Skipped</td><td>Mismatch</td><td>FAILED</td></tr>"
				$outputHTML+="<tr style='color:red'><td>Files</td><td>$Total</td><td>$Copied</td><td>$Skipped</td><td>$Mismatched</td><td>$Failed</td></tr>" 
			}
			else
			{
				$outputHTML+="<table>"
				$outputHTML+="<tr style='color:black'><td colspan='6'>$rlog</td></tr>"
				$outputHTML+="<tr style='color:black'><td colspan='6'>$SourceText</td></tr>"
				$outputHTML+="<tr style='color:black'><td colspan='6'>$DestText</td></tr>"
				$outputHTML+="<tr style='color:black'><td>Type</td><td>Total</td><td>Copied</td><td>Skipped</td><td>Mismatch</td><td>FAILED</td></tr>"
				$outputHTML+="<tr style='color:black'><td>Files</td><td>$Total</td><td>$Copied</td><td>$Skipped</td><td>$Mismatched</td><td>$Failed</td></tr>" 
				}
			$files= $mylog[$i+3]
			$arrFiles = $files -split '\s+'
			$files= $mylog[$i+3]
			$arrFiles = $files -split '\s+'
			$arrFilesFiltered = New-Object System.Collections.ArrayList
			$k=0
			foreach ($line in $arrFiles)
			{
				if($line.Trim() -eq ""){$k++;continue}
				if($line -in @("t","g","m","k",":","bytes")){$k++;continue}
				if([double]$line -is [double])
				{
					if($arrFiles[$k+1] -in @("t","g","m","k"))
					{
						$MetricString=$arrFiles[$k+1]
						$arrFilesFiltered.add("$line $MetricString")>$null
					}
					else
					{
						$arrFilesFiltered.add($line)>$null
					}
				} 
				$k++
			}
        	$Total = $arrFilesFiltered[0]
	        $Copied = $arrFilesFiltered[1]
	        $Skipped = $arrFilesFiltered[2]
	        $Mismatched = $arrFilesFiltered[3]
	        $Failed = $arrFilesFiltered[4]
			if ($turnRed)
			{
				$outputHTML+="<tr style='color:red'><td>Bytes</td><td>$Total</td><td>$Copied</td><td>$Skipped</td><td>$Mismatched</td><td>$Failed</td></tr>" 
			}
			else
			{
				$outputHTML+="<tr style='color:black'><td>Bytes</td><td>$Total</td><td>$Copied</td><td>$Skipped</td><td>$Mismatched</td><td>$Failed</td></tr>" 
			}
			#times
			$files= $mylog[$i+4]
	        $arrFiles = $files -split '\s+'
	        $Total = $arrFiles[4]
	        $Copied = $arrFiles[5]
	        $Skipped = ""
	        $Mismatched = ""
	        $Failed = $arrFiles[6]
			if ($turnRed)
			{
				$outputHTML+="<tr style='color:red'><td>Time</td><td>$Total</td><td>$Copied</td><td>$Skipped</td><td>$Mismatched</td><td>$Failed</td></tr>" 
			}
			else
			{
				$outputHTML+="<tr style='color:black'><td>Time</td><td>$Total</td><td>$Copied</td><td>$Skipped</td><td>$Mismatched</td><td>$Failed</td></tr>" 
			}
			$outputLog=$line + "`r`n" + $mylog[$i+1] + "`r`n" + $mylog[$i+2] + "`r`n" + $mylog[$i+3] + "`r`n" + $mylog[$i+4] + "`r`n`r`n" 
			if ($turnRed)
			{
	        	logline $outputLog -ForegroundColor Red
			}
			else
			{
				logline $outputLog -ForegroundColor Black
			}
			$i=0
			break
	    }
	    $i++
	}
	$j++
	$outputHTML+="</table>"
	$outputHTML+="<p>&nbsp;</p>"
}

#===================================================================================
#If there is a Secondary Master we need to import any new vDisks
#===================================================================================

#We need to process both any secondary master servers in other farms than the master master 
#as well as Secondary Site Import Servers.  The process to import vDisks on both of these
#is the same. 
#1 For each vDisk see if it has not been imported.  
#if not, get the vDisk settings from the master master
#Export a manifest
#copy the manifest and use it to import the vDisk into the Server/Site
#Note versions use a different import command so we need to handle avhd and avhdx files differently


#Create an Array for the servers to process.  This will include masters and Secondary Site Import Servers
$arrImportServers = New-Object System.Collections.ArrayList
Logline "Looking for Farm Master Servers for Import"

if($Masters.Count -gt 1)
{
	Foreach ($MasterServer in $Masters)
	{
		#Changed these two item 5-2-2019 to make it possible to copy between stores on the same server.
		#if ($MasterServer -eq $PrimaryMaster){continue}
		#if ($MasterServer -eq ""){continue}
		if ($arrImportServers.contains($MasterServer)){continue}
		logline "Adding Master Server [$MasterServer] to Import Array"
		$arrImportServers.Add("$MasterServer")>$null
	}
}
Logline "Looking for Secondary Site Master Servers for Import"
$ImportServersFile = $ScriptSource + "\..\config\SecondaryMasters.txt"
if (Test-Path $ImportServersFile)
{
    $ImportServers = Get-Content -Path "$ImportServersFile" -Encoding ASCII
    if($ImportServers.Count -gt 0) 
    {
	    Foreach ($IServer in $ImportServers)
	    {
		    $arrIServers = $IServer -split ";"
		    $ImpServerName = $arrIServers[2]
		    if ($ImpServerName -eq $PrimaryMaster){continue}
		    if ($ImpServerName -eq ""){continue}
		    if ($arrImportServers.contains($ImpServerName)){continue}
		    $arrImportServers.Add("$ImpServerName")>$null
	    }
    }
}
else
{
	Logline "No Secondary Site Master Import Servers were defined"
}

#Now lets loop through each row in PVSRunTable and Import vDisks for any
#slave server that is a Secondary Master or Secondary Site Import Server

#Need a datatable to capture success or failure of disk imports
$vDiskImportTable = New-Object system.Data.DataTable "vDiskImportTable"
[array]$ColumnsVI = $("SlaveServer","SlaveStore","vDiskFile","Imported", "SettingsMatch")
ForEach ($Column in $ColumnsVI) {$vDiskImportTable.Columns.Add($(New-Object system.Data.DataColumn $Column,([string])))}
ForEach ($Column in $vDiskImportTable.Columns) {$Column.DataType = [string]}

foreach ($row in $PVSRunTable.Rows)
{

	$LineNumber=$row.Number
	$MasterFarm = $row.MasterFarm
	$MasterSite = $row.MasterSite
	$MasterServer = $row.MasterServer
	$MasterStore = $row.MasterStore
	$MasterPathEntry = $row.MasterPath
	If ($MasterPathEntry[1] -eq ":") 
	{
		$MasterPath = "\\$MasterServer\"+$MasterPathEntry.Replace(":", "$")
	}
	else
	{
		$MasterPath = $MasterPathEntry
	}
	
	$SlaveFarm = $row.SlaveFarm
	$SlaveSite = $row.SlaveSite
	$SlaveServer = $row.SlaveServer
	$SlaveStore = $row.SlaveStore
	$SlavePathEnrty = $row.SlavePath
	If ($SlavePathEnrty[1] -eq ":") 
	{
		$SlavePath = "\\$SlaveServer\"+$SlavePathEnrty.Replace(":", "$")
	}
	else
	{
		$SlavePath = $SlavePathEnrty
	}
	$Status = $row.Status
	$RunAfter = $row.RunAfter

	$SecondaryMaster = $SlaveServer
	#See if this is one of our servers, if not skip it
	if ($arrImportServers -notcontains $SecondaryMaster)
	{
		Logline "Import Servers does not contain Secondary Master [$SecondaryMaster]"
		continue
	}
	
	#Now lets get all the vhd files in the store
	#if there is not a site in the store info then there is only one site in the farm and we get site from SMSites
	$arExclude =  "*.pvp","*.lok","*.xml"
	$storeFilesAvhd = Get-ChildItem -Path "$SlavePath\*.avhd*"
	$storeFilesVhd = Get-ChildItem -Path "$SlavePath\*.vhd*"
	$storeFilesAvhdCount = $storeFilesAvhd.Count
	$storeFilesVhdCount = $storeFilesVhd.Count
	$CheckAgain = $True
	
	if ($storeFilesVhdCount -eq 1)
	{
		$storeFilesVhd = @($storeFilesVhd)
	
	}
	if ($storeFilesAvhdCount -eq 1)
	{
		$storeFilesAvhd = @($storeFilesAvhd)
	}
	
	$storeFiles = $storeFilesVhd + $storeFilesAvhd 
	$myCount = $storeFiles.count
	if ($myCount -gt 0) 
	{
		Logline "Store file Count is [$mycount]"
	}
	else
	{
		Logline "Store file Count is 0"
	}
    
	$arDiskLocatorsImported = New-Object System.Collections.ArrayList
	
	foreach ($storeFile in $storeFiles)
	{
		$FileType = $storeFile.Extension
		$StoreFileName = $storeFile.Name
		$arFileName=$StoreFileName.split(".")
		$diskLocatorName = $arFileName[0]

		#We need to determine if this disk has versions or not
		$checkVersions = $false
		Logline "Checking Disk [$StoreFileName] for versions"
		
		if (($FileType -eq ".avhd") -or ($FileType -eq ".avhdx"))
		{
			Logline "This file [$StoreFileName] is a version.  Therefore we will check for versions."
			$checkVersions = $true
			#Change designed by Craig Ohler IntraSystems - Thanks Craig!
			# file is not a merge base version
			# bMergeBase will be true for all versions that are a merged base
			# bMergeBaseNew will be true for all merged base versions that are not present in the Target Farm/Store (checked later)
			$bMergeBase = $false
			$bMergeBaseNew = $false									
		}
		else
		{
			Logline "This file [$StoreFileName] is not a version"
			$checkVersions = $false
			# IntraSystems - if filename includes 2 or more periods assume it's not version 0
			# and since it is not a .avhd or .avhdx it must be a merged base
			if ($arfilename.count -gt 2)
			{
				Logline "This file [$StoreFileName] is a merged base"
				$bMergeBase = $true
				$bMergeBaseNew = $false
			}																										 
		}
		
		#if we are copying selected files only we need to see if this is one of our files
		if ($bIncludeFilesOnly)
		{
			$bFileMatch = $false
			foreach ($Filentry in $IncludeFiles)
			{
					$IFArray = $Filentry -split ";"
					$IFStore = $IFArray[0]
					if ($Delmode -eq "Delete")
					{
						$IFFile = $IFArray[3]
					}
					else
					{
						$IFFile = $IFArray[1]
					}
					if ("$IFStore" -eq "$MasterStore")
					{
						if ("$IFFile" -eq "$StoreFileName")
						{
							$bFileMatch = $true
							logline "File [$StoreFileName] is included in the selected files we are processing.  It will be imported."
						}
					}
			}
			
			#if we have no match skip to the next file
			if (!$bFileMatch)
			{
				Logline "File [$StoreFileName] is not included in the selected files we are processing.  It will not be imported."
				continue
			}	
		}
		
		Logline "Checking File [$StoreFileName] on Server [$SecondaryMaster] Site[$SlaveSite] Store[$SlaveStore] for Import."

		#Lets see if we already added this disk file
		if ($arDiskLocatorsImported -contains "$diskLocatorName")
		{
			Logline "File [$StoreFileName] on Server [$SecondaryMaster] Site[$SlaveSite] Store[$SlaveStore] was already imported - skipping"
			continue
		}
		
		Logline "Connecting to Secondary Master Server [$SecondaryMaster]"
		Set-PvsConnection -Server $SecondaryMaster -ErrorAction:SilentlyContinue
		if (!$?)
		{
			Logline "**** Warning Connection to Secondary Master Server [$SecondaryMaster] Failed"
			Logline "**** Skipping this vDisk"
			continue
		}
		
		$myPVSVersion = Get-PvsVersion
		$myPVSVersionNum = $PVSVersion.MapiVersion
		Logline "PVS Version for Secondary Master Server [$SecondaryMaster] is [$myPVSVersionNum]"
		
		$bImportvDisk = $false
		$myDiskLocator = $null
		Try
		{
			$myDiskLocator = Get-PvsDiskLocator -DiskLocatorName  "$diskLocatorName" -SiteName "$SlaveSite" -StoreName "$SlaveStore" 
		}
		Catch
		{
            #no disklocator found
		}
		
    if ($myDiskLocator -eq $null)
		{
			if ($checkVersions -eq $false)
			{
				Logline "DiskLocator for file [$StoreFileName] was not found.  Importing on Server [$SecondaryMaster] Site[$SlaveSite] Store[$SlaveStore]."
				$bImportvDisk = $true
				#IntraSystems - If this is a merge base version, but the disk does not exist in Target, set mergeBaseNew to True
				if ($bmergeBase) 
				{
					Logline "The above DiskLocator is a new merged base."
					$bmergeBaseNew = $true
				}			
			}
			else
			{
				Logline "A base DiskLocator for file [$StoreFileName] was not found.  Versions cannot be imported without a base Disklocator. Skipping vDisk [$storeFile]"
				$bImportvDisk = $false
				continue
			}
		}
		else
		{
			if ($checkVersions -eq $false)
			{
		    	Logline "DiskLocator for file [$StoreFileName] was found.  No Import is necessary."
				$DLName = $myDiskLocator.name
				Logline "Disklocator name is [$DLName]"
			}
		}
		
		#Lets check to see if this is a version we need to import
		#IntraSystems - change this to also check to see if a version needs to be imported for Merge Base versions.
		#     This will catch when the only new version is a merge base.
		if ($checkVersions -or $bmergeBase)
		{
			if ($arFileName.Count -eq 2)
			{
				[int]$TestVersion = 0
			}
			else
			{
				[int]$TestVersion = $arFileName[$arFileName.Count-2]
			}
			if($TestVersion -gt 0)
			{
				Try
				{
					$DiskLocatorId = $myDiskLocator.DiskLocatorId
					Logline "Getting Disklocator Versions for file [$StoreFileName] with ID [$DiskLocatorId]"
					$DiskVersions = Get-PvsDiskVersion -DiskLocatorId $DiskLocatorId
				}
				Catch
				{
					Logline "***Error: No Disk Versions Found for File [$StoreFileName] with ID [$DiskLocatorId]"
				}
				$bNewVersion = $true
				foreach ($DiskVersion in $DiskVersions)
				{
					[int]$VersionNumber = $DiskVersion.version
					If ($VersionNumber -eq $TestVersion)
					{
						Logline "File [$StoreFileName] was already imported on Server [$SecondaryMaster] Site[$SlaveSite] Store[$SlaveStore]."
						$bNewVersion = $false
						continue
					}
				}
			}
		}
		if ($bNewVersion -eq $true){$bImportvDisk = $true}
		if ($bImportvDisk)
		{
			$arDiskLocatorsImported.Add("$diskLocatorName")>$null
			#We want to add it in
			#Lets get a manifest from the primary master
			Logline "Connecting to Master Server [$MasterServer] to Export Disk Manifest"
			Set-PvsConnection -Server $MasterServer -ErrorAction:SilentlyContinue
			if (!$?)
			{
				Logline "**** Warning Connection to Master Server [$MasterServer] Failed while trying to Export the disk manifest"
			}
			
			Logline "Exporting manifest for DiskLocatorName [$diskLocatorName] SiteName [$MasterSite] StoreName [$MasterStore]"
			if ($RunMode -ne "Test")
			{
				Export-PvsDisk -DiskLocatorName "$diskLocatorName" -SiteName "$MasterSite" -StoreName "$MasterStore"
				if (!$?)
				{
					Logline "**** Warning Export of vDisk [$diskLocatorName] failed"
				}
				
				#Get the vDisk info to set when we import
				Logline "Getting Disk information from Master Server [$MasterServer] for Disklocator [$diskLocatorName]"
				$PrimDiskLocator = Get-PvsDiskLocator -DiskLocatorName "$diskLocatorName" -SiteName "$MasterSite" -StoreName "$MasterStore"
				if (!$?)
				{
					Logline "***Getting the Primary Server Disk Information failed for Server [$MasterServer] for Disklocator [$diskLocatorName]"
					Logline "***Skipping the vDisk Import"
					continue
				}		
				
				#Store the settings from the master vDisk
				$dl_Name = $PrimDiskLocator.Name 
				$dl_Site = $PrimDiskLocator.SiteName
				$dl_Store = $PrimDiskLocator.StoreName
				$dl_Description = $PrimDiskLocator.Description
				$dl_MenuText = $PrimDiskLocator.MenuText
				$dl_ServerName = $PrimDiskLocator.ServerName
				$dl_RebalanceEnabled = $PrimDiskLocator.RebalanceEnabled
				$dl_RebalanceEnabledPercent = $PrimDiskLocator.RebalanceTriggerPercent
				$dl_SubnetAffinity = $PrimDiskLocator.SubnetAffinity
				
				Logline "Getting Disk Settings from Master Server [$MasterServer] for Disklocator [$diskLocatorName]"
				$PrimDisk = Get-PvsDisk -DiskLocatorId $PrimDiskLocator.DiskLocatorId
				if (!$?)
				{
					Logline "***Getting Disk Settings failed for [$MasterServer] for Disklocator [$diskLocatorName]"
				}
				else
				{
					#Get settings from the master disk
					$dl_ActivationDateEnabled = $PrimDisk.ActivationDateEnabled 
					$dl_HaEnabled = $PrimDisk.HAEnabled 
					$dl_AdPasswordEnabled = $PrimDisk.ADPasswordEnabled 
					$dl_PrinterManagementEnabled = $PrimDisk.PrinterManagementEnabled 
					$dl_WriteCacheType = $PrimDisk.WritecacheType 
					$dl_WriteCacheSize = $PrimDisk.WriteCacheSize 
					$dl_LicenseMode = $PrimDisk.LicenseMode 
					$dl_VHDX = $PrimDisk.VHDX
				}
				
				#Lets get the manifest we exported	
				$xmlfile = "$MasterPath\" + $diskLocatorName + ".xml"
				if (Test-Path $xmlfile)
				{
					logline "Copy XML file from [$xmlfile] to [$SlavePath]"
					copy "$xmlfile" "$SlavePath"
					$xmlFileSecondary = "$SlavePath\" + $diskLocatorName + ".xml"
				}
				else
				{
					logline "**** Warning XML file [$xmlfile] was not found"
				}
			}
		
			# Now lets import the vDisk
			if (Test-Path $xmlFileSecondary)
			{
				Logline "XML File was successfully copied from [$xmlfile] to [$xmlFileSecondary]"
				Set-PvsConnection -Server $SecondaryMaster -ErrorAction:SilentlyContinue 
				if (!$?)
				{
					Logline "**** Warning Connection to Secondary Master Server [$SecondaryMaster] Failed while trying to Import the vDisk"
					Logline "Skipping this vDisk"
					continue
				}
				# IntraSystems
				# Change this to only import new versions which are NOT completely new Merged Base disks
				if ($bnewVersion -and -not $bmergeBaseNew)
				{
					Logline "A new version of vDisk [$diskLocatorName] will be imported"
					if ($RunMode -ne "Test")
					{
						Add-PvsDiskVersion -DiskLocatorId $myDiskLocator.DiskLocatorId 
						if ($?)
						{
							Logline "New Versions for vDisk [$diskLocatorName] were added"
							$rowvDiskImported = "Yes"
						}
						else
						{
							Logline "Error:Adding new versions for vDisk [$diskLocatorName] Failed"
							$ErrorText = $Error[0]
							Logline "$ErrorText"
						}
						#We need to get this for checking later.
						$SecondaryDiskLocator = Get-PVSDiskLocator -DiskLocatorName "$diskLocatorName" -SiteName "$SlaveSite" -StoreName "$SlaveStore"
					}
					else
					{
						Logline "Test Mode:New Versions for vDisk [$diskLocatorName] would have been added"
					}
				}
				else
				{
					#A whole new vDisk will be imported
					if (($FileType -eq ".vhdx") -or ($FileType -eq ".avhdx"))
					{
						if ($RunMode -ne "Test")
						{
							#Processing X type file (vhdx or achdx)
							if ($dl_MenuText.Length -eq 0 -and $dl_Description.Length -eq 0)
							{
								$SecondaryDiskLocator = Import-PvsDisk -DiskLocatorName "$diskLocatorName" `
								-SiteName "$SlaveSite" -StoreName "$SlaveStore" `
								-Enabled:$true -RebalanceEnabled:$dl_RebalanceEnabled `
								-rebalanceTriggerPercent $dl_RebalanceEnabledPercent -SubnetAffinity $dl_SubnetAffinity `
								-VHDX
							}
							if ($dl_MenuText.Length -eq 0 -and $dl_Description.Length -gt 0)
							{
								 $SecondaryDiskLocator = Import-PvsDisk -DiskLocatorName "$diskLocatorName" `
								-SiteName "$SlaveSite" -StoreName "$SlaveStore" `
								-Enabled:$true -RebalanceEnabled:$dl_RebalanceEnabled `
								-Description $dl_Description `
								-rebalanceTriggerPercent $dl_RebalanceEnabledPercent -SubnetAffinity $dl_SubnetAffinity `
								-VHDX
							}
							if ($dl_MenuText.Length -gt 0 -and $dl_Description.Length -eq 0)
							{
								 $SecondaryDiskLocator = Import-PvsDisk -DiskLocatorName "$diskLocatorName" `
								-SiteName "$SlaveSite" -StoreName "$SlaveStore" `
								-Enabled:$true -RebalanceEnabled:$dl_RebalanceEnabled `
								-MenuText $dl_MenuText `
								-rebalanceTriggerPercent $dl_RebalanceEnabledPercent -SubnetAffinity $dl_SubnetAffinity `
								-VHDX
							}
						}
						else
						{
							Logline "Test Mode:vDisk Settings for vDisk [$diskLocatorName] would have been updated"
						}
					}
					else
					{
						if ($RunMode -ne "Test")
						{
							#Processing non-X type file (vhd or avhd)
							if ($dl_MenuText.Length -eq 0 -and $dl_Description.Length -eq 0)
							{
								$SecondaryDiskLocator = Import-PvsDisk -DiskLocatorName "$diskLocatorName" `
								-SiteName "$SlaveSite" -StoreName "$SlaveStore" `
								-Enabled:$true -RebalanceEnabled:$dl_RebalanceEnabled `
								-rebalanceTriggerPercent $dl_RebalanceEnabledPercent -SubnetAffinity $dl_SubnetAffinity 
							}
							if ($dl_MenuText.Length -eq 0 -and $dl_Description.Length -gt 0)
							{
								 $SecondaryDiskLocator = Import-PvsDisk -DiskLocatorName "$diskLocatorName" `
								-SiteName "$SlaveSite" -StoreName "$SlaveStore" `
								-Enabled:$true -RebalanceEnabled:$dl_RebalanceEnabled `
								-Description $dl_Description `
								-rebalanceTriggerPercent $dl_RebalanceEnabledPercent -SubnetAffinity $dl_SubnetAffinity
							}
							if ($dl_MenuText.Length -gt 0 -and $dl_Description.Length -eq 0)
							{
								 $SecondaryDiskLocator = Import-PvsDisk -DiskLocatorName "$diskLocatorName" `
								-SiteName "$SlaveSite" -StoreName "$SlaveStore" `
								-Enabled:$true -RebalanceEnabled:$dl_RebalanceEnabled `
								-MenuText $dl_MenuText `
								-rebalanceTriggerPercent $dl_RebalanceEnabledPercent -SubnetAffinity $dl_SubnetAffinity
							}
							else
							{
								Logline "Test Mode:vDisk Settings for vDisk [$diskLocatorName] would have been updated"
							}
						}
					}

					#Set PVSDisk settings to what the master had
					$oDisk = Get-PvsDisk -DiskLocatorId $SecondaryDiskLocator.DiskLocatorId
					if (!$?)
					{
						Logline "WARNING**** vDisk [$diskLocatorName] was not Successfully imported"
						$rowvDiskImported = "No"
						continue
					}
					else
					{
						Logline "vDisk [$diskLocatorName] was  Successfully imported"
						$rowvDiskImported = "Yes"
						
						#Now lets copy all the settings from the master
						Logline "Copying Master vDisk settings to slave"
						
						$oDisk.ActivationDateEnabled = $dl_ActivationDateEnabled 
						$oDisk.HaEnabled = $dl_HAEnabled 
						$oDisk.AdPasswordEnabled = $dl_ADPasswordEnabled 
						$oDisk.PrinterManagementEnabled = $dl_PrinterManagementEnabled 
						$oDisk.WriteCacheType = $dl_WritecacheType 
						$oDisk.WriteCacheSize = $dl_WriteCacheSize 
						$oDisk.LicenseMode = $dl_LicenseMode 
						if ($dl_VHDX){$oDisk.VHDX = $true}else{$oDisk.VHDX = $false}
						#Change the disk to use the new DiskLocator
						Try
						{
							if ($RunMode -eq "Test")
							{
								Logline "In Test Mode Setting Disk Properties on vDisk [$diskLocatorName] is skipped"
							}
							else
							{
								Logline "Test Mode:Setting Disk Properties on vDisk [$diskLocatorName]"
								Set-PvsDisk $oDisk
							}
						}
						Catch
						{
						
						}
					} #End Successful Import
			
					#Since it worked we need to copy the pvp file from the Master Server we used to import the vDisk to the other
					#servers in the same site
					
					Logline "Copying PVP files to Site Servers from Secondary Masters"
					
					foreach ($line in $PVSRunTable.Rows)
					{
						
						$LineNumber=$row.Number
						
						#Use $SlaveSite and $SlaveStore
						$lnPrimaryMaster=$line.MasterServer
						$lnSecondaryMaster=$line.SlaveServer
						$lnSMStore=$line.SlaveStore
						$lnSMSite=$line.SlaveSite
						$lnSMStorePathEntry=$line.SlavePath
						If ($lnSMStorePathEntry[1] -eq ":") 
						{
							$lnSMStorePath = "\\$lnSecondaryMaster\"+$lnSMStorePathEntry.Replace(":", "$")
						}
						else
						{
							$lnSMStorePath = $lnSMStorePathEntry
						}
						$lnPMStorePathEntry=$line.MasterPath
						If ($lnPMStorePathEntry[1] -eq ":") 
						{
							$lnPMStorePath = "\\$lnPrimaryMaster\"+$lnPMStorePathEntry.Replace(":", "$")
						}
						else
						{
							$lnPMStorePath = $lnPMStorePathEntry
						}
						
						$myPVPFile = "$lnPMStorePath\" + $diskLocatorName + ".pvp"
						
						if (($SlaveSite -eq $lnSMSite) -and ($SlaveStore -eq $lnSMStore))
						{
							#Then copy the PVP to the lines destination
							if ($lnSMStorePath -ne $SlavePath)
							{
								logline "Copying PVP File [$myPVPFile] to [$lnSMStorePath] on Server [$lnSecondaryMaster]"
								if ($RunMode -ne "Test")
								{
									Copy-Item $myPVPFile $lnSMStorePath -Force
									if (!$?)
									{
										$MyError = $Error[0]
										Logline "***Error [$MyError]"
									}
								}
								else
								{
									Logline "Test Mode: PVP file would have been copied."
								}
							}
						}
					}
				
					#Copy the manifest to the log folder
					Copy $xmlFileSecondary $LogFolder 
					#Delete the manifest
					Del $xmlFileSecondary
					
					#Get the disk and check all settings
					if ($RunMode -eq "Test")
					{
						Logline "test Mode:Checking Disk Properties on vDisk [$diskLocatorName] is skipped"
					}
					else
					{
						Logline "Checking Disk Properties on vDisk [$diskLocatorName]"
						$TestSecondaryDisk = Get-PvsDisk -DiskLocatorId $SecondaryDiskLocator.DiskLocatorId
						$diskTestMismatch = ""
						$dlt_ActivationDateEnabled = $TestSecondaryDisk.ActivationDateEnabled
						if ($dlt_ActivationDateEnabled -ne $dl_ActivationDateEnabled){$diskTestMismatch+= " ActivationdateEnabled"}
						
						$dlt_HaEnabled = $TestSecondaryDisk.HAEnabled 
						if ($dlt_HaEnabled -ne $dl_HaEnabled){$diskTestMismatch+= " ActivationdateEnabled"}
						
						$dlt_AdPasswordEnabled = $TestSecondaryDisk.ADPasswordEnabled 
						if ($dlt_ActivationDateEnabled -ne $dl_ActivationDateEnabled){$diskTestMismatch+= " HaEnabled"}
						
						$dlt_PrinterManagementEnabled = $TestSecondaryDisk.PrinterManagementEnabled 
						if ($dlt_PrinterManagementEnabled -ne $dl_PrinterManagementEnabled){$diskTestMismatch+= " PrinterManagementEnabled"}
						
						$dlt_WriteCacheType = $TestSecondaryDisk.WritecacheType 
						if ($dlt_WriteCacheType -ne $dl_WriteCacheType){$diskTestMismatch+= " WriteCacheType"}
						
						$dlt_WriteCacheSize = $TestSecondaryDisk.WriteCacheSize 
						if ($dlt_WriteCacheSize -ne $dl_WriteCacheSize){$diskTestMismatch+= " WriteCacheSize"}
						
						$dlt_LicenseMode = $TestSecondaryDisk.LicenseMode 
						if ($dlt_LicenseMode -ne $dl_LicenseMode){$diskTestMismatch+= " LicenseMode"}
						
						$dlt_VHDX = $TestSecondaryDisk.VHDX
						if ($dlt_VHDX -ne $dl_VHDX){$diskTestMismatch+= " VHDX"}
						if($diskTestMismatch -ne "")
						{
							$rowSettingsMatch = "No"
							Logline "Disk Update Failed for disk for disk [$StoreFileName] on Server [$SecondaryMaster] Site[$SlaveSite] Store[$SlaveStore]."
							Logline "The following settings did not match [$diskTestMismatch]"
						}
						else
						{
							$rowSettingsMatch = "Yes"
							Logline "Disk Update Succeeded for disk for disk [$StoreFileName] on Server [$SecondaryMaster] Site[$SlaveSite] Store[$SlaveStore]."
						}
						$TableImportRow = $vDiskImportTable.NewRow()
						
						$TableImportRow.SlaveServer = $SecondaryMaster
						$TableImportRow.SlaveStore = $SlaveStore
						$TableImportRow.vDiskFile = $StoreFileName
						$TableImportRow.Imported = $rowvDiskImported
						$TableImportRow.SettingsMatch = $rowSettingsMatch
						$vDiskImportTable.Rows.Add($TableImportRow)
					}
					#clear variables
					$diskTestMismatch = ""
					$PrimDisk = $null
					$SecondaryDisk = $null
					$TestSecondaryDisk = $null
				}
			}
			else
			{
				Logline "**** Error: XML File Failed to copy from [$xmlfile] to [$xmlFileSecondary]"
				Logline "**** Import Failed"
			}
		}
	}
}

#===================================================================================
#Now we will cycle through all master servers checking to see if any vDisks
#need to be DELETED from any stores.  We will look at every DiskLocator to see if the
#vDisk exists.  If it does not we will remove the vDisk from the store.
#===================================================================================

If ($RunDelete)
{
	Logline "============================================================================================="
	Logline "vDisk Deleting has been enabled.  Will check for deleted vDisks to remove store entries"
	Logline "============================================================================================="
	Logline ""
	
	$mydeltrlog = "$LogFolder\trlog.txt"
	$mydeltrlogout = "This log can be used to review the state of vDisks prior to deletion."
	$mydeltrlogout += "`n`r"
	foreach ($MasterSrv in $arrImportServers)
	{
		$mydeltrlogout += "Processing $MasterSrv`r`n"
		logline ""
		Logline "Processing Master Server [$MasterSrv]"
		#Lets Connect to the server
		Set-PvsConnection -Server $MasterSrv -ErrorAction:SilentlyContinue
		if (!$?)
		{
			Logline "**** Warning Connection to Master Server [$MasterSrv] Failed"
			Logline "**** Skipping this Server"
			continue
		}
		#Lets get the server info
		$MyServer = Get-PvsServer -ServerName $MasterSrv
		$mySite = $myServer.SiteName
		
		Logline "Getting Stores for Master Server [$MasterSrv]"
		$MasterSrvStores = Get-PvsStore
		
		$Storecount = $MasterSrvStores.count
		
		if ($Storecount -gt 0)
		{
			Logline "[$Storecount] Stores were found for Master Server [$MasterSrv]"
		}
		else
		{
			Logline "***No Stores were fpund for Master Server [$MasterSrv] skippiong this server"
			continue
		}
		
		
		foreach ($MasterSrvStore in $MasterSrvStores)
		{
			$myDiskLocators = $null
			$myStore = $MasterSrvStore.storeName
			$MyStorepath = $MasterSrvStore.Path
			$myStorePathType = $MasterSrvStore.PathType
			$mydeltrlogout += "Processing Store $myStore`r`n"
			
			#Convert store path to a network path
			if ($myStorePathType -eq "Local")
			{
				$arrRemoteScriptFilePath = $MyStorepath.split(":")
				$RemoteDrive = $arrRemoteScriptFilePath[0]
				$RemoteFolder = $arrRemoteScriptFilePath[1]
				$StorePath = "\\$masterSrv\$RemoteDrive`$$RemoteFolder"
			}
			else
			{
				$StorePath = $MyStorepath
			}
			
			Try
			{
				logline ""
				Logline "Getting vDisks for Server [$MasterSrv] Site [$mySite] Store [$myStore]"
				$myDiskLocators = Get-PvsDiskLocator  -SiteName "$mySite" -StoreName "$myStore" 
			}
			Catch
			{
		        Logline "*** No vDisks found for Server [$MasterSrv] Site [$mySite] Store [$myStore]"
				#no disklocator found
			}
			
			#Now go through all the vDisks Versions and make sure the file exists.
			
			foreach ($DiskLocator in $myDiskLocators)
			{
				#Now lets get each version
				$DiskVersions = Get-PvsDiskVersion -DiskLocatorId $DiskLocator.DiskLocatorId
				$diskLocatorName = $DiskLocator.Name
				$TRDiskLcatorId = $DiskLocator.DiskLocatorId
				$mydeltrlogout += "---------------------------------`r`n"
				$mydeltrlogout += "Processing Disklocator $diskLocatorName $TRDiskLcatorId `r`n"
				[string]$ActProp = $DiskLocator.Active
				$mydeltrlogout += "Disklocator Active property [$ActProp]`r`n"
				
				#We treat the delete differently if there are more than one version
				$NumberOfVersions = $DiskVersions.count
				if ($NumberOfVersions -eq 1)
				{
					#In this case since there is only one version its not an array we can get the filename directly as a property
					$DiskFile = $DiskVersions.DiskFileName
					Logline "DiskLocator named [$diskLocatorName] with file name [$DiskFile] will be checked in the path [$StorePath]"
					$DiskFilePath = "$StorePath\$DiskFile"
					#Lets see if this file exists
					if (Test-Path -Path $DiskFilePath)
					{
						Logline "+++Filename [$DiskFile] exists. So it will be skipped."
						continue
					}
					#File doesnt exist we can remove it as its the only version
					Logline "+++Filename [$DiskFile] does not exist. It will be removed."
					#To check lets make sure there is no usage
					$vDiskInfo = Get-PvsDiskInfo -DiskLocatorId $DiskLocator.DiskLocatorId
					$testActive = $vDiskInfo.Active
					[string]$TRVersion = $DiskVersion.Version
					[string]$TRType = $DiskVersions.Type
					[string]$TRAccess = $DiskVersions.Access
					[string]$TRDeviceCount = $DiskVersions.DeviceCount
					[string]$TRGoodInventoryStatus = $DiskVersions.GoodInventoryStatus
					[string]$TRCanDelete = $DiskVersions.CanDelete
					[string]$TRDiskLocatorId = $DiskVersions.DiskLocatorId
					$mydeltrlogout += "=========`r`n"
					$mydeltrlogout += "Active DiskLocator [$testActive]`r`n"
					$mydeltrlogout += "Version [$TRVersion]`r`n"
					$mydeltrlogout += "Type [$TRType]`r`n"
					$mydeltrlogout += "Access [$TRAccess]`r`n"
					$mydeltrlogout += "Devicecount [$TRDeviceCount]`r`n"
					$mydeltrlogout += "GoodInventoryStatus [$TRGoodInventoryStatus]`r`n"
					$mydeltrlogout += "CanDelete [$TRCanDelete]`r`n"
					$mydeltrlogout += "DiskLocatorId [$TRDiskLocatorId]`r`n"
					$mydeltrlogout += "=========`r`n"
					if ($testActive)
					{
						Logline "****Error vDisk with Disklocator named [$diskLocatorName] with file name [$DiskFile] and version [$DiskVersion] is marked as Active - It will not be removed"
						continue
					}
					
					#Then we can delete this vDisk here
					if ($RunMode -ne "Test")
					{
						Remove-PvsDiskLocator -DiskLocatorId $DiskLocator.DiskLocatorId
						if ($?)
						{
							Logline "vDisk named [$diskLocatorName] with file name [$DiskFile] was removed from Server [$MasterSvr] Site [$mySite] Store [$myStore]"
						}
						else
						{
							$MyError = $Error[0]
							Logline "****Error vDisk named [$diskLocatorName] with file name [$DiskFile] was NOT removed from Server [$MasterSvr] Site [$mySite] Store [$myStore]"
							Logline "Error: [$MyError]"
						}
						
					}
					else
					{
						Logline "TestMode: vDisk named [$diskLocatorName] with file name [$DiskFile] would have been removed from Server [$MasterSvr] Site [$mySite] Store [$myStore]"
					}
					#jump to next vDisk
					continue
				}
				else
				{
					#Now if there is more than one version go through each version to check for the file
					Logline "---DiskLocator [$diskLocatorName] has multiple versions. We will process each version."
					foreach ($DiskVersion in $DiskVersions)
					{
						#IntraSystems
						$DiskFile = $DiskVersion.DiskFileName
						$bCanDelete = $DiskVersion.CanDelete	
						$VersionType = $DiskVersion.Type
						Logline "DiskLocator named [$diskLocatorName] with file name [$DiskFile] will be checked in the path [$StorePath]"
						$DiskFilePath = "$StorePath\$DiskFile"
						$mydeltrlogout += "Active DiskLocator [$testActive]`r`n"
						[string]$TRVersion = $DiskVersion.Version
						[string]$TRType = $DiskVersion.Type
						[string]$TRAccess = $DiskVersion.Access
						[string]$TRDeviceCount = $DiskVersion.DeviceCount
						[string]$TRGoodInventoryStatus = $DiskVersion.GoodInventoryStatus
						[string]$TRCanDelete = $DiskVersion.CanDelete
						[string]$TRDiskLocatorId = $DiskVersion.DiskLocatorId
						$mydeltrlogout += "=========`r`n"
						$mydeltrlogout += "Version [$TRVersion]`r`n"
						$mydeltrlogout += "Type [$TRType]`r`n"
						$mydeltrlogout += "Access [$TRAccess]`r`n"
						$mydeltrlogout += "Devicecount [$TRDeviceCount]`r`n"
						$mydeltrlogout += "GoodInventoryStatus [$TRGoodInventoryStatus]`r`n"
						$mydeltrlogout += "CanDelete [$TRCanDelete]`r`n"
						$mydeltrlogout += "DiskLocatorId [$TRDiskLocatorId]`r`n"
						$mydeltrlogout += "=========`r`n"
						if (!(Test-Path -Path $DiskFilePath))
						{
							Logline "+++Filename [$DiskFile] does not exist.  This DiskLocator for this version will be removed"
							$DiskVersion = $DiskVersion.Version
							#To check lets make sure there is no usage
							if (!$bCanDelete)	 
							{
								Logline "****Error vDisk with Disklocator named [$diskLocatorName] with file name [$DiskFile] and version [$DiskVersion] is marked as CanDelete = False - It will not be removed"
								continue
							}
							
							Logline "Disk version is [$DiskVersion] will remove this version"
							if ($RunMode -ne "Test")
							{
								Remove-PvsDiskVersion -DiskLocatorId $DiskLocator.DiskLocatorId -Version $DiskVersion
								if ($?)
								{
									Logline "vDisk named [$diskLocatorName] Version [$DiskVersion] with file name [$DiskFile] was removed from Server [$MasterSvr] Site [$mySite] Store [$myStore]"
								}
								else
								{
									$MyError = $Error[0]
									Logline "****Error vDisk Version for vDisk named [$diskLocatorName] Version [$DiskVersion] with file name [$DiskFile] was NOT removed from Server [$MasterSvr] Site [$mySite] Store [$myStore]"
									Logline "Error: [$MyError]"
								}
							}
							else
							{
								Logline "TestMode: vDisk named [$diskLocatorName] Version [$DiskVersion] with file name [$DiskFile] would have been removed from Server [$MasterSvr] Site [$mySite] Store [$myStore]"
							}
						}
						else
						{
							Logline "Filename [$DiskFile] was found.  This DiskLocator will NOT be removed"
						}
					}
				}
			}
		}
	}
}

$mydeltrlogout | Out-File -LiteralPath $mydeltrlog -Encoding ASCII 

#===============================================================
#Lets Cleanup unnecessary lok, pvp and xml files
#===============================================================
If ($CleanupLPX)
{
	Logline "============================================================================================="
	Logline "CleanupLPX has been enabled.  Will Cleanup Unused lok, pvp and xml files"
	Logline "============================================================================================="
	Logline ""
	
	$mylpxlog = "$LogFolder\lpxCleanupLog.txt"
	$mylpxlogout = "This log can be used to review the state of lok, pvp and xml file cleanup."
	$mylpxlogout += "`n`r"
	
	#First we need to clean up the files in the master stores
	Set-PvsConnection -Server $PrimaryMaster -ErrorAction:SilentlyContinue
	$PrimaryMasterStores = Get-PvsStore -ServerName $PrimaryMaster
	Foreach ($StoreInstance in $PrimaryMasterStores)
	{
		$SlaveStore = $StoreInstance.storeName
		$myStorePathType = $StoreInstance.pathType
		$MyStorepath = $StoreInstance.path
		#Convert store path to a network path
		if ($myStorePathType -eq "Local")
		{
			$arrRemoteScriptFilePath = $MyStorepath.split(":")
			$RemoteDrive = $arrRemoteScriptFilePath[0]
			$RemoteFolder = $arrRemoteScriptFilePath[1]
			$SlavePath = "\\$PrimaryMaster\$RemoteDrive`$$RemoteFolder"
		}
		else
		{
			$SlavePath = $MyStorepath
		}
		
		$mylpxlogout += "Processing Master Server $PrimaryMaster`r`n"
		logline ""
		Logline "Processing Master Server [$PrimaryMaster]"
		#Lets Connect to the server
		$SlavePathAll = "$SlavePath\*"
		$FilesToCheck = Get-ChildItem -Path $SlavePathAll  -File -Include "*.lok","*.pvp","*.xml"
		if (!$?)
		{
			Logline "**** Warning Connection to Slave Server [$SlaveServer] Failed for lok, pvp and xml file cleanup"
			Logline "**** Skipping this Server"
			continue
		}
		#Now lets look at every file and see if there is an associated vDidk.  If not lets delete it.
		
		foreach ($FileSpec in $FilesToCheck)
		{
			$BaseFile = $FileSpec.BaseName
			$FullFileName = $FileSpec.FullName
			Logline "Checking file $FullFileName"
			$mylpxlogout += "Checking file $FullFileName`r`n"
			$vhdName = "$BaseFile.vhd"
			$vhdxName = "$BaseFile.vhdx"
			$avhdName = "$BaseFile.avhd"
			$avhdxName = "$BaseFile.avhdx"
			Logline "Getting files matching $vhdName,$vhdxName,$avhdName,$avhdxName for slave path [$SlavePathAll]"
			$Test = Get-ChildItem -Path $SlavePathAll -File -include $vhdName,$vhdxName,$avhdName,$avhdxName
			If ($Test -eq $null)
			{
				Logline "vDisk matching file $FullFileName not Found - Will delete $FullFileName"
				$mylpxlogout += "vDisk matching file $FullFileName not Found - Will delete $FullFileName `r`n"
				if ($RunMode -ne "Test")
				{
					Try
					{
						logline ""
						Logline "Deleting $FullFileName"
						logline ""
						Remove-Item -Path "$FullFileName"
					}
					Catch
					{
				        Logline "*** File $FullFileName Could not be deleted"
					}
				}
				else
				{
					Logline "TestMode: vDisk matching file $FullFileName not Found - Will delete $FullFileName"
					$mylpxlogout += "TestMode: vDisk matching file $FullFileName not Found - Will delete $FullFileName `r`n"
				}
			}
			else
			{
				Write-Host "vDisk matching file $FullFileName Found - Will Not delete $FullFileName `r`n"
			}
		}
	}
	
	#Now lets do all the slave stores
	Foreach ($TableRow in $PVSRunTable.Rows)
	{
		$LineNumber=$TableRow.Number
		$SlaveFarm = $TableRow.SlaveFarm
		$SlaveSite = $TableRow.SlaveSite
		$SlaveServer = $TableRow.SlaveServer
		$SlaveStore = $TableRow.SlaveStore
		$SlavePath = $TableRow.SlavePath
		$IPG = $TableRow.IPG
		$Status=$TableRow.Status
		$RunAfter=$TableRow.RunAfter

		$mylpxlogout += "Processing $SlaveServer`r`n"
		logline ""
		Logline "Processing Slave Server [$SlaveServer]"
		#Lets Connect to the server
		$SlavePathAll = "$SlavePath\*"
		$FilesToCheck = Get-ChildItem -Path $SlavePathAll  -File -Include "*.lok","*.pvp","*.xml"
		if (!$?)
		{
			Logline "**** Warning Connection to Slave Server [$SlaveServer] Failed for lok, pvp and xml file cleanup"
			Logline "**** Skipping this Server"
			continue
		}
		#Now lets look at every file and see if there is an associated vDisk.  If not lets delete it.
		
		foreach ($FileSpec in $FilesToCheck)
		{
			$BaseFile = $FileSpec.BaseName
			$FullFileName = $FileSpec.FullName
			Logline "Checking file $FullFileName"
			$mylpxlogout += "Checking file $FullFileName`r`n"
			$vhdName = "$BaseFile.vhd"
			$vhdxName = "$BaseFile.vhdx"
			$avhdName = "$BaseFile.avhd"
			$avhdxName = "$BaseFile.avhdx"
			Logline "Getting files matching $vhdName,$vhdxName,$avhdName,$avhdxName for slave path [$SlavePathAll]"
			$Test = Get-ChildItem -Path $SlavePathAll -File -include $vhdName,$vhdxName,$avhdName,$avhdxName
			If ($Test -eq $null)
			{
				Logline "vDisk matching file $FullFileName not Found - Will delete $FullFileName"
				$mylpxlogout += "vDisk matching file $FullFileName not Found - Will delete $FullFileName `r`n"
				if ($RunMode -ne "Test")
				{
					Try
					{
						logline ""
						Logline "Deleting $FullFileName"
						logline ""
						Remove-Item -Path "$FullFileName"
					}
					Catch
					{
				        Logline "*** File $FullFileName Could not be deleted"
					}
				}
				else
				{
					Logline "TestMode: vDisk matching file $FullFileName not Found - Will delete $FullFileName"
					$mylpxlogout += "TestMode: vDisk matching file $FullFileName not Found - Will delete $FullFileName `r`n"
				}
			}
			else
			{
				#Write-Host "vDisk matching file $FullFileName Found - Will Not delete $FullFileName `r`n"
			}
		}
	}
	$mylpxlogout | Out-File -LiteralPath $mylpxlog -Encoding ASCII 

}


#===============================================================
#Create Log output for success and failure of each disk
#===============================================================

$outputHTMLSF+="<style>table, th, td {border: 1px solid black;}</style>"
$outputHTMLSF+="<p></p>"
$outputHTMLSF+="<h2>Secondary Site Import Status</h2>"
$outputHTMLSF+="<p>Import Status of vDisk Files on Secondary Sites and Masters</p>"
$outputHTMLSF+="<table><tr><th>Slave Server</th><th>Slave Store</th><th>vDisk</th><th>Successfully Imported</th><th>Settings Match Master</th></tr>"

foreach ($logrow in $vDiskImportTable.Rows)
{
	$vDiskName = $logrow.vDiskFile
	$logrowImported = $logrow.Imported
	$logrowMatch = $logrow.SettingsMatch
	$logrowSlaveServer = $logrow.SlaveServer
	$logRowSlaveStore = $logrow.SlaveStore
	
	if($logrowImported -eq "Yes")
	{
		$outputHTMLSF+="<tr style='color:black'><td>$logrowSlaveServer</td><td>$logRowSlaveStore</td><td>$vDiskName</td><td>$logrowImported</td><td>$logrowMatch</td></tr>"
	}
	else
	{
		$outputHTMLSF+="<tr style='color:red'><td>$logrowSlaveServer</td><td>$logRowSlaveStore</td><td>$vDiskName</td><td>$logrowImported</td><td>$logrowMatch</td></tr>"
	}
}
$outputHTMLSF+="</table>"

#Now Run the Replication Status Report
."$ScriptSource\ReplStatus.ps1"
sleep 1

#Now copy the replstatus.html into the log directory
copy -Path "$ScriptSource\..\config\ReplStatus.html" -Destination $LogFolder

#Now Run the Storage Space Status Report
#We suppress the email because the html file will get included in the master email
."$ScriptSource\GetStoreSpace.ps1" -SuppressEmail $true
sleep 1

#Now copy the StoreSpaceStatus.html into the log directory
copy -Path "$ScriptSource\..\config\StoreSpaceStatus.html" -Destination $LogFolder


#==================================================
#   Lets Document Some information
#==================================================
Logline ""
Logline "Document Environment"
Logline "================================================================"
$OSVerison = (Get-CimInstance Win32_OperatingSystem).version
Logline "OSVersion:$OSVerison"
$ComputerName = $ENV:ComputerName
Logline "ComputerName:$ComputerName"
$PSVersion = $PSVersionTable.PSVersion
Logline "PowerShell Version:$PSVersion"
Logline "PSExec Credentials:$PSAccount"
Logline "Primary Master:$PrimaryMaster"
Logline "Primary Master Server PVS Version:$MasterServerPVSVersion"
Logline "Copy Method:$CopyMethod"
Logline ""
Logline "Master Servers"
Logline "------------------------------------------------"
foreach ($Row in $Masters)
{
	Logline "$Row"
}
Logline "------------------------------------------------"
Logline ""
Logline "Secondary Masters"
Logline "------------------------------------------------"
foreach ($Row in $arrImportServers)
{
	Logline "$Row"
}
Logline "------------------------------------------------"
Logline ""
Logline "Rows to Process"
Logline "------------------------------------------------"
foreach ($Row in $RowsToProcess)
{
	Logline "$Row"
}
Logline "------------------------------------------------"
Logline ""
Logline "Included Files"
Logline "------------------------------------------------"
foreach ($File in $IncludeFiles)
{
	Logline "$File"
}
Logline "------------------------------------------------"
Logline ""
Logline "Excluded Files"
Logline "------------------------------------------------"
foreach ($File in $ExcludeFiles)
{
	Logline "$File"
}
Logline "------------------------------------------------"

Logline "================================================================"

#Add any Errors found to log file
FormatErrors
"`r`nErrors" | Out-file -FilePath $global:LogFile -Encoding ASCII -Append
"--------------------------------------------------" | Out-file -FilePath $global:LogFile -Encoding ASCII -Append
$global:FormatedErrors | Out-file -FilePath $global:LogFile -Encoding ASCII -Append

if ($SendEmail)
{
	Logline "Email has been enabled.  Sending Status Email"
	#Get Attachments
	$myLogDir = Get-Item -Path $LogFolder
	$arrAttachments = Get-ChildItem -Path $myLogDir  -Exclude *.rcj
	
	$EmailAttach = $outputHTML + $outputHTMLSF
	
	Sendmail $arrAttachments $EmailAttach
}


Logline "==========================================="
Logline "Processing Complete"
Logline "==========================================="

