iNNOKENTIY21
Silver Member | Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору Код: <# .SYNOPSIS Копирование из теневой копии. .DESCRIPTION Создание теневой копии и копирование из неё указанных файлов, папок, рекурсивно. .PARAMETER Source Откуда копировать, один или множество путей к файлам, папкам. .PARAMETER Destination Куда копировать, путь к папке. Должен существовать до начала работы скрипта. .EXAMPLE PS> 'C:\Projects', 'F:\Work' | >> .\Copy-FromShadowCopy.ps1 -Destination 'G:\Back\' -Verbose -WhatIf .EXAMPLE PS> ls C:\Docs\*.doc | .\Copy-FromShadowCopy.ps1 -Destination 'G:\Back\Docs' .NOTES Автор: iNNOKENTIY21 #> ## Указывает минимальную версию PowerShell, требуемую сценарию. #Requires -Version 5.1 ## Сценарий, должен запускаться с повышенными правами пользователя #Requires -RunAsAdministrator [CmdletBinding(SupportsShouldProcess)] param ( # Что копировать. Массив полных путей. Полные пути из конвейера [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidateNotNullOrEmpty()] [string[]] [Alias("FullName")] $Sources, # Куда копировать. Полный путь к папке назначения [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Destination ) begin { function New-ShadowCopy { <# .SYNOPSIS Создание теневой копии .DESCRIPTION Функция создаёт теневую копию для указанного диска. NTFS ссылку на созданную теневую копию, для доступа к теневой копии. .PARAMETER Disc Диск для которого создать теневую копию (в формате C: или C:\). .INPUTS [string] — строка из двух или трёх символов, представляющих диск. .OUTPUTS [pscustomobject] — объект со свойствами теневой копии и NTFS ссылки. .NOTES Автор: iNNOKENTIY21 Для работы функции требуются повышенные права. .EXAMPLE PS> New-ShadowCopy -Disc 'C:' #> param ( # Диск для создания теневой копии (Пример: C:\ или C:) [Parameter( Mandatory, HelpMessage = 'Укажите диск (например c:)' )] [ValidateNotNullOrEmpty()] [ValidateCount(2, 3)] [ValidateScript( { (Test-Path $PSItem -PathType Container) -and (Split-Path $PSItem -IsAbsolute) })] [string] $Disc ) if ($Disc.EndsWith(':')) { $Disc = Join-Path -Path $Disc -ChildPath \ } $Volumes = vssadmin List Volumes | Where-Object { $PSItem -match "(.+:\s)([a-zA-Z]:\\)$" } | ForEach-Object { $Matches[2] } if ($Volumes -notcontains $Disc) { throw "Для диска '$Disc' — невозможно создать теневую копию!" } #region Создание теневой копии $ShadowID = ((Get-WmiObject -List Win32_ShadowCopy).Create( $Disc, "ClientAccessible")).ShadowID Write-Verbose "Создана теневая копия с ID: $ShadowID" $DeviceObject = (Get-WmiObject Win32_ShadowCopy | Where-Object { $_.ID -eq $ShadowID }).DeviceObject Write-Verbose "Создан объект устройства: $DeviceObject" $ShadowCopyPath = Join-Path -Path $DeviceObject -ChildPath \ Write-Verbose "Путь теневой копии: $ShadowCopyPath" #endregion #region Создание ссылки на теневую копию $Name = (Split-Path $ShadowCopyPath -Leaf) Write-Verbose "Имя теневой копии: $Name" $CurrentDateTime = Get-Date -Format ("yyyy.MM.dd-hh.mm.ss") Write-Verbose "Текущая дата и время: $CurrentDateTime" $MountName = "{0}-{1}" -f $Name, $CurrentDateTime Write-Verbose "Имя для создания ссылки: $MountName" $MountPoint = Join-Path -Path $Disc -ChildPath $MountName Write-Verbose "Точка монтировния: $MountPoint" $null = cmd /c mklink /d "$MountPoint" "$ShadowCopyPath" Write-Verbose "Создание ссылки для теневой копии" #endregion # Вывод объекта с информацией о созданной теневой копии [pscustomobject] @{ "Disc" = $Disc "ShadowID" = $ShadowID "DeviceObject" = $DeviceObject "ShadowCopyPath" = $ShadowCopyPath "MountName" = $MountName "MountPoint" = $MountPoint } } function Remove-ShadowCopy { <# .SYNOPSIS Удаление теневой копии .DESCRIPTION Функция удаляет теневую копию и созданную для доступа к ней NTFS ссылку. .PARAMETER ShadowID ID теневой копии. .PARAMETER MountPoint NTFS ссылка на теневую копию. .INPUTS [string] — ID теневой копии. [string] — NTFS ссылка на теневую копию. .NOTES Автор: iNNOKENTIY21 Для работы функции требуется утилита vssadmin и повышенные права. .EXAMPLE PS> Remove-ShadowCopy -ShadowID $ShadowID -MountPoint $MountPoint --- $ShadowID — ID теневой копии. $MountPoint — полный путь к NTFS ссылке. #> param ( # ID теневой копии [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ShadowID, # Точка монтирования теневой копии (NTFS link) [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $MountPoint ) #region Удаление теневой копии $null = vssadmin Delete Shadows /Shadow="$ShadowID" /Quiet Write-Verbose "Теневая копия с id: $ShadowID — удалена" #endregion #region Удаление точки монтирования теневой копии # Remove-Item — баг: https://github.com/powershell/powershell/issues/621 # https://stackoverflow.com/questions/51160864/ (Get-Item $MountPoint).Delete() Write-Verbose "Точка монтирования: $MountPoint — удалена" #endregion } $ShadowCopies = @() } process { foreach ($Source in $Sources) { #region Создание теневой копии $Disc = Join-Path (Split-Path -Path $Source -Qualifier) '\' Write-Verbose "Определение диска для создания его теневой копии: $Disc" if ($ShadowCopies.Disc -contains $Disc) { $Target = $Disc $Action = "Используем имеющиюся теневую копию" if ($PSCmdlet.ShouldProcess($Target, $Action)) { $ShadowCopy = $ShadowCopies | Where-Object Disc -eq $Disc Write-Verbose "$Action`: $ShadowCopy" } } else { $Target = $Disc $Action = "Создание теневой копии" if ($PSCmdlet.ShouldProcess($Target, $Action)) { $ShadowCopy = try { New-ShadowCopy -Disc $Disc } catch { $Error[0].Exception.Message continue } $ShadowCopies += $ShadowCopy Write-Verbose "$Action`: $ShadowCopy" } else { $ShadowCopy = @{ Disc = $Disc } $ShadowCopies += $ShadowCopy } } #endregion #region Копирование из теневой копии Write-Verbose "Полный путь источника: $Source" $SourceWithoutQualifier = Split-Path -Path $Source -NoQualifier Write-Verbose "Относительный путь источника: $SourceWithoutQualifier" $Target = "Полный путь источника: Теневая копия:$SourceWithoutQualifier" $Action = "Переопределение" if ($PSCmdlet.ShouldProcess($Target, $Action)) { $SourcePath = Join-Path ` -Path $ShadowCopy.MountPoint ` -ChildPath $SourceWithoutQualifier Write-Verbose "Полный путь источника: $SourcePath" } else { $SourcePath = "Теневая копия:$SourceWithoutQualifier" } Write-Verbose "Путь назначения: $Destination" $Target = "$SourcePath Назначение: $Destination" $Action = "Копирование" if ($PSCmdlet.ShouldProcess($Target, $Action)) { $Copied = (Copy-Item ` -LiteralPath $SourcePath ` -Destination $Destination ` -Recurse ` -Force ` -PassThru ` -ErrorAction SilentlyContinue ).FullName if ($Copied) { $Copied | Write-Verbose } } #endregion } } end { foreach ($SC in $ShadowCopies) { # Удаление теневой копии и ссылки на неё $Target = "Теневая копия и cсылка" $Action = "Удаление" if ($PSCmdlet.ShouldProcess($Target, $Action)) { Remove-ShadowCopy -ShadowID $SC.ShadowID -MountPoint $SC.MountPoint Write-Verbose "Удалена теневая копия: $SC" } } } | |