source

파워셸 스크립트를 사용하여 두 폴더를 동기화하는 방법

nicesource 2023. 8. 22. 22:13
반응형

파워셸 스크립트를 사용하여 두 폴더를 동기화하는 방법

두 개의 폴더가 있습니다.

  • FolderAD:\Powershell\원본
  • FolderBD:\Powershell\copy

이제, 저는 계속하고 싶습니다.FolderA그리고.FolderB동기화(즉, 사용자가 파일/디렉토리를 변경/수정/수정할 때)FolderA그러면 동일한 변화가 발생해야 합니다.FolderB).

노력했습니다.

$Date = Get-Date 
$Date2Str = $Date.ToString("yyyMMdd") 
$Files = gci "D:\Powershell\Original" 
ForEach ($File in $Files){
        $FileDate = $File.LastWriteTime
        $CTDate2Str = $FileDate.ToString("yyyyMMdd")
        if ($CTDate2Str -eq $Date2Str) { 
           copy-item "D:\Powershell\Original" "D:\Powershell\copy" -recurse    
           -ErrorVariable capturedErrors -ErrorAction SilentlyContinue; 
        } 
}

그러나 이를 위해서는 파일을 삭제하기 위해 유사한 파워셸 스크립트가 필요합니다.FolderA의 변화FolderB.

로보카피(Robocopy, 강력한 파일 복사)를 살펴보셨습니까?PS와 함께 사용할 수 있으며 원하는 것을 제공합니다. 즉, 폴더의 안정적인 복사 또는 미러링(변경/추가/제거)을 위해 설계되었습니다. 필요에 따라 옵션을 선택하기만 하면 됩니다.

Robocopy sourceFolder destinationFolder /MIR /FFT /Z /XA:H /W:5

/MIR옵션은 원본 디렉터리와 대상 디렉터리를 미러링합니다.원본에서 파일이 삭제된 경우 대상에 있는 파일이 삭제됩니다.

로보카피

다음을 시도해보셔야 할 것 같습니다. 요구 사항에 따라 syncMode 기반을 변경할 수 있습니다. 1은 단방향 동기화 소스에서 대상으로, 2는 이중방향 동기화입니다.

$source="The source folder" 
$target="The target folder" 

touch $source'initial.initial'
touch $target'initial.initial'

$sourceFiles=Get-ChildItem -Path $source -Recurse
$targetFiles=Get-ChildItem -Path $target -Recurse

$syncMode=2 

    try{
    $diff=Compare-Object -ReferenceObject $sourceFiles -DifferenceObject $targetFiles

    foreach($f in $diff) {
        if($f.SideIndicator -eq "<=") {
            $fullSourceObject=$f.InputObject.FullName
            $fullTargetObject=$f.InputObject.FullName.Replace($source, $target)

            Write-Host "Attemp to copy the following: " $fullSourceObject
            Copy-Item -Path $fullSourceObject -Destination $fullTargetObject
        }


        if($f.SideIndicator -eq "=>" -and $syncMode -eq 2) {
            $fullSourceObject=$f.InputObject.FullName
            $fullTargetObject=$f.InputObject.FullName.Replace($target,$source)

            Write-Host "Attemp to copy the following: " $fullSourceObject
            Copy-Item -Path $fullSourceObject -Destination $fullTargetObject
        }

    }
    }      
    catch {
    Write-Error -Message "something bad happened!" -ErrorAction Stop
    }
    rm $source'initial.initial'
    rm $target'initial.initial'

이전 답변 외에도 파일을 비교하는 방법에 대한 이 기사는 도움이 될 수 있습니다. 실제로 파일을 내용별로 비교하려면 추가 단계가 필요합니다.(해싱처럼)이 방법에 대한 자세한 설명은 https://mcpmag.com/articles/2016/04/14/contents-of-two-folders-with-powershell.aspx 에 나와 있습니다.

다음은 한 가지 동기화 방법을 유지하기 위한 본격적인 CLI입니다.

# Script will sync $source_folder into $target_folder and delete non relevant files. 
# If $target_folder doesn't exist it will be created. 

param ($source_folder, $target_folder, $cleanup_target = "TRUE", $log_file = "sync.log")

function Write-Log {
    Param ([string]$log_string, [string]$log_level = "INFO")
    $time_stamp = (Get-Date).toString("dd-MM-yyyy HH:mm:ss")
    $log_message = "$time_stamp [$log_level] $log_string"
    Add-content $log_file -value $log_message
    if ($log_level = "INFO") {
        Write-Host $log_message
    }
    elseif ($log_level = "ERROR") {
        Write-Error $log_message
    }
    elseif ($log_level = "WARNING") {
        Write-Warning $log_message
    }
    else {
        Write-Error "Wrong log level: $log_level"
        exit 1
    }
}

if (!(Test-Path -Path $source_folder -PathType Container)) {
    Write-Log "Source folder doesn't exist: $source_folder" "ERROR"
    exit 1
}

if (Test-Path -Path $target_folder -PathType Leaf) {
    Write-Log"Target object is file. Can't create target folder with the same name: $target_folder" "ERROR"
    exit 1
}

