Merge folders with Windows PowerShell script

Detect changes and merge folders and files with PowerShell script

When deploying application to specific location it is often required to deploy only few files and not the whole deployment package.

For example, if you changed only single static image file in your ASP.NET WebApplication, there is no reason to overwrite bin folder content and cause WebApplication on IIS to restart.

Similar example can be running Windows Service for which you changed only files excluding executable file which might be running and locked by the running Windows Service process. In case you are replacing all files in the destination folder and therefore restarting the windows service.

Some deployment tools provide these kind of options to replace only different files, but in some cases this is not available, so to avoid scenarios like this or similar we can always rely to PowerShell.

Before we start with the PowerShell script, we need to create some test folders for merging. I created the following two folders named SOURCE and DESTINATION with some dummy file which should represent the live scenario

Folder -Merge 

Hwere you can clearly see the differences between folders. To make it more obvious that we copied only the files that are different or missing, we are going to use a temporaty folder which for this sample I named TEMP.

Param([Parameter(Mandatory=$true)][string]$sourcePath,[Parameter(Mandatory=$true)][string]$destinationPath,[Parameter(Mandatory=$true)][string]$tempPath)if(!$tempPath.EndsWith("\")){$tempPath = $tempPath + "\"}$tmpContent = $tempPath "*"Remove-Item $tmpContent -Recurse -Force$files = Get-ChildItem -Path $sourcePath -Recurse -Filter "*.*"foreach($file in $files){$sourcePathFile = $file.FullName$destinationPathFile = $file.FullName.Replace($sourcePath, $destinationPath)$tempPathFile = $file.FullName.Replace($sourcePath, $tempPath)

    $exists = Test-Path $destinationPathFile

    if(!$exists){
        $dir = Split-Path -parent $tempPathFile
        if (!(Test-Path($dir))) { New-Item -ItemType directory -Path $dir }
        Copy-Item -Path $sourcePathFile -Destination $tempPathFile -Recurse -Force
    }
    else{
        $isFile = Test-Path -Path $destinationPathFile -PathType Leaf
       
        if($isFile){
            $different = Compare-Object -ReferenceObject $(Get-Content $sourcePathFile) -DifferenceObject $(Get-Content $destinationPathFile)
            if(Compare-Object -ReferenceObject $(Get-Content $sourcePathFile) -DifferenceObject $(Get-Content $destinationPathFile)){
            $dir = Split-Path -parent $tempPathFile
            if (!(Test-Path($dir))) { New-Item -ItemType directory -Path $dir }

                Copy-Item -Path $sourcePathFile -Destination $tempPathFile -Recurse -Force
            }
        }
    }
}
    

Now when we run this script with SOURCE, DESTINATION and TEMP folder full paths we should have only images and templates folder in it as their content is diffrent/missing in the destination folder.

Since we all the changes copied to TEMP folder, we just need to copy them to DESTINATION folder

Copy-Item -Path $tmpContent -Destination $destinationPath -Force -Recurse
    

File -merge -finished

We do not actually need TEMP folder, we only used it here to check the files to be copied and to confirm that only differences are copied. We can easily remove all operation with TEMP folder ad do directly copy to DESTINATION folder

Param(
[Parameter(Mandatory=$true)]
[string]$sourcePath,
[Parameter(Mandatory=$true)]
[string]$destinationPath
)


$files = Get-ChildItem -Path $sourcePath -Recurse -Filter "*.*"

foreach($file in $files){
    $sourcePathFile = $file.FullName
    $destinationPathFile = $file.FullName.Replace($sourcePath,  $destinationPath)

    $exists = Test-Path $destinationPathFile

    if(!$exists){
        $dir = Split-Path -parent $destinationPathFile
        if (!(Test-Path($dir))) { New-Item -ItemType directory -Path $dir }
        Copy-Item -Path $sourcePathFile -Destination $destinationPathFile -Recurse -Force
    }
    else{
        $isFile = Test-Path -Path $destinationPathFile -PathType Leaf
       
        if($isFile){
            $different = Compare-Object -ReferenceObject $(Get-Content $sourcePathFile) -DifferenceObject $(Get-Content $destinationPathFile)
            if(Compare-Object -ReferenceObject $(Get-Content $sourcePathFile) -DifferenceObject $(Get-Content $destinationPathFile)){
            $dir = Split-Path -parent $destinationPathFile
            if (!(Test-Path($dir))) { New-Item -ItemType directory -Path $dir }

                Copy-Item -Path $sourcePathFile -Destination $destinationPathFile -Recurse -Force
            }
        }
    }
}

    

 

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

.NET

read more

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

Comments for this article