Simpan semua stempel waktu saat memindahkan data dari satu drive NTFS ke drive lain

4

Saya ingin memindahkan folder — yang berisi banyak sub-folder dan file — dari satu drive NTFS ke drive lain, tetapi saya memerlukan metadata date dan nilai atribut cap waktu yang disimpan dari sumber asli pada drive tujuan yang baru.

Masalahnya: Saya perhatikan ketika saya menyelesaikan berbagai operasi penyalinan untuk tugas, nilai timestamp untuk "tanggal pembuatan", "tanggal modifikasi terakhir", dll. Tidak disimpan pada folder yang berisi setidaknya satu folder / file. Saya juga memperhatikan bahwa folder kosong yang dipindahkan pada akhirnya akan dan secara otomatis mengubah tanggal pembuatannya agar sesuai dengan yang lainnya serta ketika menempatkan sesuatu di folder kosong pada drive baru.

masukkan deskripsi gambar di sini

Usaha Saya: Saya sudah mencoba hampir semua yang saya dapat temukan melalui Google pada subjek ini (Robocopy, Richcopy, Microsoft SyncToy, Total Commander, Free Commander ... dan banyak, banyak lagi ...) - yang semuanya menghasilkan relatif sama hasil. Tidak ada yang menghasilkan pelestarian komprehensif, 100% dari sumber yang dipindahkan. Robocopy dan Richcopy (bersama dengan "Komandan") datang dekat, tapi saya masih mengalami masalah (dalam semua kasus) di mana tanggal pembuatan salah "diawetkan", tanggal modifikasi terakhir tidak dapat dipertahankan sama sekali, dll. Satu-satunya janji yang benar Saya telah melihat lebih dari itu ... adalah Powershell.


Perjalanan PowerShell saya

Saya menemukan tautan ini:

https://stackoverflow.com/questions/34951911/powershell-move-item-folder-time-stamp

... dengan skrip ini:

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
}

Skrip di utas di atas masih tidak melakukan yang berbeda dari program yang saya daftarkan, tetapi setidaknya di sini, saya memiliki platform di mana saya dapat mengubah / menyesuaikan / men-tweak beberapa hal untuk kebutuhan saya yang sebenarnya. Jadi saya melakukan apa yang saya bisa dengan pengetahuan saya yang terbatas di bidang ini (yaitu mengubah ".LastAccessTime" dengan ".CreationTime", bertukar ".LastAccessTime" dengan "LastWriteTime", dll.), Dan akhirnya relatif dekat untuk mempertahankan semua stempel waktu ( Saya percaya pada satu titik, saya telah menyimpan yang terakhir diubah, terakhir diakses, dan terakhir disimpan pada folder pengujian saya). Namun, saya masih tidak dapat mempertahankan tanggal pembuatan dengan benar, dan apa yang dapat saya capai dengan yang lainnya jelas hanya diterapkan pada folder uji tunggal (dan tidak ada yang lain, seperti sub-folder di dalamnya ... tapi ini adalah hanya karena saya tidak

Saya berada di atas kepala saya ketika datang ke hal-hal ini, jadi saya bertanya-tanya apakah ada orang di luar sana yang ingin mengatasi ini.

UPDATE: Di sinilah saya sekarang:

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
}

Ini tampaknya mempertahankan waktu pembuatan asli untuk folder utama yang sedang dipindahkan (serta waktu modifikasi / penulisan terakhir), tetapi jelas waktu yang diakses terakhir berubah ke waktu pembuatan asli dalam proses (sepertinya seolah-olah ketika sebuah folder adalah dipindahkan ke drive baru, Windows, secara default, mengubah waktu diakses terakhir selama proses itu, dan JUGA mengacu pada waktu diakses terakhir baru untuk membuat waktu pembuatan baru folder di lokasi baru (itu TIDAK merujuk pada waktu pembuatan asli apa pun secara wajar). IE jika Anda mencoba dan mengatur waktu pembuatan baru untuk menyamai waktu pembuatan asli, tidak ada yang akan menghasilkan, karena waktu akses terakhir yang baru secara otomatis akan mengubah waktu pembuatan baru untuk menyamakannya. Jadi, jika Anda memaksa Windows untuk membuat waktu akses terakhir yang baru sama dengan waktu pembuatan asli,maka Anda akhirnya berakhir dengan waktu pembuatan yang benar, tetapi waktu akses terakhir yang salah.

Jadi, sekarang saya terjebak dengan waktu akses terakhir yang salah, tetapi memperbaiki waktu untuk yang lainnya. Juga, saya tidak tahu bagaimana saya akan mendapatkan ini untuk diterapkan ke semua subfolder juga, jadi beri tahu saya jika ada yang tahu cara melakukannya.

MEMPERBARUI:

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 }
}

Sekarang, saya memiliki folder utama dan satu jika itu sub-folder dengan pembuatan yang benar dan tanggal modifikasi terakhir (tetapi tidak diakses terakhir). Saya tidak tahu bagaimana menyelesaikan ini untuk sisa sub-folder di folder utama, dan juga untuk setiap sub-folder di dalam sub-folder tersebut.

Devon Heath
sumber
Apakah Anda mengatakan bahwa saya Robocopy /copyalltidak bekerja?
Appleoddity
Disalin ke komentar untuk OP: Untuk menjawab pertanyaan Anda, tidak, robocopy tidak menyimpan 3 cap waktu utama untuk saya di folder (dibuat, diubah terakhir, dan diakses terakhir). Saya sudah mencoba semua sakelar. Saya pasti berpikir ada cara untuk mencapai ini dengan Powershell namun ... Saya terlalu tidak terbiasa dengan pengkodean dan scripting ... itulah sebabnya saya berharap seseorang di luar sana dapat melihat dan menjadi seperti, "oh, itu sederhana ".
fixer1234