$source_content = Get-ChildItem -Path $source_folder -Recurse
if ($null -eq $source_content) { 
    $source_content = [array]
}

$target_content = Get-ChildItem -Path $target_folder -Recurse
if ($null -eq $target_content) { 
    $target_content = [array]
}

Write-Log "************************** Started syncing $source_folder >> $target_folder **************************"

$differences = Compare-Object -ReferenceObject $source_content -DifferenceObject $target_content


foreach ($difference in $differences) {
    if ($difference.SideIndicator -eq "<=") {
        $source_object_path = $difference.InputObject.FullName
        $target_object_path = $source_object_path.Replace($source_folder, $target_folder)
        if (Test-Path -Path $source_object_path -PathType Leaf) {
            $hash_source_file = (Get-FileHash $source_object_path -Algorithm SHA256).Hash
            if (Test-Path -Path $target_object_path -PathType Leaf) {
                $hash_target_file = (Get-FileHash $target_object_path -Algorithm SHA256).Hash
            }
            else {
                $hash_target_file = $null
            }
            if ( $hash_source_file -ne $hash_target_file ) {
                Write-Log "Synced file $source_object_path >> $target_object_path"
                Copy-Item -Path $source_object_path -Destination $target_object_path
            }
            else {
                Write-Log "Same file, will not sync $source_object_path >> $target_object_path"
            }
        }
        elseif (Test-Path -Path $target_object_path -PathType Container) {
            Write-Log "Folder already exists, will not sync $source_object_path >> $target_object_path"
        }
        else {
            Write-Log "Synced folder $source_object_path >> $target_object_path"
            Copy-Item -Path $source_object_path -Destination $target_object_path
        }        
    }
    elseif (($difference.SideIndicator -eq "=>") -and $cleanup_target -eq "TRUE") {
        $target_object_path = $difference.InputObject.FullName
        $source_object_path = $target_object_path.Replace($target_folder, $source_folder)
        if (!(Test-Path -Path $source_object_path) -and (Test-Path -Path $target_object_path)) {
            Remove-Item -Path $target_object_path -Recurse -Force
            Write-Log "Removed $target_object_path"
        }
    }
}
Write-Log "************************** Ended syncing $source_folder >> $target_folder **************************"

저는 양방향으로 작동하는 솔루션을 찾을 수 없어서 저만의 솔루션을 만들었습니다.

양방향 동기화의 주요 문제는 비교할 항목이 없기 때문에 파일이 한 폴더에 생성되었는지 다른 폴더에서 삭제되었는지 확인할 수 없다는 것입니다.

이 문제의 해결책은 파일이 아니라 디렉터리를 비교하는 것입니다.디렉토리의 수정 타임스탬프는 파일 또는 하위 폴더가 추가, 이름 변경 또는 삭제될 때만 변경됩니다.

이 스크립트는 두 디렉터리의 기존 파일과 폴더를 비교합니다.파일이 추가, 이름 변경 또는 삭제되었기 때문에 한 폴더가 더 최신인 경우 폴더가 미러링됩니다.

미러링 전에 재귀를 수행하여 수정된 파일을 덮어쓰기 전에 다시 복사합니다.이렇게 하면 항상 최신 파일을 유지하면서 파일 구조를 동기화할 수 있습니다.

$source = "D:\Homework"
$target = "C:\Users\User\Documents\Homework"

function Sync-Folders ($src, $dst) {
  Get-ChildItem $src | ForEach-Object {
    $srcPath = Join-Path $src $_.Name
    $dstPath = Join-Path $dst $_.Name

    if ($_.PSIsContainer) {
      if (Test-Path $dstPath) {
        $srcTime = (Get-Item $srcPath).LastWriteTime
        $dstTime = (Get-Item $dstPath).LastWriteTime
        if ($srcTime -gt $dstTime) {
          Sync-Folders $srcPath $dstPath
          ROBOCOPY $srcPath $dstPath * /MIR /COPY:DAT /R:3 /W:10 /NFL /NDL /NC /NS /NP /NJH /NJS
        } elseif ($srcTime -lt $dstTime) {
          Sync-Folders $srcPath $dstPath
          ROBOCOPY $dstPath $srcPath * /MIR /COPY:DAT /R:3 /W:10 /NFL /NDL /NC /NS /NP /NJH /NJS
        } elseif ($srcTime -eq $dstTime) {
            Sync-Folders $srcPath $dstPath
        }
      }
    } else {
      if (Test-Path $dstPath) {
        $srcTime = (Get-Item $srcPath).LastWriteTime
        $dstTime = (Get-Item $dstPath).LastWriteTime
        if ($srcTime -gt $dstTime) {
          Copy-Item $srcPath $dstPath
        } elseif ($srcTime -lt $dstTime) {
          Copy-Item $dstPath $srcPath 
        }
      }
    }
  }
}

Sync-Folders $source $target

Pause

언급URL : https://stackoverflow.com/questions/25869806/how-to-keep-2-folders-in-sync-using-powershell-script

반응형