PowerShell: загрузка списка файлов из общих ресурсов SMB без перезаписи

Я хочу загрузить список предопределенных файлов из удаленных сетевых ресурсов, не перезаписывая локальные файлы с тем же именем. У меня эта функция в основном работает в PowerShell с использованием модуля Bitstransfer. Вы можете видеть в коде, что C: \ SMB \ paths.txt указывает на локальный файл, который включает удаленные пути SMB.

SMBBulkDownload.ps1:

Import-Module bitstransfer

foreach($line in Get-Content C:\SMBDump\paths.txt) {
    $sourcePath = $line
    $destPath = "C:\SMBDump\"
    Start-BitsTransfer -Source $sourcePath -Destination $destPath     
}

где C: \ SMB \ paths.txt содержит (образец фрагмента):

\\10.17.202.21\some\dir\app.config
\\10.19.197.68\some\dir\app.config
\\10.28.100.34\some\dir\Web.config

Приведенный выше код загружает файлы правильно, если у них разные имена файлов. В случае, когда имена файлов совпадают, передача битов возвращает ошибку ACCESSDENIED. Это могло произойти из-за того, что модуль не поддерживает копии файлов с одинаковыми именами, или из-за условий гонки при копировании файлов с одинаковыми именами в одно и то же время. Это прискорбно, потому что моя работа требует массовой загрузки множества разных файлов с одинаковыми именами, таких как App.Config, Web.Config и т. Д.

Ошибка:

Start-BitsTransfer : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

Есть ли у кого-нибудь решение, которое может обойти этот одноименный блок копирования файлов? В идеале мне нужно решение, которое копирует файлы с повторяющимися именами в тот же каталог с суффиксом «_1», «_2» или _.


person Karimi    schedule 27.10.2017    source источник


Ответы (2)


Предполагая, что ваши ошибки коренятся в вашей теории имен файлов, это было бы чем-то, что нужно попробовать ...

Все ваши пути имеют один уникальный компонент: IP-адрес или имя сервера. Я бы посоветовал создать подкаталог для каждого адреса или добавить его к имени.

Файлы, организованные в папки по хосту

foreach($line in Get-Content C:\SMBDump\paths.txt) {
    $hostName = ([uri]$line).Host
    $fileName = Split-Path $line -Leaf
    $destPath = "C:\SMBDump\$hostName\$fileName"
    Start-BitsTransfer -Source $sourcePath -Destination $destPath     
}

or

Файлы в той же папке с префиксом имени хоста

foreach($line in Get-Content C:\SMBDump\paths.txt) {
    $hostName = ([uri]$line).Host
    $fileName = Split-Path $line -Leaf
    $destPath = "C:\SMBDump\$hostName-$fileName"
    Start-BitsTransfer -Source $sourcePath -Destination $destPath     
}

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

person Matt    schedule 27.10.2017
comment
это должно быть $destPath = "C:\SMBDump\$hostname\$fileName"? (Обратная косая черта между хостом и именем файла) - person Jonathon Anderson; 27.10.2017
comment
@NonSecwitter Нет. Второй пример - все файлы находятся в одном каталоге. например 10.17.202.21app.config. Хотя небольшой разрыв в имени между ними не повредит читабельности. - person Matt; 27.10.2017
comment
Попался. Тогда просто разница в стилях. Я бы также добавил дату, если она повторяется: $destPath = "C:\SMBDump\$hostname\$date\$fileName", где $date - это некоторая отформатированная строка, например YYYYMMDD - person Jonathon Anderson; 27.10.2017
comment
Это было бы хорошей идеей в зависимости от варианта использования, здесь да. Я уверен, что оператор поймет из этого суть. - person Matt; 27.10.2017
comment
Только что протестировал этот @matt. Второе решение работает как шарм! Первое решение берет имя файла (например, Web.config) и переименовывает его в имя хоста (например, 10.30.20.1), перезаписывая его всякий раз, когда обнаруживаются новые файлы Web.config, а не создает уникальные каталоги. Тем не менее, ваше второе решение - это то, что я искал. Спасибо! - person Karimi; 27.10.2017
comment
Ах. Я думал, что если я дам ему папку, остальное он возьмет на себя. похоже, что это не так. @Karimi Я исправил. - person Matt; 27.10.2017

Подход Мэтта - это способ сохранить уникальные пути к файлам и позволить вам отслеживать файлы до их исходного сервера.

Чтобы буквально ответить на вопрос, вам нужно будет проверить, существует ли файл, который вы хотите скопировать, и изменить свой путь, чтобы избежать конфликта.

Import-Module bitstransfer

foreach($line in Get-Content C:\SMBDump\paths.txt) {
    $sourcePath = $line
    $destPath = "C:\SMBDump\"      
    $fileName = Split-Path -Path $line -leaf

    if(Test-Path "$destPath$fileName"){
        $extension = [io.path]::GetExtension($fileName)
        $basename  = [io.path]::GetFileNameWithoutExtension($fileName)
        $i = 1

        do{
            $fileName  = "${basename}_$i$extension"
            if(-not (Test-Path "$destPath$fileName")){
                $next = $false
            }else{
                $next = $true
                $i++
            }

        }while($next -eq $true)

    }

    Start-BitsTransfer -Source $sourcePath -Destination "$destPath$fileName"    
}
person G42    schedule 27.10.2017
comment
[io.path]::GetExtension() и [io.path]::GetFileNameWithoutExtension() сотворили бы здесь чудеса. Также в этом случае нет необходимости, чтобы фигурные скобки с двумя переменными располагались рядом в строке. $this="this";$that="that";"$this$that". Ваша замена потенциально опасна, если расширение также присутствует в имени файла. - person Matt; 27.10.2017