Como preservar timestamps para todas as pastas ao movê-los de uma unidade NTFS para outra?

2

Eu quero mover uma pasta (contendo várias subpastas e arquivos) de uma unidade NTFS para outra.

Observação: notei que, ao fazer isso, os carimbos de data e hora ("data de criação", "data da última modificação" etc.) não são preservados em pastas contendo pelo menos uma pasta / arquivo. Mesmo as pastas vazias que são movidas acabarão por alterar "automaticamente" a data de criação para ficarem compatíveis com o restante (assim que você colocar algo nessa pasta vazia na nova unidade).

Meu esforço: Já experimentei quase tudo que encontrei via Google sobre esse assunto (Robocopy, Richcopy, Microsoft SyncToy, Total Commander, Free Commander ... e muitos, muitos mais ... .) - todos produzem relativamente os mesmos resultados. Nada produziu uma preservação abrangente de 100% da fonte que está sendo movida. Robocopy e Richcopy (junto com os "Comandantes") chegam perto, mas eu ainda tenho problemas (em todos os casos) onde a data de criação é incorretamente "preservada", a última data modificada não pode ser preservada, etc. Eu vi além disso ... é o Powershell.

Minha jornada no PowerShell

Eu tropecei neste link:

link

... com este script:

function Move-FileWithTimestamp {
[cmdletbinding()]
param(
[Parameter(Mandatory=$true,Position=0)][string]$Path,
[Parameter(Mandatory=$true,Position=1)][string]$Destination
)

$origLastAccessTime = ( Get-Item $Path ).LastAccessTime
$fileName = ( Get-Item $Path ).Name
Move-Item -Path $Path -Destination $Destination
$(Get-Item ($Destination+'\'+$fileName)).LastAccessTime = 
$origLastAccessTime
}

O script no tópico acima ainda não apresentou um desempenho diferente dos programas que listei, mas pelo menos aqui, eu tinha uma plataforma onde eu poderia alterar / personalizar / ajustar algumas coisas para as minhas necessidades exatas. Então eu fiz o que pude com meu conhecimento limitado neste reino (isto é, alterando ".LastAccessTime" com ".CreationTime", trocando ".LastAccessTime" por "LastWriteTime", etc), e eventualmente fiquei relativamente perto de preservar todos os timestamps ( Acredito que, em determinado momento, eu havia preservado a última modificação, acessado pela última vez e salvo pela última vez na minha pasta de teste). No entanto, eu ainda não consigo preservar a data de criação corretamente, e o que eu era capaz de realizar com todo o resto obviamente se aplicava apenas à pasta de teste solitário (e nada mais, como as subpastas dentro dela ... mas isso é só porque eu não sei como roteirizar essas coisas além de um diretório principal).

Eu estou em cima da minha cabeça quando se trata dessas coisas, então estou me perguntando se alguém lá fora quer resolver isso.

ATUALIZAÇÃO: aqui é onde eu estou agora:

function Move-FileWithTimestamp {
[cmdletbinding()]
param(
[Parameter(Mandatory=$true,Position=0)][string]$Path,
[Parameter(Mandatory=$true,Position=1)][string]$Destination
)
$origCreationTime = ( Get-Item $Path ).CreationTime
$origLastWriteTime = ( Get-Item $Path ).LastWriteTime
$origLastAccessTime = ( Get-Item $Path ).CreationTime

$fileName = ( Get-Item $Path ).Name
Move-Item -Path $Path -Destination $Destination
$(Get-Item ($Destination+'\'+$fileName)).CreationTime = $origCreationTime
$(Get-Item ($Destination+'\'+$fileName)).LastWriteTime = 
$origLastWriteTime
$(Get-Item ($Destination+'\'+$fileName)).LastAccessTime = 
$origLastAccessTime
}

Isto parece manter o tempo de criação original para a pasta principal sendo movida (assim como o último tempo de modificação / gravação), mas obviamente o último tempo acessado muda para a hora de criação original no processo (parece que uma pasta é movida para uma nova unidade, o Windows, por padrão, altera a última hora acessada durante esse processo, e TAMBÉM se refere a essa nova hora acessada para criar a nova hora de criação da pasta em sua nova localização (NÃO Se você tentar definir o novo horário de criação para igualar o tempo de criação original, nada resultará, porque o novo horário do último acesso, por padrão, mudará automaticamente o novo horário de criação para igualá-lo. Então, se você forçar o Windows a fazer com que o novo horário do último acesso seja igual ao tempo de criação original, você acabará tendo o tempo de criação correto, mas o último acesso incorreto.

Então, agora estou preso a um último horário incorreto acessado, mas os horários corretos para todo o resto. Além disso, não tenho ideia de como vou fazer com que isso se aplique a todas as subpastas também, então deixe-me saber se alguém sabe como fazer isso.

ATUALIZAÇÃO:

function Move-FileWithTimestamp {
[cmdletbinding()]
param(
[Parameter(Mandatory=$true,Position=0)][string]$Path,
[Parameter(Mandatory=$true,Position=1)][string]$Destination
)
$origCreationTime = ( Get-Item $Path ).CreationTime
$origLastWriteTime = ( Get-Item $Path ).LastWriteTime
$origLastAccessTime = ( Get-Item $Path ).CreationTime
$origChildCreationTime = ( Get-ChildItem $Path ).CreationTime
$origChildLastWriteTime = ( Get-ChildItem $Path ).LastWriteTime
$origChildLastAccessTime = ( Get-ChildItem $Path ).CreationTime


$fileName = ( Get-Item $Path ).Name
Move-Item -Path $Path -Destination $Destination
$(Get-Item ($Destination+'\'+$fileName)).CreationTime = $origCreationTime
$(Get-Item ($Destination+'\'+$fileName)).LastWriteTime = $origLastWriteTime
$(Get-Item ($Destination+'\'+$fileName)).LastAccessTime = 
$origLastAccessTime
$(Get-ChildItem ($Destination+'\'+$fileName)) | ForEach-Object { 
$_.CreationTime = $origChildCreationTime }
$(Get-ChildItem ($Destination+'\'+$fileName)) | ForEach-Object { 
$_.LastWriteTime = $origChildLastWriteTime }
$(Get-ChildItem ($Destination+'\'+$fileName)) | ForEach-Object { 
$_.LastAccessTime = $origChildLastAccessTime }
}

Agora, tenho uma pasta principal e uma se são subpastas com a criação correta e as datas da última modificação (mas não acessadas pela última vez). Não tenho ideia de como fazer isso para o restante das subpastas na pasta principal e também para qualquer subpasta dessas subpastas.

    
por Devon Heath 12.10.2018 / 04:11

1 resposta

1

Mova a árvore de diretórios e mantenha todos os valores de atributo de registro de data e hora

Assim, seu objetivo é garantir que os arquivos e pastas movidos de um local de origem para um local de destino tenham seus valores de atributo LastWriteTime , LastAccessTime e CreationTime retidos no local de origem de origem.

Essentially this. . .

  • Uses Copy-Item rather than Move-Item
  • Loops through source and sets timestamp attribute variables values to then use Set-ItemProperty to set those same values to those properties in the destination for all folders and files recursively
  • Explicitly does the same Set-ItemProperty timestamp attribute value set loop for folder objects only
  • Uses Remove-Item to then delete the original source file objects only cleaning those up
  • Uses Remove-Item to then delete the original source folder object only cleaning those up

Script

$src = "C:\Src\Folder3\"
$dest = "X:\Dest\Folder1\"
$src = $src.Replace("\","\")

$i = Get-ChildItem -Path $src -Recurse
$i | % {     ## -- All files and folders

    $apath = $_.FullName -Replace $src,""
    $cpath = $dest + $apath

    Copy-Item -Path $_.FullName -Destination $cpath -Force

    If (Test-Path $cpath)
       {
           Set-ItemProperty -Path $cpath -Name CreationTime -Value $_.CreationTime
           Set-ItemProperty -Path $cpath -Name LastWriteTime -Value $_.LastWriteTime
           Set-ItemProperty -Path $cpath -Name LastAccessTime -Value $_.LastAccessTime
       }
    }

$d = Get-ChildItem -Path $src -Recurse -Directory
$d | % {     ## -- Folders only

    $apath = $_.FullName -Replace $src,""
    $cpath = $dest + $apath

    If (Test-Path $cpath)
       {
           Set-ItemProperty -Path $cpath -Name CreationTime -Value $_.CreationTime
           Set-ItemProperty -Path $cpath -Name LastWriteTime -Value $_.LastWriteTime
           Set-ItemProperty -Path $cpath -Name LastAccessTime -Value $_.LastAccessTime
       }
    }


$f = Get-ChildItem -Path $src -Recurse -File
$f | % {     ## -- Delete files only

    $apath = $_.FullName -Replace $src,"" 
    $cpath = $dest + $apath

    If (Test-Path $cpath)
       {
            Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
       }
    }


$d | % {     ## -- Delete directories only

    $apath = $_ -Replace $src,"" 
    $cpath = $dest + $apath

    If (Test-Path $cpath)
       {
            Remove-Item $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
       }
    }

Mais recursos

por 12.10.2018 / 09:28