Summary: Learn how to use Windows PowerShell to back up modified files to the network.
Hey, Scripting Guy! I have a folder that contains files in it, some of which I modify on a daily basis. I am wondering if I can use Windows PowerShell to back up only the modified files—those that have changed that particular day?
—NG
Hello NG,
Microsoft Scripting Guy, Ed Wilson, is here. I don’t know if you have noticed it, but for the last couple of weeks, many of the topics have related to items that are to be covered in the 2012 Scripting Games. Registration is not yet open, and the PoshCode site for the 2012 Scripting Games is not yet up, but things are progressing along nicely. If you are planning to compete in the games, you should be reviewing the 2012 Scripting Games Study Guide. (If the truth be told, even if you are not competing in the Scripting Games, you should be reviewing the Study Guide because it contains great information about essential tasks faced on a daily basis by network administrators.)
Two topics to be covered in the 2012 Scripting Games are working with files and working with folders. NG, your question happens to hit both topics. At its most basic level, backing up modified files from a folder involves the following two tasks:
- Find all the files that have changed during a particular period of time.
- Copy the modified files to another location.
Find modified files
By using Windows PowerShell, this first task is incredibly simple; in fact, it is a one-liner. The one-line command to search a folder named C:\data, and all of the folders contained inside that folder, for files that are written to today is shown here.
dir c:\data -r | ? {$_.lastwritetime -gt (get-date).date}
Just a few notes about this command:
- Dir is an alias for the Get-ChildItem cmdlet
- –r is short for -recurse
- ? is an alias for the Where-Object cmdlet
- (get-date).date returns todays date as of midnight
A longer and more readable version of the previous command is shown here.
Get-ChildItem -Path c:\data -Recurse | Where-Object { $_.lastwritetime -gt (get-date).date}
The two commands are exactly the same. In the image that follows, the first command is the short version of the command, and the second command is the long version of the command. The output from each is the same.
One problem with the two previous commands is that if a file inside of a directory reports modification, the folder also reports as changed. For this particular scenario, NG is only interested in modified files, not the actual folders containing the files. Therefore, a change to the Where clause needs to take place so that folders are filtered, but modified files remain. The first version (the short version of the command) is shown here with the necessary addition.
dir c:\data -r | ? {!($_.psiscontainer) -AND $_.lastwritetime -gt (get-date).date}
For ease of comparison, and to better illustrate the problem, the first command (returns folders and files) and the second command (returns only files) are shown in the figure that follows.
Note For more information about using and accessing special folders, refer to The Easy Way to Use PowerShell to Work with Special Folders. For more information about using Windows PowerShell to compress folders, refer to Using Windows PowerShell to Compress Folders.
Copy modified files to the network
To copy the modified files to the network is a rather easy task. I pipe the results of the command that obtains all the changed files to a Foreach-Object cmdlet, and then I use the Copy-Item cmdlet to copy the files to the network shared folder.
Unfortunately, the Copy-Item cmdlet is not smart enough to accept the objects that are returned by the Get-ChildItem cmdlet as direct input. It will accept strings that represent paths to files as pipelined input, but not the results from the Get-ChildItem. When I see that a command is unable to accept pipelined input in the way I want to provide it, it nearly always means that I can accomplish what I want to do by using the Foreach-Object cmdlet. The two parameters used by the Copy-Item cmdlet are the Path to the original file, and a path to the destination file. The Destination parameter only needs the path to the folder, and not the complete file to the actual file name. The % symbol is an alias for the Foreach-Object cmdlet.
dir c:\data -r | ? {!($_.psiscontainer) -AND $_.lastwritetime -gt (get-date).date} |
% {Copy-Item -path $_.fullname -destination \\hyperv1\shared\backup}
If you decide that you would like to use the Windows Task Scheduler to schedule the previous command, see Use Scheduled Tasks to Run PowerShell Commands on Windows.
NG, that is all there is to using Windows PowerShell to back up a folder. Join me tomorrow for more Windows PowerShell cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy