#This script file is intended to provide a single page status for disk usage for PVS Stores

#This script was created by Rob Zylowski Citrix CCS
#
#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.
#
#Created 3-31-2019
#Added email 5-27-2019

#Modified 6-25-2019
#Changed name of SendMail function because it was being used in the vdiskpreplicator.ps1 when it shouldn't be.
#That fixed an issue where this script would not supress the email when it was called from the vdiskreplicator script.
#Also changed the script to set default values if none are saved in the ui.

#Modified 8-27-2020
#Changed the report to show errors when it cannot connect to a PVS Server

Param ($SuppressEmail = $false)

function Get-ScriptDirectory
#This gets the current directory which we use to store the text data files
{
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value
 Split-Path $Invocation.MyCommand.Path
}

Function SendMailSS($BodyHTMLFile)
{
	#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)
	}

	Write-Host "Sending Email To $txtMailTo at mail relay $txtMailRelay ...."
	$txtMailSubject = "PVS Storage Space Report"
	$BodyHTML = Get-Content -Path "$BodyHTMLFile" -Encoding ASCII
	$message = New-Object Net.Mail.MailMessage($txtMailFrom, $txtMailTo, $txtMailSubject, $BodyHTML)
	$myFile = $fileAttachment.FullName
	$message.IsBodyHtml = $true
	$SMTPClient.Send($message)	
	$message.Dispose()
}
#---------------------------------------------------------------
#            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
			$credential = New-Object System.Management.Automation.PsCredential("mailman",$passwordback)
			$MailmanPW = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($credential.Password))
			$global:MyPassword = $MailmanPW
		}	
		else
		{
			Logline "No Credentials defined.  Email cannot be sent."
			Logline ""
		}
	}
}

Write-Host ""
Write-Host "Running Store Usage Report"
Write-Host ""
Write-Host "SupressEmail:$SuppressEmail"

$ScriptSource = Get-ScriptDirectory
$global:imagefolder = "$ScriptSource\..\images"
$StoreSpaceStatusFile = "$ScriptSource\..\config\StoreSpaceStatus.html"

$datetime = Get-Date -Format F
try{
    Import-Module 'C:\Program Files\Citrix\Provisioning Services console\Citrix.PVS.SnapIn.dll' -ErrorAction Stop
} catch {
    Write-Host "PVS PowerShell Snap-In Not Found on $env:computername.  Script terminated."
	exit
}
$ConfFile =  "$ScriptSource\..\config\StoreSpaceConfig.txt"
if (Test-Path $ConfFile)
{
	$ConfFileContent = Get-Content "$ConfFile" -Encoding ASCII
	$arCritcal = $ConfFileContent[0] -split "::"
	$arWarning = $ConfFileContent[1] -split "::"
	$CriticalPercent = $arCritcal[0]/100
	$CriticalBgColor = $arCritcal[1]
	$WarnningPercent = $arWarning[0]/100
	$WarnningBgColor = $arWarning[1]
	if ($CriticalPercent -eq $null){$CriticalPercent = .9}
	if ($CriticalBgColor -eq $null){$CriticalBgColor = "#ff3333"}
	if ($WarnningPercent -eq $null){$WarnningPercent = .7}
	if ($WarnningBgColor -eq $null){$WarnningBgColor = "#ffff33"}
}
else
{
	$CriticalPercent = .9
	$CriticalBgColor = "#ff3333"
	$WarnningPercent = .7
	$WarnningBgColor = "#ffff33"
}


#Lets set up the header for our html output file
$h = "<!DOCTYPE html>
	<html>
	<head>
	<style>
	 H1 { font-family:Verdana,Arial,Helvetica,Sans-Serif; font-size:medium; }
     H2 { font-family:Verdana,Arial,Helvetica,Sans-Serif;font-size:small; }
     p { font-family:Verdana,Arial,Helvetica,Sans-Serif; font-size:small;margin:0;padding:0 }
	table, th, td {
	    border: 1px solid black;
	    border-collapse: collapse;
		font-family:Verdana,Arial,Helvetica,Sans-Serif; font-size:small;
	}
	</style>
	</head>
	<body>
	<h2 style='color:blue'>PVS Storage Usage Status as of <font color='Black'>$datetime</font></h2>"

	$t="<table cellpadding=""10"" border=""1"">"
	$t+="<tr><th>Farm</th><th>Site</th><th>PVS Server</th><th>Store</th><th>Drive/Share</th><th>Percent Full</th><th>Free Space (GB)</th><th>Total Space (GB)</th></tr>"


