Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Копирование из сети в локальную папку с сохранением структуры каталогов (http://forum.oszone.net/showthread.php?t=350651)

epoddubniy 08-02-2022 16:51 2979569

Копирование из сети в локальную папку с сохранением структуры каталогов
 
Здравствуйте.
Помогите пожалуйста доработать скрипт (или создать новый)

Код:


# переменные
$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 рекурсивно отобрал файлы и скопировал в каталог назначения, а как сделать, чтобы "в соответствующий каталог" копировал - не смог придумать

Sham 09-02-2022 01:15 2979597

Copy-Item сам по себе рекурсивно копирует с учётом -exclude или -include.
Код:

Copy-Item -Path $Source\* -Destination $Dest -Recurse -Include $getFiles

YuS_2 09-02-2022 05:57 2979602

Цитата:

Цитата Sham
Copy-Item сам по себе рекурсивно копирует с учётом -exclude или -include. »

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

Цитата:

Цитата epoddubniy
чтобы 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 2979624

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
Ну и все остальные файлы - по аналогии...

Цитата:

Цитата YuS_2
- линк на ресурс, где был опубликован скрипт, удален... если что-то непонятно, спрашивайте.
Конкретно для Вашего случая (скрипта), строка запуска будет такой: »

Да, я встречал Ваш скрипт, но не смог его адаптировать под свою задачу
Цитата:

Цитата YuS_2
.\script.ps1 »

вот эта строка оказалась непонятной, непонятной ее значение, то есть, что мне нужно заменить в своем скрипте этим значением

[code]

epoddubniy 09-02-2022 12:43 2979626

$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


YuS_2 09-02-2022 13:44 2979640

Цитата:

Цитата epoddubniy
вот эта строка оказалась непонятной, непонятной ее значение, то есть, что мне нужно заменить в своем скрипте этим значением »

это строка запуска скрипта, то бишь всё, что в коде, надо записать в файл 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

Не знаю как это будет работать с сетевыми путями, мне проверить не на чем...

Sham 09-02-2022 17:34 2979654

Можно подменой папки в пути источника на папку назначения и созданием несуществующих папок через 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 2979665

Почитайте про robocopy, очень полезная вещь.

epoddubniy 16-02-2022 12:39 2980174

Цитата:

Цитата DJ Mogarych
Почитайте про robocopy, очень полезная вещь. »

да, читал, пробовал пользовать - не поладил я с ней. Не получилось у меня в этой утилите с рекурсивным отбором файлов по условию.

Sham, Спасибо.
Цитата:

Цитата 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, объясните пожалуйста
Цитата:

Цитата Sham
$_.FullName.Remove(0, $Source.TrimEnd('\').Length) »

что делает вот эта команда? Как можно догадаться, что после $_.FullName можно поставить точку и еще потом использовать Remove с какими-то параметрами.
Цитата:

Цитата Sham
$new_path.Remove($new_path.LastIndexOf('\')) »

Remove - это какой-то модуль для работы со строками? А LastIndexOf - это тоже какая-то команда? А ее только со строками можно использовать и через "точку"?

Elven 16-02-2022 15:59 2980187

Цитата:

Цитата epoddubniy
Как можно догадаться, что после $_.FullName можно поставить точку и еще потом использовать Remove с какими-то параметрами. »

есть офигенская команда get-member, по пайпу она принимает то что вываливается из предыдущей команды и говорит почти понятным языком, что с этим можно сделать.
например вот так:
Код:

Get-Item ./ | Get-Member
или из переменной
Код:

$new_variable | Get-Member

Sham 17-02-2022 03:33 2980213

$getFiles содержит массив объектов FileInfo, которые наследует от FileSystemInfo с этим свойством Fullname, которое отдаёт полный путь к файлу в виде строки. Строка тоже объект с кучей методов. Remove отдаёт строку без префикса в виде папки источника, чтобы слева к нему приклеить папку назначения. TrimEnd удаляет возможный конечный слеш папки источника, при наличии которого обрежется слеш в начале (обрезаем по длине пути папки источника).
$new_path.Remove($new_path.LastIndexOf('\')) это [IO.Path]::GetDirectoryName($new_path). Обрезаем всё от последнего слеша до конца. Получаем путь новой папки, чтобы проверить её наличие и создать в случае чего.

epoddubniy 17-02-2022 16:35 2980275

Sham, спасибо, буду все равно, пока практически ничего не понятно :) Буду смотреть ссылки, читать справочную информацию


Время: 18:05.

Время: 18:05.
© OSzone.net 2001-