from - Powershell Copy-Item pero solo copia archivos modificados
powershell copy-item overwrite (3)
Estoy tratando de responder a través de un directorio y copiarlo de A a B. Esto se puede hacer con lo siguiente:
Copy-Item C:/MyTest C:/MyTest2 –recurse
Sin embargo, quiero poder copiar solo los archivos nuevos (los que existen en src pero no dest) y también los archivos que pueden haber cambiado en base a una verificación CRC y no a una marca de fecha y hora.
$file = "c:/scripts"
param
(
$file
)
$algo = [System.Security.Cryptography.HashAlgorithm]::Create("MD5")
$stream = New-Object System.IO.FileStream($file, [System.IO.FileMode]::Open)
$md5StringBuilder = New-Object System.Text.StringBuilder
$algo.ComputeHash($stream) | `
% { [void] $md5StringBuilder.Append($_.ToString("x2")) }
$md5StringBuilder.ToString()
$stream.Dispose()
Este código me da una verificación de CRC en un archivo específico ... Simplemente no estoy seguro de cómo unir los dos scripts para realmente darme lo que necesito. Tampoco sé si la verificación CRC anterior es realmente la forma correcta de hacerlo.
¿Alguien tiene alguna idea?
Ambas son respuestas sólidas para powershell, pero probablemente sería mucho más fácil simplemente aprovechar Robocopy (aplicación de copia robusta suministrada por MS).
robocopy "C:/SourceDir/" "C:/DestDir/" /MIR
Lograría lo mismo.
Encontré una solución ... pero no estoy seguro de que sea la mejor desde una perspectiva de rendimiento:
$Source = "c:/scripts"
$Destination = "c:/test"
###################################################
###################################################
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
{
#Don''t want to copy this in my case..but good to know
#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
}
# 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(!(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(!(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(Compare-Object $srcMD5 $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(!(test-Path $SrcFile))
{
Write-Host "$SrcFile Missing... Copying from $DesFullname"
copy-Item -path $DesFullname -dest $SrcFile -force
}
}
Estas son algunas de las pautas sobre cómo puede mantener su script para que sea más fácil de mantener.
Convierte el script original como filtro.
filter HasChanged {
param($file)
# if $file''s MD5 has does not exist
# then return $_
}
Luego simplemente filtre todos los archivos que están actualizados y cópielos.
# Note that "Copy-Item" here does not preserve original directory structure
# Every updated file gets copied right under "C:/MyTest2"
ls C:/MyTest -Recurse | HasChanged | Copy-Item -Path {$_} C:/MyTest2
O puedes crear otra función que genere un subdirectorio.
ls C:/MyTest -Recurse | HasChanged | % { Copy-Item $_ GenerateSubDirectory(...) }