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)] [ValidateNotNullOrEmpty()] [string[]] [Alias("FullName")] $Sources, # Куда копировать. Полный путь к папке назначения [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Destination ) begin { function New-ShadowCopy { 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 \ } # Создание теневой копии $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" # Создание ссылки на теневую копию $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 "Создание ссылки для теневой копии" # Вывод объекта с информацией о созданной теневой копии [pscustomobject] @{ "Disc" = $Disc "ShadowID" = $ShadowID "DeviceObject" = $DeviceObject "ShadowCopyPath" = $ShadowCopyPath "MountName" = $MountName "MountPoint" = $MountPoint } } function Remove-ShadowCopy { param ( # ID теневой копии [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ShadowID, # Точка монтирования теневой копии (NTFS link) [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $MountPoint ) # Удаление теневой копии $null = vssadmin Delete Shadows /Shadow="$ShadowID" /Quiet Write-Verbose "Теневая копия с id: $ShadowID — удалена" # Удаление точки монтирования теневой копии # Remove-Item — баг: https://github.com/powershell/powershell/issues/621 # https://stackoverflow.com/questions/51160864/ (Get-Item $MountPoint).Delete() Write-Verbose "Точка монтирования: $MountPoint — удалена" } $ShadowCopies = @() } process { foreach ($Source in $Sources) { # Создание теневой копии $Disc = Join-Path (Split-Path -Path $Source -Qualifier) '\' Write-Verbose "Определение диска для создания его теневой копии: $Disc" if ($ShadowCopies.Disc -contains $Disc) { $ShadowCopy = $ShadowCopies | Where-Object Disc -eq $Disc Write-Verbose "Используем имеющиюся теневую копию: $ShadowCopy" } else { $ShadowCopy = New-ShadowCopy -Disc $Disc $ShadowCopies += $ShadowCopy Write-Verbose "Создана теневая копия: $ShadowCopy" } # Копирование из теневой копии $SourceWithoutQualifier = Split-Path -Path $Source -NoQualifier Write-Verbose "Относительный путь источника: $SourceWithoutQualifier" $SourcePath = Join-Path ` -Path $ShadowCopy.MountPoint ` -ChildPath $SourceWithoutQualifier Write-Verbose "Полный путь источника: $SourcePath" Write-Verbose "Путь назначения: $Destination" $Copied = (Copy-Item ` -LiteralPath $SourcePath ` -Destination $Destination ` -Recurse ` -Force ` -PassThru ` -ErrorAction SilentlyContinue ).FullName if ($Copied) { $Copied | Write-Verbose } } } end { foreach ($SC in $ShadowCopies) { # Удаление теневой копии и ссылки на неё Remove-ShadowCopy -ShadowID $SC.ShadowID -MountPoint $SC.MountPoint Write-Verbose "Удалена теневая копия: $SC" } } |
|