Jawaban:

2

Pindahkan susunan direktori dan simpan semua nilai atribut cap waktu

Jadi tujuan Anda adalah untuk memastikan bahwa file dan folder yang dipindahkan dari lokasi sumber ke lokasi tujuan memiliki mereka LastWriteTime, LastAccessTimedan CreationTimenilai atribut dipertahankan dari lokasi sumber mana mereka berasal.

Intinya ini. . .

  • Menggunakan Item-Salin daripadaMove-Item
  • Loop melalui sumber dan set nilai variabel atribut timestamp untuk kemudian gunakan Set-ItemProperty untuk mengatur nilai-nilai yang sama ke properti di tujuan untuk semua folder dan file secara rekursif
  • Secara eksplisit melakukan nilai atribut timestamp Set-ItemProperty yang sama mengatur loop untuk objek folder saja
  • Menggunakan Remove-Item untuk kemudian menghapus objek file sumber asli hanya membersihkannya
  • Menggunakan Remove-Item untuk kemudian menghapus objek folder sumber asli hanya membersihkannya

Naskah

$src = "C:\Src\Folder\123\"
$dest = "X:\Dest\Folder\321\"
$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
       }
    }

Sumber Daya Lebih Lanjut

Pimp Juice
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
DavidPostill
@DavidPostill Bisakah Anda memberi saya tautan untuk membaca bagaimana saya bisa melakukan ini? Saya selalu mendapatkan komentar panjang dan tidak pernah mendapatkan tautan untuk membuat obrolan yang sangat ingin tahu jika ada cara lain dengan beberapa bacaan saya bisa belajar bagaimana cara memindahkan ini ke obrolan sendiri sehingga mods tidak ditandai dan sebagainya.
Pimp Juice,
1
AFAIK hanya mod yang dapat melakukan ini.
DavidPostill
0

Dengan NTFS, Anda hanya dapat memindahkan file dan folder pada satu disk. Memindahkan direktori pada disk tunggal adalah operasi pada pointer file dan bukan lokasi data pada disk.

Pindahkan NTFS (disk tunggal)

Anda cukup memanggil fungsi .NET Move dari Powershell.
1. Buat file move.ps1

2. Salin berikut ini dan ubah jalur yang diperlukan.

$Source = "C:\test"
$Destination = "C:\test1"
[System.IO.Directory]::Move($Source, $Destination)
  1. Klik kanan pada file dan pilih Run in Powershell.

Jika Anda "pindah" dari satu disk ke disk lain, Anda perlu melakukan salinan NTFS dan kemudian menghapus sumbernya. Perilaku default NTFS adalah memperbarui tanggal folder karena secara teknis, mereka adalah folder yang baru dibuat (pointer NTFS) pada disk baru. Untuk mengesampingkan perilaku ini, Anda harus mengatur tanggal pada salinan baru file dan folder seperti yang diposting oleh orang lain. Inilah cara lain untuk melakukan hal yang sama. Di sini saya memanggil kode C # dari Powershell.

NTFS "move" (multiple disks) - Salin sumber secara rekursif ke tujuan, salin atribut, lalu hapus sumber.

$source = @"
using System;
using System.IO;

public class DirectoryCopyExample
{
    public static void DirectoryCopy(string sourceDirName, string destDirName)
    {
        // Get the subdirectories for the specified directory.
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);

        if (!dir.Exists)
        {
            throw new DirectoryNotFoundException(
                "Source directory does not exist or could not be found: "
                + sourceDirName);
        }

        // Since we are deleting the files in the source directory, we need to save the dates before they are modified
        DateTime dirCreationTime = Directory.GetCreationTime(sourceDirName);
        DateTime dirLastAccessTime = Directory.GetLastAccessTime(sourceDirName);
        DateTime dirLastWriteTime = Directory.GetLastWriteTime(sourceDirName);

        DirectoryInfo[] dirs = dir.GetDirectories();
        // If the destination directory doesn't exist, create it.
        if (!Directory.Exists(destDirName))
        {
            Directory.CreateDirectory(destDirName);        
        }

        // Get the files in the directory and copy them to the new location.
        FileInfo[] files = dir.GetFiles();
        foreach (FileInfo file in files)
        {
            string temppath = Path.Combine(destDirName, file.Name);

            file.CopyTo(temppath, false);

            File.SetCreationTime(temppath, File.GetCreationTime(file.FullName));
            File.SetLastAccessTime(temppath, File.GetLastAccessTime(file.FullName));
            File.SetLastWriteTime(temppath, File.GetLastWriteTime(file.FullName));

            File.Delete(file.FullName);
        }

        // Recursively copy all sub directories
        foreach (DirectoryInfo subdir in dirs)
        {
            string temppath = Path.Combine(destDirName, subdir.Name);
            DirectoryCopy(subdir.FullName, temppath);
        }

        Directory.SetCreationTime(destDirName, dirCreationTime);
        Directory.SetLastAccessTime(destDirName, dirLastAccessTime);
        Directory.SetLastWriteTime(destDirName, dirLastWriteTime);

        Directory.Delete(sourceDirName);

    }
}
"@

Add-Type -TypeDefinition $source

[DirectoryCopyExample]::DirectoryCopy("C:\test", "D:\test")

Kode yang dipinjam dari sini:

https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories

dan di sini

https://stackoverflow.com/questions/2143460/how-to-convert-c-sharp-code-to-a-powershell-script

Penafian: Ini telah diuji secara minimal. Gunakan dengan risiko Anda sendiri.

William S.
sumber
Apa ini? Bagaimana cara menggunakannya?
Scott
Jawaban yang Diedit. Semoga ini membantu.
William S.