#Get the Master master Server.  This is the source of all teh replications.
$Masters = Get-Content "$ScriptSource\..\config\masters.txt"

#Loop through the Master Servers to get sites, servers and stores.
foreach ($MasterServer in $Masters)
{
	Write-Host "Connecting to Master Server [$MasterServer]"
	Set-PvsConnection -Server $MasterServer
	$FarmInfo = Get-PvsFarm
	$Farm = $FarmInfo.FarmName
	$MySites = Get-PvsSite
	foreach ($SiteInfo in $MySites)
	{
		$Site = $SiteInfo.SiteName
		
		Write-Host "Getting PVS Servers for Site [$Site]"

		#Now get all PVS Servers in the Site
		$PVSServers = Get-PvsServer -SiteName $Site
		
		foreach ($PVSServer in $PVSServers)
		{
		
			#Lets get the stores on this server
			$myServerName = $PVSServer.ServerName
			$myServerId = $PVSServer.ServerId
			Write-Host "Getting Stores for PVS server [$myServerName]"
			$MyStores = Get-PvsStore -ServerId $myServerId
		
			foreach ($StoreInfo in $MyStores)
			{
				$size = 0
				$sizeGB = 0
				$SizeforReport = 0
				$freespace = 0
				$freespaceGB = 0
				$freespaceforReport = 0

				$myStoreName = $StoreInfo.StoreName
				$storePath = $StoreInfo.Path
				if ($storePath.Substring(0,2) -eq "\\")
				{
						$ShareServerSlash = $storePath.Substring(2).IndexOf("\")
						$ShareServer = $storePath.Substring(2,$ShareServerSlash)
						$Share = Get-WmiObject Win32_Share -ComputerName $ShareServer -Filter "Name = `'$myStoreName`'"
						$ShareLocalPath = $Share.path
						$StoreDisk = $ShareLocalPath.Substring(0,2)
						$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $ShareServer -Filter "DeviceID=`'$StoreDisk`'" | Foreach-Object {$_.Size,$_.FreeSpace}
						$DriveforReport = $storePath
				}
				else
				{
						$StoreDisk = $StoreInfo.Path.Substring(0,2)
						$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $myServerName -Filter "DeviceID=`'$StoreDisk`'" | Foreach-Object {$_.Size,$_.FreeSpace}
						$DriveforReport = $StoreDisk
				}
				
				if ($disk -ne $null)
				{
					$size = $disk[0]
					$sizeGB = $size/1000000000
					$SizeforReport = $sizeGB.ToString("n0")
					$freespace = $disk[1]
					$freespaceGB = $freespace/1000000000
					$freespaceforReport = $freespaceGB.ToString("n0")

					$percentFull = ($Size-$freespace)/$Size
					$percentFullString = $percentFull.ToString("P")
				}
				Else
				{
					$SizeforReport = "Error"
					$freespaceforReport = "Error"
					$percentFullString = "Error"
				}
				Write-Host "Server [$myServerName] Store [$myStoreName] is [$percentFullString] full"
				$NL = "<tr>"
				if ($percentFullString -eq "Error")
				{
					$NL = "<tr bgcolor=`"$CriticalBgColor`">"
				}
				elseif ($percentFull -gt $WarnningPercent)
				{
					$NL = "<tr bgcolor=`"$WarnningBgColor`">"
				}
				if ($percentFull -gt $CriticalPercent)
				{
					$NL = "<tr bgcolor=`"$CriticalBgColor`">"
				}
				$t+="$NL<td>$Farm</td><td>$Site</td><td>$myServerName</td><td>$myStoreName</td><td>$DriveforReport</td><td>$percentFullString</td><td>$freespaceForReport</td><td>$SizeforReport</td></tr>"
			}
		}
	}
}
$t +="</table>"

##writing html table to a html file 
$f += "</table><p>&nbsp;</p><p>The tables above list each vDisk and its replication status. Status codes are defined as follows: 0 = up to date, 1 = version file is 
missing, 2 = version file is out of date, 3 = properties are missing, 4 = properties are out of date, 5 = server 
is not reachable, 6 = no load balancing configured.</p></body></html>"
 
$h+$t | out-file $StoreSpaceStatusFile -Encoding ASCII

sleep 2

#We only want to email when this script is run on its own.  If its called from the UI or the vDiskReplicator script the emailing will be suppressed.
if (!$SuppressEmail)
{
	if ($SendEmail)
	{
		Write-Host "Email has been enabled.  Sending Status Email"
		SendMailSS  $StoreSpaceStatusFile
	}
}

Write-Host "Process Complete"

Sleep 3



