Перемещение файлов по различным критериям в Powershell 3.0

Я прочитал https://stackoverflow.com/questions/ask/advice? Переименовать элемент Powershell, если файл существует http://social.technet.microsoft.com/Forums/scriptcenter/en-US/c347ce7a-3e23-4476-90c2-37b79785ac2f/moving-files-based-on-modified-date Powershell: рекурсивное перемещение файлов http://blogs.technet.com/b/heyscriptingguy/archive/2009/09/22/hey-scripting-guy-september-22-2009.aspx и еще около двух десятков статей.

Прошу прощения, я плохо разбираюсь в сценариях, хотя мне нравится изучать его и возможности, которые он предоставляет. Мои предыдущие должности не требовали от меня написания сценариев, кроме пакетных файлов с использованием Windows CMD. Недавно я принял должность сетевого администратора, и мой руководитель попросил меня написать сценарий, который будет перемещать файлы на основе нескольких критериев. Для этого я использую Powershell.

  1. Файлы старше одного дня перемещаются - не копируются - из $ path в $ destination
  2. Исключение относится к callpilot.dev, который должен оставаться нетронутым.
  3. Файлы, находящиеся в исходной папке, а также файлы, находящиеся во всех подпапках, должны быть перемещены
  4. Структура исходной папки должна оставаться на месте
  5. Верхняя папка назначения должна содержать фактическую дату минус 1 день.
  6. Вся структура подпапок должна быть создана с использованием тех же имен, что и исходная структура.
  7. Остальные исходные файлы следует удалить (кроме callpilot.dev).

Вот моя структура тестовых папок:

    c:\temp\others\callpilot 
    c:\temp\others\ftps 
    c:\temp\others\mysql 
    c:\temp\others\rss-enterprise 
    c:\temp\others\rss-sql2k8 
    c:\temp\others\tree.txt 
    c:\temp\others\callpilot\example2.gz 
    c:\temp\others\callpilot\backup.gz 
    c:\temp\others\callpilot\barnak.bak 
    c:\temp\others\callpilot\callpilot.dev 
    c:\temp\others\callpilot\IPESystemBackup 131022 2000.bkp 
    c:\temp\others\ftps\www.123.com 
    c:\temp\others\ftps\www.123.com\backup-10.22.2013_00-00-08_123.tar.gz 
    c:\temp\others\ftps\www.123.com\backup-10.23.2013_00-00-08_123.tar.gz 
    c:\temp\others\ftps\www.123.com\backup-10.4.2013_00-00-07_123.tar.gz 
    c:\temp\others\mysql\sql.txt 
    c:\temp\others\rss-enterprise\enterprise.txt 
    c:\temp\others\rss-sql2k8\data 
    c:\temp\others\rss-sql2k8\data\New Bitmap Image.bmp 
    c:\temp\others\rss-sql2k8\data\New Journal Document.jnt 
    c:\temp\others\rss-sql2k8\data\New Microsoft PowerPoint Presentation.pptx 
    c:\temp\others\rss-sql2k8\data\New Microsoft Visio Drawing.vsd

Вот мой сценарий:

$date = get-date 
$path = "C:\temp\others\*.*"
$destination = new-item "c:\temp\others\$($date.toshortdatestring().replace("/","-"))" -type directory
Foreach($file in (Get-ChildItem $path -file -recurse -exclude "callpilot.dev")) 
{ 
    If($file.LastWriteTime -gt (Get-Date).adddays(-1).date) 
    { 
        Move-Item -Path $file.fullname -Destination $destination 
    } 
}

Мне не хватает №6 и №7. Не могли бы вы помочь мне их найти?


Я получил ваш ответ, спасибо за это. Что-то все еще не работает.

Вот мой сценарий:

$date = get-date
$path = "C:\temp\others\*.*"
$destination = new-item "c:\temp\others\$($date.toshortdatestring().replace("/","-"))" -type directory

