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 names
The 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)
all files in folder C:\Windows\ProPatches\Patches will also be 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 "Bitte Ihr Passwort eingeben" -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 in $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 "\\","\\") + "\\"
$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
}
}
}