We help IT Professionals succeed at work.

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

203 Views
Last Modified: 2015-09-24
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
Comment
Watch Question

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

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

C:\Users\Marek>powershell -noexit "& ""C:\backup2.ps1"""
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
Oh I just noticed - powershell -noexit "& ""C:\backup2.ps1""" won't work

Try:

powershell -noexit -command C:\backup2.ps1

Author

Commented:
Even running under 64-bit PowerShell ISE doesn't show any errors. It's just running but nothing is moving on.

Author

Commented:
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).
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
I may also have misformed the vhd2disk line -

Try changing it to

.\disk2vhd c: "F:\"$filename

Author

Commented:
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.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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.

Author

Commented:
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.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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!

Author

Commented:
Please see how it looks:

Screenshot
Lionel MMSmall Business IT Consultant
CERTIFIED EXPERT

Commented:
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
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
Still nothing. Just blinking cursor.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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.

Author

Commented:
That works well ;)

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

Open in new window

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
Blinking cursor again - no output ;)

Also nothing is removed. I got two VHD images waiting in the root of F: drive.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
How big are the files?

Might be that they are going but it will take a while.

Author

Commented:
231 GB each - it takes about 2-3 seconds to remove them normally from Seagate 5900 rpm 4 TB drive.

Author

Commented:
Also I got about 4% CPU (2x Intel Xeon X5675) usage when running this script - it's probably some infinite loop.

Author

Commented:
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

Author

Commented:
This seems to be working:

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

but asks for confirmation

Author

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
Hmm the -force should make it assume "Yes"
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
And yes...I created some 500MB files to test and they went in seconds.

Author

Commented:
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

Author

Commented:
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

Author

Commented:
Also I don't know why it removing the oldest folders first instead of files ;)
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
Duh..I just spotted you have folders. Yeah that'd need the recurse switch.

Author

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
powershell isn't case sensitve. :)

Author

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
I got this:
PS C:\Users\Marek> C:\backup2.ps1
1153,06732559204
221,421562194824
1153,06732559204
221,421562194824

Open in new window

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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.

Author

Commented:
Still nothing - just blinking cursor ;(

Author

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
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 ;)
Lead Technical Architect
CERTIFIED EXPERT
Commented:
This one is on us!
(Get your first solution completely free - no credit card required)
UNLOCK SOLUTION

Author

Commented:
Good - it works now,

Would be great to hide Disk2Vhd inside a tray icon ;)
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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"

Author

Commented:
I will be testing it for a few days now ;)
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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.

Author

Commented:
It works well but I got this Windows Powershell left opened when the script is finished ;)

Maybe we can add some exit out there ?
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
You still running it with the noexit switch?...

Author

Commented:
Yes - that's probably the reason ;) Now it closes itself.

Is there any possibility to hide Disk2VHD window ?
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
OK. I will check it out ;)

Author

Commented:
It doesn't work. Disk2VHD does not start ;(

Author

Commented:
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

Author

Commented:
Also please note: You can use 1GB instead of 1073741824.
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
Oh man. Shouldn't be a . In front of start-process

Author

Commented:
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

Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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

Author

Commented:
It works now, but disk2vhd window is still visible ;(
Tony JohncockLead Technical Architect
CERTIFIED EXPERT

Commented:
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. :(

Author

Commented:
Probably I would need to run it with some tray minimizer ;)

Author

Commented:
Found what I was looking for ;) http://www.whitsoftdev.com/trayconizer/

Author

Commented:
It's not working - must be too old for Windows 7 SP1

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Unlock the solution to this question.
Join our community and discover your potential

Experts Exchange is the only place where you can interact directly with leading experts in the technology field. Become a member today and access the collective knowledge of thousands of technology experts.

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.