Link to home
Start Free TrialLog in
Avatar of SpacedustPL
SpacedustPL

asked on

Disk2VHD image backup with automatic removal of old images when backup drive is full

I've got the following script that I'm running as scheduled task each day.

It makes a VHD image of C: drive (447 GB) and copy it to F: drive (3,63 TB) and removes old vhd images when there is more than 4 of these.

I would like to modify it so it would take current disk space usage from C drive and compare it with current disk usage of F drive. If there will be less space on F than it's needed to backup whole C then the last image would be removed.

It would be good to use fsutil utility:

C:\Users\Marek>fsutil volume diskfree c:
Całkowita liczba bajtów wolnych           : 244490219520
Całkowita liczba bajtów                   : 480127946752
Całkowita liczba dostępnych bajtów wolnych: 244490219520

C:\Users\Marek>fsutil volume diskfree f:
Całkowita liczba bajtów wolnych           : 324223422464
Całkowita liczba bajtów                   : 4000575385600
Całkowita liczba dostępnych bajtów wolnych: 324223422464

REM
REM A simple backup system using disk2vhd
REM
REM version 1.3, by J.E.B., 2011-02-22
REM
REM requires 'disk2vhd.exe' to be in the path
REM

setLocal EnableDelayedExpansion

REM "DRIVES" can be one drive identifier with colon, multiple separated by spaces,
REM or asterisk for all.  
REM "DEST" can be a drive letter or a UNC.

SET DRIVES="C:"
SET DEST="F:"

REM Keep most recent 4 VHD files in DEST, delete the rest

for /f "skip=4 tokens=* delims= " %%a in ('dir/b/o-d %DEST%\*.VHD') do (
del %DEST%\%%a
)

REM Backup to VHD

C:
cd \
DISK2VHD %DRIVES% %DEST%\%COMPUTERNAME%--%date:~-10,3%%date:~-7,2%%date:~-4,4%.VHD

EXIT /B n
Avatar of Tony J
Tony J
Flag of United Kingdom of Great Britain and Northern Ireland image

I've just knocked up the following powershell script but can't easily test it's individual components.

It's possibly not the most graceful solution, if I'm honest, but it should work.

I put the /1073741824 in whilst I was testing as it made for easier numbers on the eye. There's no functional reason for it to remain unless you wanted to pipe some of the variables out.

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force
}

