Powershell Получить родительскую папку файла

Я пишу script, который архивирует файлы для анализа. Моя проблема в том, что имена файлов не уникальны по нескольким папкам, поэтому они переписываются.

Например:

C:\StuffToCopy\Folder1\myFile1.txt
C:\StuffToCopy\Folder1\myFile2.txt
C:\StuffToCopy\Folder2\myFile1.txt
C:\StuffToCopy\Folder2\myFile2.txt

В конце моего процесса копирования я получаю только 2 файла, но хочу 4.

Я хочу, чтобы результат был таким:

C:\ArchiveCopy\Folder1_myFile1.txt
C:\ArchiveCopy\Folder1_myFile2.txt
C:\ArchiveCopy\Folder2_myFile1.txt
C:\ArchiveCopy\Folder2_myFile2.txt

Здесь мой script.

$files = dir -r -path "C:\StuffToCopy\" -i *.*

foreach ($file in $files)
{
    if ($file.LastWriteTime -gt (get-date).AddDays(-1)) {
        copy -path $file C:\ArchiveCopy\
    }
}

Я хочу сделать что-то вроде copy -path $file.FolderName & '_' & $file C:\ArchiveCopy\

Я просто не уверен, как это сделать.

Ответ 1

Если $file - это действительно файл - экземпляр System.IO.FileInfo (и не действительно каталог: System.IO.DirectoryInfo), то он имеет свойство Directory, которое является экземпляром DirectoryInfo, который имеет Name

$file |
  copy-item -destination { 
     Join-Path C:\ArchiveCopy\ -childpath ($_.Directory.Name + "_" + $_.Name) }

(Использование конвейера для запуска, поскольку параметр -LiteralPath Copy-Item будет привязан к свойству PSPath из конвейера, поэтому нет необходимости вытаскивать исходное имя файла из объекта $file.)

Если $file может быть каталогом, то вам нужно выполнить большую часть работы самостоятельно, но, вероятно, проще сначала отфильтровать каталоги:

dir -r -path C:\StuffToCopy\ |
  where { -not $_.PSIsContainer } |
  copy-item -destination { 
     Join-Path C:\ArchiveCopy\ -childpath ($_.Directory.Name + "_" + $_.Name) }

Примечание:

  • Не нужно сохранять все объекты файла, а затем перебирать их: пусть конвейер выполняет цикл
  • Не нужно -i "*.*": это по-прежнему по умолчанию (и если вам нужно фильтровать файлы по шаблону подстановки, выберите параметр -filter pattern: фильтр передается в файловую систему, а не создает объекты .NET, а затем фильтрует они намного медленнее, если файлов много).

Ответ 2

Попробуйте следующее:

dir -r -path C:\StuffToCopy | 
        where {!$_.psiscontainer} | 
        copy -dest { "C:\ArchiveCopy\$($_.Directory.Name)_$($_.Name)"}

Ответ 3

Основываясь на вашем script, вот еще один способ сделать это:

$files = dir -r -path "C:\StuffToCopy\" -i *.*
$destPath = "c:\ArchiveCopy\"

foreach ($file in $files)
{

   $folderPath =  Split-Path $file.fullname -parent
   $folder = Split-Path $folderPath -leaf
   $destFilename = $folder + "_" + $file.name
   $destFileFullPath = $destPath + $destFilename
   write-host $destFileFullPath
    if ($file.LastWriteTime -eq (get-date).AddDays(0)) {
        copy -path $file $destFileFullPath
    }
}