Показать полную графическую версию : [решено] Копирование из сети в локальную папку с сохранением структуры каталогов
epoddubniy
08-02-2022, 16:51
Здравствуйте.
Помогите пожалуйста доработать скрипт (или создать новый)
# переменные
$Data=Get-Date -Format "dd.MM.yyyy"
$CurrentDay=get-date -format "%d"
$newfoldername = [string]$Data +"_"+ "User"
$Source="\\USER-PC\c$\users\User\Desktop"
$Dest="H:\USERPROFILE-BACKUP\Increment\$newfoldername"
$MakeDir=New-Item -Path $Dest -ItemType Directory -force
$getFiles=Get-ChildItem $Source -Recurse | where-object {$_.lastwritetime -lt (get-date).date.adddays(1) -and $_.lastwritetime -ge (get-date).date.adddays(-1)}
#непосредственно скрипт
# копирование с сохранением структуры
$MakeDir
$getFiles | ForEach-Object -Process {Copy-Item -Path $_.FullName -Destination $Dest}
Получилось, чтобы powershell рекурсивно отобрал файлы и скопировал в каталог назначения, а как сделать, чтобы "в соответствующий каталог" копировал - не смог придумать
Copy-Item сам по себе рекурсивно копирует с учётом -exclude или -include. Copy-Item -Path $Source\* -Destination $Dest -Recurse -Include $getFiles
Copy-Item сам по себе рекурсивно копирует с учётом -exclude или -include. »
Это Вы погорячились, понадеявшись на разработчиков из микрософт... увы не всё так радужно, как кажется...
В случае копирования каталога целиком, это работает, а вот в случае выборочного копирования, увы и ах, сохранения структуры не получится...
чтобы powershell рекурсивно отобрал файлы и скопировал в каталог назначения »
Когда-то что-то подобное делал:
<#
.SYNOPSIS
Копирование или псевдоперемещение файлов и каталогов с сохранением структуры
.Description
Скрипт предназначен для копирования или перемещения файлов из одного каталога
в другой, при этом сохраняется вложенная структура каталогов. Фактически,
перемещение не выполняется, вместо него работает копирование с последующим
удалением скопированнных итемов.
.Parameter Source
Необязательный: Исходный каталог для выборки элементов. Указывается либо
относительный, либо абсолютный путь.
.Parameter Destination
Необязательный: Целевой каталог. Указывается либо относительный, либо
абсолютный путь.
.Parameter Include
Необязательный: маска(и) для включения файлов в выборку
.Parameter Exclude
Необязательный: маска(и) для исключения файлов из выборки
.Parameter Delete
Переключатель: Если указан, то будут удалены исходные файлы, включенные в выборку,
рекурсивно
.Parameter Emptydelete
Переключатель: Если указан, то будут удалены пустые подкаталоги в исходном каталоге,
рекурсивно
.Example
.\script.ps1 -sourc "D:\FOLDER1" -dest "d:\Folder2" -incl '*.pdf','*.txt' -excl '*_out.*' -del
Это пример перемещения файлов по маскам '*.pdf','*.txt' с исключением из выборки по маске
'*_out.*', с последующим удалением исходных элементов. Пустые каталоги не удаляются.
.Example
.\script.ps1
Это пример копирования/перемещения файлов/каталогов, с сохранением структуры, но
по указанным в самом скрипте параметрам...
.Link
[удалено во избежание нарушения]
.Notes
Created By YuS
Version: 1.00
Date: 20.01.2021
Purpose/Change: Первая версия
#>
# requires v 3.0
param (
[string]
$source = ".\Folder1",
[string]
$destination = ".\Folder2",
[string[]]
$include = '*.*',
[string[]]
$exclude = '',
[switch]
$delete,
[switch]
$emptydelete
)
$src = gi -lit $source -force
# копирование файлов с сохранением структуры
dir -lit $src.fullname -inc $include -exc $exclude -rec -force|copy -d {
$d = split-path $_.fullname.replace("$($src.fullname)",$destination)
if (!(test-path -lit $d)){md $d -force} else {$d}
} -force #-whatif
if ($delete) {
# удаляем все скопированные файлы
dir -lit $src.fullname -inc $include -exc $exclude -rec -force -file|
del -force -rec
}
if ($emptydelete) {
# удаляем пустые каталоги
dir -lit $src.fullname -rec -dir -force|sort{$_.fullname.length} -des|%{
if((dir -lit $_.fullname -rec -force) -eq $null){
del -lit $_.fullname -force
}
}
}
- линк на ресурс, где был опубликован скрипт, удален... если что-то непонятно, спрашивайте.
Конкретно для Вашего случая (скрипта), строка запуска будет такой:
.\script.ps1 -sourc $Source -dest $Dest -incl $getFiles.name
epoddubniy
09-02-2022, 12:17
Sham, не получилось. Запустил скрипт. Powershell никакой ошибки не выдал, но ничего и не скопировал, хотя измененные файлы со вчерашнего дня были.
YuS_2, может быть не совсем корректно изложил цель задачи... Попробую подробно, пошагово описать, то чего я хотел добиться и что получилось
У меня есть каталог
\\USER-PC\c$\users\User\Desktop, в этом каталоге много папок и подпапок и каждый день в этих подпапках изменяются файлы
Вот пример подкаталогов
\\USER-PC\c$\users\User\Desktop\Word
\\USER-PC\c$\users\User\Desktop\Сканы
\\USER-PC\c$\users\User\Desktop\Документы
Из этих папок я хочу скопировать только те файлы, которые были изменены вчера, но таким образом, чтобы в каталоге назначения они располагались в тех же папках и подпапках, откуда были скопированы.
Получить список файлов, измененных вчера, и скопировать их в одну кучу в каталог назначения у меня получилось, то есть в корень этого каталога
H:\USERPROFILE-BACKUP\Increment\$newfoldername
скопировались все файлы из папок и подпапок удовлетворяющие условию, но как сделать, чтобы например
\\USER-PC\c$\users\User\Desktop\Word\Реестр1.rtf скопировался в H:\USERPROFILE-BACKUP\Increment\$newfoldername\Desktop\Word\Реестр1.rtf
Ну и все остальные файлы - по аналогии...
- линк на ресурс, где был опубликован скрипт, удален... если что-то непонятно, спрашивайте.
Конкретно для Вашего случая (скрипта), строка запуска будет такой: »
Да, я встречал Ваш скрипт, но не смог его адаптировать под свою задачу
.\script.ps1 »
вот эта строка оказалась непонятной, непонятной ее значение, то есть, что мне нужно заменить в своем скрипте этим значением
[code]
epoddubniy
09-02-2022, 12:43
$Data=Get-Date -Format "dd.MM.yyyy"
$CurrentDay=get-date -format "%d"
$Source=""
$Dest=""
YuS_2, попробовал понять и отредактировать Ваш скрипт, но у меня не получилось. Запускать планирую через планировщик. Помогите с написанием строки запуска и поправкой в самом скрипте
param (
$Data = Get-Date -Format "dd.MM.yyyy"
$CurrentDay = get-date -format "%d"
$CurrentDayDD = get-date -format "dd"
$newfoldername = [string]$Data +"_"+ "User"
$MakeDir = New-Item -Path $Dest -ItemType Directory -force
$getFiles = Get-ChildItem $Source -Recurse | where-object {$_.lastwritetime -lt (get-date).date.adddays(1) -and $_.lastwritetime -ge (get-date).date.adddays(-1)
[string]
$Source = "\\USER-PC\c$\users\User\Desktop"
[string]
$destination = "H:\USERPROFILE-BACKUP\Increment\$newfoldername"
[string[]]
$include = $getFiles
)
$src = gi -lit $source -force
# копирование файлов с сохранением структуры
dir -lit $src.fullname -inc $include -rec -force|copy -d {
$d = split-path $_.fullname.replace("$($src.fullname)",$destination)
if (!(test-path -lit $d)){md $d -force} else {$d}
} -force #-whatif
вот эта строка оказалась непонятной, непонятной ее значение, то есть, что мне нужно заменить в своем скрипте этим значением »
это строка запуска скрипта, то бишь всё, что в коде, надо записать в файл script.ps1 и запускать уже из Вашего скрипта, предварительно поместив файл рядом с вашим файлом скрипта...
Ну или оформить всё в функцию и вызывать её прямо в Вашем же скрипте...
function copy-str {
param (
[string]
$source = ".\Folder1",
[string]
$destination = ".\Folder2",
[string[]]
$include = '*.*',
[string[]]
$exclude = '',
[switch]
$delete,
[switch]
$emptydelete
)
$src = gi -lit $source -force
# копирование файлов с сохранением структуры
dir -lit $src.fullname -inc $include -exc $exclude -rec -force|copy -d {
$d = split-path $_.fullname.replace("$($src.fullname)",$destination)
if (!(test-path -lit $d)){md $d -force} else {$d}
} -force #-whatif
if ($delete) {
# удаляем все скопированные файлы
dir -lit $src.fullname -inc $include -exc $exclude -rec -force -file|
del -force -rec
}
if ($emptydelete) {
# удаляем пустые каталоги
dir -lit $src.fullname -rec -dir -force|sort{$_.fullname.length} -des|%{
if((dir -lit $_.fullname -rec -force) -eq $null){
del -lit $_.fullname -force
}
}
}
}
#... здесь текст основного скрипта
# а здесь вызов функции:
copy-str -sourc $Source -dest $Dest -incl $getFiles.name
Не знаю как это будет работать с сетевыми путями, мне проверить не на чем...
Можно подменой папки в пути источника на папку назначения и созданием несуществующих папок через new-item. Не идеально, но рекурсивные папки создаёт и копирует.
$getFiles | foreach {
$new_path = $Dest + $_.FullName.Remove(0, $Source.TrimEnd('\').Length)
$dir_name = $new_path.Remove($new_path.LastIndexOf('\'))
if (-not (Test-Path $dir_name -PathType 'Container')) {
New-Item -Path $dir_name -ItemType 'Directory' -Force -Verbose
}
Copy-Item $_.FullName $new_path -Force -Verbose
}
DJ Mogarych
09-02-2022, 19:57
Почитайте про robocopy, очень полезная вещь.
epoddubniy
16-02-2022, 12:39
Почитайте про robocopy, очень полезная вещь. » да, читал, пробовал пользовать - не поладил я с ней. Не получилось у меня в этой утилите с рекурсивным отбором файлов по условию.
Sham, Спасибо.
$getFiles | foreach {
$new_path = $Dest + $_.FullName.Remove(0, $Source.TrimEnd('\').Length)
$dir_name = $new_path.Remove($new_path.LastIndexOf('\'))
if (-not (Test-Path $dir_name -PathType 'Container')) {
New-Item -Path $dir_name -ItemType 'Directory' -Force -Verbose
}
Copy-Item $_.FullName $new_path -Force -Verbose
} »
То что нужно, то, что хотел но не знал как сделать.
Sham, позвольте пожалуйста Вас немного помучить.
Sham, объясните пожалуйста $_.FullName.Remove(0, $Source.TrimEnd('\').Length) » что делает вот эта команда? Как можно догадаться, что после $_.FullName можно поставить точку и еще потом использовать Remove с какими-то параметрами.
$new_path.Remove($new_path.LastIndexOf('\')) » Remove - это какой-то модуль для работы со строками? А LastIndexOf - это тоже какая-то команда? А ее только со строками можно использовать и через "точку"?
Как можно догадаться, что после $_.FullName можно поставить точку и еще потом использовать Remove с какими-то параметрами. »
есть офигенская команда get-member, по пайпу она принимает то что вываливается из предыдущей команды и говорит почти понятным языком, что с этим можно сделать.
например вот так:
Get-Item ./ | Get-Member
или из переменной
$new_variable | Get-Member
$getFiles содержит массив объектов FileInfo, которые наследует от FileSystemInfo с этим свойством Fullname (https://docs.microsoft.com/en-us/dotnet/api/system.io.filesysteminfo.fullname), которое отдаёт полный путь к файлу в виде строки. Строка тоже объект (https://docs.microsoft.com/en-us/dotnet/api/system.string) с кучей методов. Remove (https://docs.microsoft.com/en-us/dotnet/api/system.string.remove#system-string-remove(system-int32-system-int32)) отдаёт строку без префикса в виде папки источника, чтобы слева к нему приклеить папку назначения. TrimEnd (https://docs.microsoft.com/en-us/dotnet/api/system.string.trimend#system-string-trimend(system-char)) удаляет возможный конечный слеш папки источника, при наличии которого обрежется слеш в начале (обрезаем по длине пути папки источника).
$new_path.Remove($new_path.LastIndexOf('\')) это [IO.Path]::GetDirectoryName (https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getdirectoryname#system-io-path-getdirectoryname(system-string))($new_path). Обрезаем всё от последнего слеша до конца. Получаем путь новой папки, чтобы проверить её наличие и создать в случае чего.
epoddubniy
17-02-2022, 16:35
Sham, спасибо, буду все равно, пока практически ничего не понятно :) Буду смотреть ссылки, читать справочную информацию
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.