#Once enough free space has been created on F: this function creates the latest VHD
Function CreateVHD {
$filename = (get-date -uformat %d%b%y) + "_"  + $Env:COMPUTERNAME + ".vhd"
.\disk2vhd c: ("F:\" +$filename) # The .\ assumes disk2vhd is in the same folder as this script;
}

#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
Do {
if ($fdisk -lt $Cdiskused) {
write-host "Not enough free space on F: Drive. Deleting oldest image"
DelVHD
diskspace
}
}
until ($fdisk -gt $Cdiskused)

write-host "Enough free space on F:\ found...creating latest VHD"
CreateVHD

Open in new window

Avatar of SpacedustPL
SpacedustPL

ASKER

I'm running on Windows 7 Ultimate and nothing happens:

C:\Users\Marek>powershell -noexit "& ""C:\backup2.ps1"""
No errors?

I just ran it and as far as I can (no disk2vhd etc) it tries to remove oldest files due to a lack of disk space.

Running powershell as an Adminitrator?

For debugging I prefer to use the powershell ISE
I just created a few thousand empty files and I can see them being deleted in the correct order. I can also see the disk space count going up, so the tests for free space and the deletion function are definitely working for me.
Oh I just noticed - powershell -noexit "& ""C:\backup2.ps1""" won't work

Try:

powershell -noexit -command C:\backup2.ps1
Even running under 64-bit PowerShell ISE doesn't show any errors. It's just running but nothing is moving on.
It seems the first part is working. It stops when trying to run disk2vhd.

Get it here: https://download.sysinternals.com/files/Disk2vhd.zip (it's free).
I need a bit more info - as I say, it's running fine for me here but I am running PS as an administrator;

When you say it's running but nothing is moving on...?

Have you made sure that disk2vhd.exe is in the same folder as the script or change this line to an explicit path:

.\disk2vhd <-- e.g. C:\Disk2VHD (also try adding the .exe).

Do you see either of the following lines output?

Enough free space on F:\ found...creating latest VHD

or

Not enough free space on F: Drive. Deleting oldest image
?

If the latter, can you see any .VHD files being deleted? Remembe the script assumes they're in the root of the F: drive.
I may also have misformed the vhd2disk line -

Try changing it to

.\disk2vhd c: "F:\"$filename
disk2vhd.exe and backup2.ps1 is in the same path (root of C:\ drive).

I do not see any output just blinking cursor.

I'm currently making the drive full so I can see if it removes old images.

Changing .\disk2vhd c: "F:\"$filename or to .\disk2vhd.exe c: "F:\"$filename does not help either.
Ok so you run the script and it does what? Says there's enough free space or not enough free space?

If it's the latter, it's going to take it a fair amount of time to delete a 400-odd GB file and you'll get no feedback at that point until it's deleted the file.

If there's then enough space, you should see the message saying so at which point it will try to create the VHD.

Not sure you get any visual feedback from disk2vhd when it's run from a command line.
It says nothing but when I've just leave the first part till

#Once enough free space has been created on F: this function creates the latest VHD

then it ends as I have enough disk space.

I will check again when the disk is full now.
Grumble... my bad.

Change the CreateVHD function to:

#Once enough free space has been created on F: this function creates the latest VHD
Function CreateVHD {
$filename = (get-date -uformat %d%b%y) + "_"  + $Env:COMPUTERNAME + ".vhd"
$filename = "F:\"+$Filename
write-host .\disk2vhd c: $filename # The .\ assumes disk2vhd is in the same folder as this script;
}

Open in new window


You will notice the slight change of the filename parameter
The original was adding in an additional space so it effectively appeared like this:

.\disk2vhd c: F:\ 21Sep15_TESTBED.vhd <-- See the space between the \ and the 2 ?

Whereas now it resolves correctly:

.\disk2vhd c: F:\21Sep15_TESTBED.vhd <-- No space!
Please see how it looks:

User generated image
try
for /F "tokens=* skip=4" %%A in ('dir /b /a-d /o-d "%DRIVES%\%DEST%\*.VHD"') do del "%DEST%\%%~A"
please note the ''' (3) after VHD and that the entire command "%DRIVES%\%DEST%\*.VHD" is in " " too
I'm an idiot and this is what you get for not clearing out variables.

Need to move where diskpace is called!

#This loop kicks everything off - it gets the free disk space, deletes files one at a time on D: as required and then creates the VHD when there is sufficient disk space freed up.
Do {
if ($fdisk -lt $Cdiskused) {
diskspace
write-host "Not enough free space on D: Drive. Deleting oldest image"
DelVHD
}
}
until ($fdisk -gt $Cdiskused)

Open in new window

Still nothing. Just blinking cursor.
How very odd

I am looking at the same thing on my PC merrily deleting files.

Can you try just running this snippet?

#This function is called repeatedly until the space on the D: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}
diskspace

Open in new window


It should just return the free space on F: and the used space on C:, nothing more.
That works well ;)

PS C:\Users\Marek> powershell -noexit -command C:\test.ps1
82,8459358215332
221,111248016357

Open in new window

Good.

Now can we expand to simply delete files?

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force
}


#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
Do {
if ($fdisk -lt $Cdiskused) {
diskspace
write-host "Not enough free space on F: Drive. Deleting oldest image"
DelVHD
}
}
until ($fdisk -gt $Cdiskused)
diskspace

Open in new window

Blinking cursor again - no output ;)

Also nothing is removed. I got two VHD images waiting in the root of F: drive.
How big are the files?

Might be that they are going but it will take a while.
231 GB each - it takes about 2-3 seconds to remove them normally from Seagate 5900 rpm 4 TB drive.
Also I got about 4% CPU (2x Intel Xeon X5675) usage when running this script - it's probably some infinite loop.
This is how my F: drive look like:


    Directory: F:\


Mode                LastWriteTime     Length Name                                                                                                                                             
----                -------------     ------ ----                                                                                                                                             
-ar--        2015-04-15     20:49        528 MediaID.bin                                                                                                                                      
d----        2015-05-02     19:22            WindowsImageBackup6                                                                                                                              
d----        2015-05-06     13:37            WindowsImageBackup7                                                                                                                              
d----        2015-05-12     12:00            WindowsImageBackup8                                                                                                                              
d----        2015-05-17     12:00            WindowsImageBackup9                                                                                                                              
d----        2015-05-22     20:51            WindowsImageBackup10                                                                                                                             
d----        2015-05-24     13:53            WindowsImageBackup11                                                                                                                             
d----        2015-06-01     12:00            WindowsImageBackup12                                                                                                                             
d----        2015-06-03     15:07            WindowsImageBackup13                                                                                                                             
d----        2015-06-08     12:18            WindowsImageBackup14                                                                                                                             
d----        2015-06-15     12:01            WindowsImageBackup15                                                                                                                             
d----        2015-06-19     12:01            WindowsImageBackup16                                                                                                                             
d----        2015-06-26     12:01            WindowsImageBackup17                                                                                                                             
d----        2015-07-10     12:47            WindowsImageBackup18                                                                                                                             
d----        2015-07-23     12:01            WindowsImageBackup19                                                                                                                             
d----        2015-08-03     12:01            WindowsImageBackup20                                                                                                                             
d----        2015-08-08     13:22            WindowsImageBackup21                                                                                                                             
d----        2015-08-11     12:01            WindowsImageBackup22                                                                                                                             
d----        2015-09-02     22:35            WindowsImageBackup23                                                                                                                             
d----        2015-09-16     16:58            WindowsImageBackup                                                                                                                               
-a---        2015-09-16     16:55 2311530024 MACPRO--2015-9-16.VHD                                                                                                                            
                                          96                                                                                                                                                  
-a---        2015-09-21     14:10 2311530024 MACPRO--2015-9-21.VHD                                                                                                                            
                                          96                         

Open in new window

This seems to be working:

Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force

but asks for confirmation
When put inside a function it doesn't make anything - it quits immediately:

#This function will simply delete the oldest file in the root of the F: drive
function test {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force
}

Open in new window

You have to call it:

#This function will simply delete the oldest file in the root of the F: drive
function test {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force
}
test

Open in new window

Hmm the -force should make it assume "Yes"
And yes...I created some 500MB files to test and they went in seconds.
I got it :) I've needed to add -Recurse parameter because I got some folder from WindowsImageBackup:

#This function will simply delete the oldest file in the root of the F: drive
function test {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}
test

Open in new window

So this works for me so far - the oldest one is removed ;)

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}

DelVHD

Open in new window

Also I don't know why it removing the oldest folders first instead of files ;)
Interesting - you shouldn't really have required the recurse switch.

What happens if you now add on the function to test for free space?

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}

Do {
if ($fdisk -lt $Cdiskused) {
diskspace
write-host "Not enough free space on D: Drive. Deleting oldest image"
DelVHD
}
}
until ($fdisk -gt $Cdiskused)

Open in new window

Duh..I just spotted you have folders. Yeah that'd need the recurse switch.
Again blinking cursor and nothing is moving on ;(

Something is wrong here:

Do {
if ($fdisk -lt $Cdiskused) {
diskspace
write-host "Not enough free space on D: Drive. Deleting oldest image"
DelVHD
}
}
until ($fdisk -gt $Cdiskused)

Open in new window

I am losing it.

That _exact_ piece of code gives this on mine (I just dropped a few 500MB files into the folder):

0.267337799072266
107.147037506104
Not enough free space on F: Drive. Deleting oldest image
0.697784423828125
107.147037506104
Not enough free space on F: Drive. Deleting oldest image
1.12823104858398
107.147037506104
Not enough free space on F: Drive. Deleting oldest image
1.55867767333984
107.147037506104
Not enough free space on F: Drive. Deleting oldest image
1.9891242980957
107.147037506104

Open in new window

Maybe a typo here ? See the USed or used:

$CdiskUSed = $CdiskCapacity-$CDiskFree

Open in new window


and here:

if ($fdisk -lt $Cdiskused) {

Open in new window


or here:

until ($fdisk -gt $Cdiskused)

Open in new window

powershell isn't case sensitve. :)
Even If I do something like this:

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}


#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
if ($fdisk -gt $Cdiskused) {
write-host "Not enough free space on F: Drive. Deleting oldest image"
}
diskspace

Open in new window


it doesn't work properly:

PS C:\Users\Marek> C:\backup2.ps1
1153,06732559204
221,418174743652

Open in new window

Can you try a slight change to yours?

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function DiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
$fdisk = $fdisk.freespace/1073741824

return $Fdisk, $cdiskUsed
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}


#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
diskspace
if ($fdisk -gt $Cdiskused) {
write-host "Not enough free space on F: Drive. Deleting oldest image"
}
diskspace

Open in new window


You will notice I've added an additional call to the diskspace function
I got this:
PS C:\Users\Marek> C:\backup2.ps1
1153,06732559204
221,421562194824
1153,06732559204
221,421562194824

Open in new window

Sorry for the delay replying.

So if I nulled the values I got the same result as you. It would appear that the values weren't coming back from the function correctly and rather than try to waste our time looking into why, it was quicker to rewrite slightly.

Could you try the following:

# Null all the values
$Cdisk = $null
$Fdisk = $null
$CdiskCapacity =  $null
$CdiskFree =  $null
$CdiskUSed =  $null

#This function is called to determine the used space on the C: drive
function UsedDiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
return $cdiskUsed
}

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function FreeDiskSpace() {
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$fdisk = $fdisk.freespace/1073741824
return $Fdisk
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}

#Once enough free space has been created on F: this function creates the latest VHD
Function CreateVHD {
$filename = (get-date -uformat %d%b%y) + "_"  + $Env:COMPUTERNAME + ".vhd"
$filename = "F:\"+$Filename
.\disk2vhd c: $filename # The .\ assumes disk2vhd is in the same folder as this script;
}

#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.

Do {
$c = useddiskspace
$f = freediskspace


if ($f -lt $c) {

write-host "Space used on C: = "$c"
write-host "Free space on F: = "$f"
write-host "Not enough free space on F: Drive. Deleting oldest image"
DelVHD
}
}
until ($fdisk -gt $Cdiskused)

write-host "Enough free space on F:\ found...creating latest VHD"
CreateVHD

Open in new window


I have this working, even with the values all nicely nulled.
Still nothing - just blinking cursor ;(
The good thing is - this works for me - disk2vhd is started ;)

# Null all the values
$Cdisk = $null
$Fdisk = $null
$CdiskCapacity =  $null
$CdiskFree =  $null
$CdiskUSed =  $null

#This function is called to determine the used space on the C: drive
function UsedDiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
return $cdiskUsed
}

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function FreeDiskSpace() {
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$fdisk = $fdisk.freespace/1073741824
return $Fdisk
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}

#Once enough free space has been created on F: this function creates the latest VHD
Function CreateVHD {
$filename = (get-date -uformat %d%b%y) + "_"  + $Env:COMPUTERNAME + ".vhd"
$filename = "F:\"+$Filename
.\disk2vhd c: $filename # The .\ assumes disk2vhd is in the same folder as this script;
}

#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
write-host "Enough free space on F:\ found...creating latest VHD"
CreateVHD

Open in new window

Typo crept in (I am trying to manage two copies as I don't have an F: drive and I don't want everything in my D: drive deleted, just a test folder).

change
until ($fdisk -gt $Cdiskused)

Open in new window


to

until ($f -gt $c)

Open in new window

If I change

if ($f -lt $c) {

Open in new window


to

if ($f -gt $c) {

Open in new window


Then it works - removes all the images on the disk ;)
ASKER CERTIFIED SOLUTION
Avatar of Tony J
Tony J
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Good - it works now,

Would be great to hide Disk2Vhd inside a tray icon ;)
Yeah unfortunately it doesn't look like there is a command line to do that :)

Sorry it took so many iterations....I shouldn't think "Hmmm...5 minute script will do this"
I will be testing it for a few days now ;)
Let me know how you get on!

One of the reasons I like powershell is it's fairly easy to set up scheduled tasks to run jobs like this overnight in the background.
It works well but I got this Windows Powershell left opened when the script is finished ;)

Maybe we can add some exit out there ?
You still running it with the noexit switch?...
Yes - that's probably the reason ;) Now it closes itself.

Is there any possibility to hide Disk2VHD window ?
Ok I'll caveat this by saying it's another quick hit but my equally quick test suggests it'll work:

# Null all the values
$Cdisk = $null
$Fdisk = $null
$CdiskCapacity =  $null
$CdiskFree =  $null
$CdiskUSed =  $null
$Hidden = $null

#This function is called to determine the used space on the C: drive
function UsedDiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
return $cdiskUsed
}

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function FreeDiskSpace() {
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$fdisk = $fdisk.freespace/1073741824
return $Fdisk
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}

#Actually create the VHD
Function CreateVHD($Hidden) {
$filename = (get-date -uformat %d%b%y) + "_"  + $Env:COMPUTERNAME + ".vhd"
$filename = "F:\"+$Filename
    If ($Hidden -eq $True){.start-process -WindowStyle Hidden .\disk2vhd.exe c: $filename } # The .\ assumes disk2vhd is in the same folder as this script;
    ElseIf ($Hidden -eq $False){.\disk2vhd.exe c: $filename } # The .\ assumes disk2vhd is in the same folder as this script;
}


#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
Do {
$c = useddiskspace
$f = freediskspace


if ($f -lt $c) {

write-host "Space used on C: = "$c
write-host "Free space on F: = "$f
write-host "Not enough free space on F: Drive. Deleting oldest image"
DelVHD
}
}
until ($f -gt $c)

write-host "Enough free space on F:\ found...creating latest VHD"
CreateVHD $True #$True to hide the process; $False to have it run visible

Open in new window

OK. I will check it out ;)
It doesn't work. Disk2VHD does not start ;(
See this error:

PS C:\> C:\backup.ps1
Enough free space on F:\ found...creating latest VHD
.start-process : The term '.start-process' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, v
erify that the path is correct and try again.
At C:\backup.ps1:34 char:28
+     If ($Hidden -eq $True){.start-process -WindowStyle Hidden .\disk2vhd.exe c:  ...
+                            ~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (.start-process:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Open in new window

Also please note: You can use 1GB instead of 1073741824.
Oh man. Shouldn't be a . In front of start-process
Now I got this ;)

PS C:\> C:\backup.ps1
Enough free space on F:\ found...creating latest VHD
Start-Process : A positional parameter cannot be found that accepts argument 'F:\23wrz15_MACPRO.vhd'.
At C:\backup.ps1:34 char:28
+     If ($Hidden -eq $True){start-process -WindowStyle Hidden .\disk2vhd.exe c: $ ...
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Process], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand

Open in new window

This the problem when your test environment is ever so slightly different.

Needed to pass the arguments separately to the start-process line:

# Null all the values
$Cdisk = $null
$Fdisk = $null
$CdiskCapacity =  $null
$CdiskFree =  $null
$CdiskUSed =  $null

#This function is called to determine the used space on the C: drive
function UsedDiskSpace() {
$Cdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$CdiskCapacity = $Cdisk.size/1073741824
$CdiskFree = $Cdisk.freespace/1073741824
$CdiskUSed = $CdiskCapacity-$CDiskFree
return $cdiskUsed
}

#This function is called repeatedly until the space on the F: drive is greater than the used space on the C: drive
function FreeDiskSpace() {
$Fdisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='F:'" | Select-Object Size,FreeSpace
$fdisk = $fdisk.freespace/1073741824
return $Fdisk
}

#This function will simply delete the oldest file in the root of the F: drive
Function DelVHD {
Get-ChildItem F:\ | Sort CreationTime | Select -First 1 | Remove-Item -force -Recurse
}

#Create the VHD - pass $true to run the Disk2VHD program hidden; $False for visible. First run should be false to allow agreement of EULA.!
Function CreateVHD($Hidden) {
$filename = (get-date -uformat %d%b%y) + "_"  + $Env:COMPUTERNAME + ".vhd"
$filename = "F:\"+$Filename
    If ($Hidden -eq $True){
        start-process -WindowStyle Hidden .\disk2vhd.exe -argumentlist 'c:', $filename # The .\ assumes disk2vhd is in the same folder as this script;
    }
        ElseIf ($Hidden -eq $False){.\disk2vhd.exe c: $filename # The .\ assumes disk2vhd is in the same folder as this script;
    }
}

#This loop kicks everything off - it gets the free disk space, deletes files one at a time on F: as required and then creates the VHD when there is sufficient disk space freed up.
Do {
$c = useddiskspace
$f = freediskspace


if ($f -lt $c) {

write-host "Space used on C: = "$c
write-host "Free space on F: = "$f
write-host "Not enough free space on F: Drive. Deleting oldest image"
DelVHD
}
}
until ($f -gt $c)

write-host "Enough free space on F:\ found...creating latest VHD"
CreateVHD $true #NOTE - Run with $False so the Disk2VHD window is visible at least the first time in order to accept the EULA

Open in new window

It works now, but disk2vhd window is still visible ;(
For goodness sake...it would appear that if you don't pass additional command line parameters to disk2vhd it's perfectly happy to run hidden...the moment you pass them it displays

Which is somewhat backwards, in my humble opinion.

Sorry mate...looks like visible is the only option. :(
Probably I would need to run it with some tray minimizer ;)
Found what I was looking for ;) http://www.whitsoftdev.com/trayconizer/
It's not working - must be too old for Windows 7 SP1