Posts RSS Comments RSS 130 Posts and 202 Comments till now

Sync Folder Script.

I initially wrote this for a guy on the NG, but I decided to use at work to sync some application folders I used to store tools and scripts and such. Please Try it out and tell me what you think.

Basic Flow
- Checks for Folders that Source has the Destination Does NOT and Creates.
- Checks for Folders that Destination has the Source Does NOT and Creates.
- Checks for files that Source has the Destination Does NOT and Copies.
- If the file is found in both, the MD5 of both files are checked… Last Write Wins
- Checks for Folders that Destination has the Source Does NOT
- It does NOT Delete anything yet… I am considering using a mirror switch

Param($Source,$Destination)
function Get-FileMD5 {
   Param([string]$file)
   $mode = [System.IO.FileMode]("open")
   $access = [System.IO.FileAccess]("Read")
   $md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
   $fs = New-Object System.IO.FileStream($file,$mode,$access)
   $Hash = $md5.ComputeHash($fs)
   $fs.Close()
   [string]$Hash = $Hash
   Return $Hash
}
function Copy-LatestFile{
    Param($File1,$File2,[switch]$whatif)
    $File1Date = get-Item $File1 | foreach-Object{$_.LastWriteTimeUTC}
    $File2Date = get-Item $File2 | foreach-Object{$_.LastWriteTimeUTC}
    if($File1Date -gt $File2Date)
    {
        Write-Host "$File1 is Newer… Copying…"
        if($whatif){Copy-Item -path $File1 -dest $File2 -force -whatif}
        else{Copy-Item -path $File1 -dest $File2 -force}
    }
    else
    {
        Write-Host "$File2 is Newer… Copying…"
        if($whatif){Copy-Item -path $File2 -dest $File1 -force -whatif}
        else{Copy-Item -path $File2 -dest $File1 -force}
    }
    Write-Host
}

if(!(test-Path $Destination))
{
    New-Item $Destination -type Directory -force | out-Null
}

# Getting Files/Folders from Source and Destination
$SrcEntries = Get-ChildItem $Source -Recurse
$DesEntries = Get-ChildItem $Destination -Recurse

# Parsing the folders and Files from Collections
$Srcfolders = $SrcEntries | Where-Object{$_.PSIsContainer}
$SrcFiles = $SrcEntries | Where-Object{!$_.PSIsContainer}
$Desfolders = $DesEntries | Where-Object{$_.PSIsContainer}
$DesFiles = $DesEntries | Where-Object{!$_.PSIsContainer}

# Checking for Folders that are in Source, but not in Destination
foreach($folder in $Srcfolders)
{
    $SrcFolderPath = $source -replace "\\","\\" -replace "\:","\:"
    $DesFolder = $folder.Fullname -replace $SrcFolderPath,$Destination
    if($DesFolder -ne ""){
        if(!(test-path $DesFolder))
        {
            Write-Host "Folder $DesFolder Missing. Creating it!"
            new-Item $DesFolder -type Directory | out-Null
        }
    }
}

# Checking for Folders that are in Destinatino, but not in Source
foreach($folder in $Desfolders)
{
    $DesFilePath = $Destination -replace "\\","\\" -replace "\:","\:"
    $SrcFolder = $folder.Fullname -replace $DesFilePath,$Source
    if($srcFolder -ne "")
    {
        if(!(test-path $SrcFolder))
        {
            Write-Host "Folder $SrcFolder Missing. Creating it!"
            new-Item $SrcFolder -type Directory | out-Null
        }
    }
}

# Checking for Files that are in the Source, but not in Destination
foreach($entry in $SrcFiles)
{
    $SrcFullname = $entry.fullname
    $SrcName = $entry.Name
    $SrcFilePath = $Source -replace "\\","\\" -replace "\:","\:"
    $DesFile = $SrcFullname -replace $SrcFilePath,$Destination
    if(test-Path $Desfile)
    {
        $SrcMD5 = Get-FileMD5 $SrcFullname
        $DesMD5 = Get-FileMD5 $DesFile
        If($srcMD5 -ne $desMD5)
        {
            Write-Host "The Files MD5’s are Different… Checking Write Dates"
            Write-Host $SrcMD5
            Write-Host $DesMD5
            Copy-LatestFile $SrcFullname $DesFile
        }
    }
    else
    {
        Write-Host "$Desfile Missing… Copying from $SrcFullname"
        copy-Item -path $SrcFullName -dest $DesFile -force
    }
}

# Checking for Files that are in the Destinatino, but not in Source
foreach($entry in $DesFiles)
{
    $DesFullname = $entry.fullname
    $DesName = $entry.Name
    $DesFilePath = $Destination -replace "\\","\\" -replace "\:","\:"
    $SrcFile = $DesFullname -replace $DesFilePath,$Source
    if($SrcFile -ne "")
    {
        if(!(test-Path $SrcFile))
        {
            Write-Host "$SrcFile Missing… Copying from $DesFullname"
            copy-Item -path $DesFullname -dest $SrcFile -force
        }
    }
}

Write-Host

No Responses to “Sync Folder Script.”

  1. on 06 Sep 2007 at 2:45 amGreg M

    Why not just use Robocopy with the appropriate parameters?

  2. on 06 Sep 2007 at 9:56 amBrandon

    Perfectly Valid Comment and one I asked myself in the beginning and I did it for three reasons.
    1) To see how hard it would be
    and More importantly. I learn a lot writing this script.
    2) I found value in the ability to customize the functionality at will.
    3) To show the power of Powershell.

    One of my main goals of Powershell is negate the need to EVER use external exe.

  3. on 06 Sep 2007 at 11:45 amGreg M

    You know, as soon as I wrote that I knew the answer. Valid pursuits all and a great effort. Thanks for keeping us up on the TMTOWTDI aspects of Posh.

    Cheers

  4. on 30 Nov 2007 at 4:28 pmSloot

    through experimentation, I have determined that -whatif can be passed to a cmdlet as follows
    Copy-Item -path $File1 -dest $File2 -force -whatif:$whatif

    the following syntax also works

    Copy-Item -path $File1 -dest $File2 -force -whatif $whatif

    but I don’t like to read that as much.

    Using this technique removes the need for your if ($whatif) blocks.

  5. on 30 Nov 2007 at 4:43 pmBrandon

    Great catch!

    I have used that before, but when I post on the blog I try to be super clear.

    Perhaps I will do a blog entry on this :)

Trackback this post | Feed on Comments to this post

Leave a Reply

CAPTCHA image