Foreach($file in (Get-ChildItem $path -file -recurse -exclude "callpilot.dev"))
{
    If($file.LastWriteTime -gt (Get-Date).adddays(-2).date)
{
        $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root.ToString())
        New-Item $destination -Type Directory -ea SilentlyContinue
        Move-Item $file $destination
    } else {
        Remove-Item $file
}
}

Файлы перемещены, но папка не создана. И ошибка:

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Move-Item : Cannot create a file when that file already exists.
At C:\temp\organize_final222.ps1:11 char:9
+         Move-Item $file $destination
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (C:\temp\others\...sio Drawing.vsd:FileInfo) [Move-Item], IOException
+ FullyQualifiedErrorId : MoveFileInfoItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand

Method invocation failed because [System.IO.DirectoryInfo] doesn't contain a method named 'op_Addition'.
At C:\temp\organize_final222.ps1:9 char:9
+         $destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Я вставил ваши строки в нужное место?


person Geo    schedule 25.10.2013    source источник
comment
Похоже, что эта задача лучше подходит для Robocopy, чем для PowerShell, или, возможно, для их комбинации.   -  person alroc    schedule 25.10.2013
comment
Я тоже так думал вначале, но мне нужен реальный ход, который включает в себя изменение указателей папок, в отличие от того, что делает Robocopy: копирование, а затем удаление источника. Что он делает, чего не может Powershell? Кроме того, мне любопытно, как интегрировать Robocopy в сценарий Powershell. Спасибо!   -  person Geo    schedule 25.10.2013


Ответы (1)


Вы можете использовать $file.DirectoryName.TrimStart($file.Directory.Root.ToString()), чтобы получить путь к исходной папке без имени диска, так что это позаботится о # 6:

$destination += '\' + $file.DirectoryName.TrimStart($file.Directory.Root.ToString())
New-Item $destination -Type Directory -ea SilentlyContinue
Move-Item $file $destination

Несколько примечаний:

  • Первая строка добавляет исходный путь (без буквы диска) к $ destination.
  • Вторая строка создает целевой каталог, если он не существует. -ea SilentlyContinue не дает ему жаловаться, если целевой каталог уже существует. Вы могли бы быть аналом и делать if (! (Test-Path $destination)) {New-Item ..., но я думаю, что это пустая трата времени.
  • Вы можете не указывать имена параметров -Path и -Destination, потому что они подразумеваются позицией (Google "позиционные параметры PowerShell" для получения дополнительной информации).
  • Вам не нужно читать свойство FullName. Если вы предоставляете строковый аргумент для строкового параметра, PowerShell автоматически вызывает метод ToString () для этого аргумента. Итак, Move-Item $file $dest совпадает с Move-Item $file.ToString() $dest, а вызов метода ToString () для объекта FileInfo дает вам свойство FullName (это указано в определении класса объекта). Это может показаться второстепенным вопросом, но вы обнаружите, что печатаете гораздо меньше ненужного, как только привыкнете к этому. Общее правило состоит в том, что если интуитивно кажется, что он должен работать, он, вероятно, будет работать (например, интуитивно понятно, что вы должны иметь возможность просто сказать ему переместить файловый объект, не выполняя никаких причудливых вещей, таких как указание свойства объекта - - так что вы можете.)

Для №7 просто добавьте предложение else, чтобы удалить исходные файлы, не соответствующие условию:

if ($file.LastWriteTime -gt (Get-Date).AddDays(-1).Date) {
  Move-Item $file "$destination\$($file.DirectoryName.TrimStart($file.Directory.Root.ToString()))"
} else {
  Remove-Item $file
}

На всякий случай я бы порекомендовал выполнить тестовый запуск с Remove-Item -WhatIf $file, чтобы убедиться, что вы получаете желаемые результаты. Еще лучше было бы объявить [CmdletBinding(SupportsShouldProcess=$true)] в начале сценария и запустить весь сценарий с помощью -WhatIf, но это, вероятно, более продвинуто, чем вы хотите получить прямо сейчас. Важная часть - всегда выполнять неразрушающий тестовый прогон, прежде чем позволить скрипту внести большое количество необратимых изменений.

person Adi Inbar    schedule 25.10.2013