The script writes zeros to unused spaces on all disk inside all VMs to free space in thin provisioned SAN based Hyper-V Cluster.
To do this, the VMs in the Hyper-V Cluster ($Clustername) are enumerated and a powershell based sdelete runs inside all VMs.
The Powershell code to zero out free spaces is original written by Chris Duck (http://blog.whatsupduck.net/2012/03/powershell-alternative-to-sdelete.html)
Customize the variable $Clustername and run the sript with elevated permissions.
You can exclude VMs costumizing $VMsExclude with VM name
sThe script will use your account to run the PS script inside the VMs, therfor it prompts for your password
### ------------------------------------
<#
ScriptVersion 1.3
4/17/2017
Guido Jeuken
The script writes zeros to unused spaces on all disk inside all VMs to free space in thin provisioned SAN based Hyper-V Cluster.
To do this, the VMs in the Hyper-V Cluster ($Clustername) are enumerated and a powershell based sdelete runs inside all VMs.
The Powershell code to zero out free spaces is original written by Chris Duck (http://blog.whatsupduck.net/2012/03/powershell-alternative-to-sdelete.html)
so all files in folder C:-Windows-ProPatches-Patches wants to deletetd
customize the variable $Clustername and run the sript with elevated permissions.
you can exclude VMs costumizing $VMsExclude with VM names
the script will use your account to run the PS script inside the VMs, therfor it prompts for your password
#>
### ------------------------------------
Cls
• customize this
$Clustername= "nameofcluster"
$VMsToExclude= "vm1*"
Cls
$pw = read-host "Please enter your password" -AsSecureString
$uName = $env:USERNAME
$Cred = New-Object System.Management.Automation.PSCredential $uName, $pw
import-module failoverclusters
$VMsinCluster = Get-ClusterResource -cluster $Clustername | Where-Object . . . . . . . . . . . . . ResourceType -eq "Virtual Machine" | Get VM
foreach ($VM, $VMsinCluster)
{
if ($VM.vmname -like $VMsToExclude) - skip if VMname is like $VMsToExclude
{
Write host $VM.VMName "excluded"
Continue
}
$S = new-PSSession -ComputerName $VM.VMName -Credential $Cred
Write host "running sdelete in" $VM.VMName
invoke-Command -Session $S -ScriptBlock - function doSdelete ($Root)
#Convert the $Root value to a valid WMI filter string
$FixedRoot = ($Root.Trim("") -replace "A",""""" + ""
$FileName = "ThinSAN.tmp"
$FilePath = Join-Path $Root $FileName
$PercentFree =.1
#Check and make sure the file doesn't already exist so we don't clobber someone's data
if( (Test-Path $FilePath) )
Write-Error message "The file $FilePath already exists, please delete the file and try again"
• else . . . . . . . . .
#Get a reference to the volume so we can calculate the desired file size later
Write host "writing zeros at $Root"
$Volume = gwmi win32_volume -filter "name='$FixedRoot'"
if ($Volume)
#I have not tested for the optimum IO size ($ArraySize), 64kb is what sdelete.exe uses
$ArraySize = 64kb
#Calculate the amount of space to leave on the disk
$SpaceToLeave = $Volume.Capacity * $PercentFree
#Calculate the file size needed to leave the desired amount of space
$FileSize = $Volume.FreeSpace - $SpacetoLeave
#Create an array of zeroes to write to disk
$ZeroArray = new-object byte[]($ArraySize)
#Open a file stream to our file
$Stream = [io.File]::OpenWrite($FilePath)
#Start a try/finally block so we don't leak file handles if any exceptions occur
try
#Keep track of how much data we've written to the file
$CurFileSize = 0
while($CurFileSize -lt $FileSize)
#Write the entire zero array buffer out to the file stream
$Stream.Write($ZeroArray.0, $ZeroArray.Length)
#Increment our file size by the amount of data written to disk
$CurFileSize += $ZeroArray.Length
}
• Finally . . . . . . . . .
#always close our file stream, even if an exception occurred
if ($Stream)
$Stream.Close()
}
#always delete the file if we created it, even if an exception occurred
if( (Test-Path $FilePath) )
del $FilePath
}
}
• else . . . . . . . . .
Write-Error "Unable to locate a volume mounted at $Root"
}
}
}
#MAIN
Write host "I'm inside" $env:COMPUTERNAME
$PatchDirToDelete="C:"Windows-ProPatches-Patches"*.*"
#delete shavlik patchmgnt folder
if( (Test-Path $PatchDirToDelete) )
remove-item $PatchDirToDelete -Confirm:$false
}
$csvs = Get-WmiObject Win32_Volume -filter "drivetype=3"
foreach ($cvs in $csvs)
{
$env:computername+" "+ $cvs.driveletter
$root = ([string]$cvs.driveletter)
doSdelete -root $Root
}
}
}