PowerShell: копирование / перемещение файлов на основе значения регулярного выражения, сохранение структуры папок и т. Д. - PullRequest
6 голосов
/ 25 октября 2011

Вот сценарий: у нас есть рабочий веб-сервер с несколькими тысячами файлов и папок, к которым прикреплена «_DATE». Мы хотим переместить их во временную папку (убедитесь, что они не используются), а затем удалите файлы.

Я могу использовать:

Get-ChildItem -Path W:\IIS -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"}

Чтобы получить список всех файлов / папок и их расположения. Но удаление их всех вручную кажется большой работой, особенно если это потребуется в будущем. Я нашел несколько примеров, которые почти делают то, что я хочу:

cls

$source = "W:\IIS"
$destination = "C:\Temp\DevTest" 

foreach ($i in Get-ChildItem -Path $source -Recurse)
{
    if ($i.Name -match "_\d{8,10}$")
    {
        Copy-Item -Path $i.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Trim($item.Name)
    }
}

И

cls

$source = "W:\IIS"
$destination = "C:\Temp\DevTest" 

$bin = Get-ChildItem -Path $source -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"}

foreach ($item in $bin) {
    Copy-Item -Path $item.FullName -Container -Destination $item.FullName.ToString().Replace($source,$destination).Trim($item.Name) -Recurse
}

Проблема с этими двумя заключается в том, что когда я тестирую их с помощью просто copy-item, я получаю плоский каталог, и мне нужно сохранить структуру каталогов, чтобы в случае неправильного перемещения я мог вернуться (предпочтительно перетаскиванием и сбросив все папки обратно в папку IIS), или я получаю копию множества дополнительных папок / файлов, которые не отображаются при запуске первой команды.

Изменение моей первой команды на:

Get-ChildItem -Path W:\IIS -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"} | Copy-Item -Container -Destination C:\Temp\DevTest -Recurse

Скопирует все, что мне нужно, но с плоским деревом каталогов, вместо сохранения древовидной структуры (но с заменой исходного каталога на место назначения).

Есть предложения / комментарии?

Ответы [ 3 ]

2 голосов
/ 26 октября 2011

Первый должен в идеале работать.Это сохраняет структуру каталогов.Но вы должны быть осторожны при копировании папок.Предполагая, что вам нужны только файлы в шаблоне, в котором вы хотите, и вам нет дела до того, какие там папки, вы можете сделать следующее:

$source = "W:\IIS"
$destination = "C:\Temp\DevTest" 

if(-not (Test-Path $destination)) { mkdir $destination | out-null}

foreach ($i in Get-ChildItem -Path $source -Recurse)
{
    if (($i.Name -notmatch "_\d{8,10}$") -and (-not $i.PsIsContainer))
    {
        continue;
    }
    Copy-Item -Path $i.FullName -Destination $i.FullName.Replace($source,$destination).Trim($i.Name)
}
1 голос
/ 26 октября 2011

Вы можете поиграть со следующим, что, кажется, выполнит работу (хотя он может использовать некоторый рефакторинг).Ядро ProcessFolder(…), которое вызывается рекурсивно.

function Log
{
    param($Error)
    if(!$script:log)
    {
        $script:log = join-path $dst "log$timestamp.txt"
    }
    $timestamp
    $timestamp >> $script:log
    $Error
    $Error >> $script:log
}

function CopyFile
{
    param($Path)
    $tmp = join-path $dst $Path.Substring($src.Length)
    write-host "File src: $Path"
    write-host "File dst: $tmp"
    Try
    {
        #copy the file
        copy $Path $tmp -Force
    }
    Catch
    {
        Log "ERROR copying file $Path to $tmp`:`
        $_"
    }
}

function ProcessFolder
{
    param($Path)
    $tmp = join-path $dst $Path.Substring($src.Length)
    write-host "Dir. src: $Path"
    write-host "Dir. dst: $tmp"
    Try
    {
        #create target directory
        New-Item $tmp -itemtype directory -force > $null
        #process files if they match
        dir $Path | ?{!$_.PsIsContainer -and $_.Name -match "_\d{8,10}$" } | sort | %{ CopyFile $_.FullName }
        #process subdirectories
        dir $Path | ?{$_.PsIsContainer} | sort | %{ ProcessFolder $_.FullName }
        #remove target directory if it contains no files on any level
        if( !(dir $tmp -recurse | ?{!$_.PsIsContainer}) ) { del $tmp -recurse }
    }
    Catch
    {
        Log "ERROR copying folder $Path to $tmp`:`
        $_"
    }
}

cls

$src = "W:\IIS\"
$dst = "C:\Temp\DevTest\"
$log = $null
$timestamp = '{0:yyyyMMddHHmmssfffffff}' -f (Get-Date)
ProcessFolder $src

''
'DONE!'
if( $log )
{
    echo "Check the log file: $log"
}
Read-Host
1 голос
/ 26 октября 2011

Для меня Copy-Item беспорядок, вы можете прочитать другие ответы StackOverflow этот или этот другой . Вот решение, которое является своего рода «бриколажем».

$source = "W:\\IIS" # Really double \

Get-ChildItem -Path $source -Recurse | Where-Object{($_.Name -match ""_\d{8,10}$") -or ($_.psiscontainer)} | % {copy-item  $_.fullname ($_.fullname -replace $source,'C:\Temp\DevTest') }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...