如何枚举给定文件或文件夹的卷影副本?

时间:2016-11-25 01:51:01

标签: powershell

所以我实际上是尝试使用PowerShell检索屏幕截图中的信息。有点难以接受第一道障碍。

enter image description here

我能找到的最好的是https://superuser.com/questions/643536/how-to-find-and-open-previous-versions-of-a-folder-programmatically-using-power

但它并不适合。

正在阅读https://msdn.microsoft.com/en-us/library/aa393625(v=vs.85).aspx

但我无法理解它。这是正确的道路吗?

5 个答案:

答案 0 :(得分:1)

Accessing Volume Shadow Copy (VSS) Snapshots from powershell有一些进一步的信息。

还有一个名为vssadmin的实用程序,它似乎是本机实用程序。此链接使用vssadmin和select-string来获取信息。 https://p0w3rsh3ll.wordpress.com/2014/06/21/mount-and-dismount-volume-shadow-copies/

答案 1 :(得分:1)

PowerShell中有一些步骤可以浏览卷影副本。 首先,下面的代码将显示驱动器及其卷影副本的列表

$shadowStorageList = @();
$volumeList = Get-WmiObject Win32_Volume -Property SystemName,DriveLetter,DeviceID,Capacity,FreeSpace -Filter "DriveType=3" | select @{n="DriveLetter";e={$_.DriveLetter.ToUpper()}},DeviceID,@{n="CapacityGB";e={([math]::Round([int64]($_.Capacity)/1GB,2))}},@{n="FreeSpaceGB";e={([math]::Round([int64]($_.FreeSpace)/1GB,2))}} | Sort DriveLetter;
$shadowStorages = gwmi Win32_ShadowStorage -Property AllocatedSpace,DiffVolume,MaxSpace,UsedSpace,Volume |
                Select @{n="Volume";e={$_.Volume.Replace("\\","\").Replace("Win32_Volume.DeviceID=","").Replace("`"","")}},
                @{n="DiffVolume";e={$_.DiffVolume.Replace("\\","\").Replace("Win32_Volume.DeviceID=","").Replace("`"","")}},
                @{n="AllocatedSpaceGB";e={([math]::Round([int64]($_.AllocatedSpace)/1GB,2))}},
                @{n="MaxSpaceGB";e={([math]::Round([int64]($_.MaxSpace)/1GB,2))}},
                @{n="UsedSpaceGB";e={([math]::Round([int64]($_.UsedSpace)/1GB,2))}}

# Create an array of Customer PSobject
foreach($shStorage in $shadowStorages) {
    $tmpDriveLetter = "";
    foreach($volume in $volumeList) {
        if($shStorage.DiffVolume -eq $volume.DeviceID) {
            $tmpDriveLetter = $volume.DriveLetter;
        }
    }
    $objVolume = New-Object PSObject -Property @{
        Volume = $shStorage.Volume
        AllocatedSpaceGB = $shStorage.AllocatedSpaceGB
        UsedSpaceGB = $shStorage.UsedSpaceGB
        MaxSpaceGB = $shStorage.MaxSpaceGB
        DriveLetter = $tmpDriveLetter
    }
    $shadowStorageList += $objVolume;
}


for($i = 0; $i -lt $shadowStorageList.Count; $i++){
    $objCopyList = Get-WmiObject Win32_ShadowCopy  | Where-Object {$_.VolumeName -eq $shadowStorageList[$i].Volume} | select DeviceObject, InstallDate
    $shadowStorageList[$i] | add-member Noteproperty shadowcopies $objCopyList
    $shadowStorageList[$i]
}

示例输出:

  

AllocatedSpaceGB:9.17 DriveLetter:F:音量:   \?\卷{6c974bfe-0525-11e7-80bf-0050568007f5} \ MaxSpaceGB:   15 UsedSpaceGB:8.46 shadowcopies:   {@ {设备对象= \ \ GLOBALROOT \设备\ HarddiskVolumeShadowCopy39?;                      InstallDate = 20170902070009.648986 + 600},@ {DeviceObject = \?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy40;                      InstallDate = 20170903070009.902376 + 600},@ {DeviceObject = \?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy41;                      InstallDate = 20170904070016.340573 + 600},@ {DeviceObject = \?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy42;                      InstallDate = 20170904120031.644419 + 600} ...}

     

AllocatedSpaceGB:6.28 DriveLetter:C:卷:   \?\卷{4c22f9da-2b50-11e6-80b3-806e6f6e6963} \ MaxSpaceGB:   6.96 UsedSpaceGB:5.78 shadowcopies:{@ {DeviceObject = \?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy3;   InstallDate = 20170921070020.298687 + 600},                      @ {设备对象= \ \ GLOBALROOT \设备\ HarddiskVolumeShadowCopy4?;   InstallDate = 20170921120026.126738 + 600},                      @ {设备对象= \ \ GLOBALROOT \设备\ HarddiskVolumeShadowCopy5?;   InstallDate = 20170922070025.309517 + 600},                      @ {设备对象= \ \ GLOBALROOT \设备\ HarddiskVolumeShadowCopy6?;                      InstallDate = 20170922120004.852824 + 600} ...}

要浏览卷影副本(例如GLOBALROOT \ Device \ HarddiskVolumeShadowCopy6),您需要创建一个符号链接(Windows快捷方式),然后您可以在Windows资源管理器中浏览。 示例代码如下:

# Load assembly to create symlink
try {
    $null = [mklink.symlink]
}
catch {
Add-Type @"
    using System;
    using System.Runtime.InteropServices;

  namespace mklink
    {
    public class symlink
    {
        [DllImport("kernel32.dll")]
        public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
    }
  }
"@
}
# create symlink
[mklink.symlink]::CreateSymbolicLink('symlink path (example C:\temp\link1)', '\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy4\', 1);

答案 2 :(得分:0)

尽管这可能不是OP问题的精确解决方案,但我将其添加到几个相关的帖子中,希望它可以帮助其他人,像我一样,需要一种方法来列出远程路径上的所有快照。搜索这是一个痛苦的过程,我将放弃直到找到答案。

我搜索并搜索了以编程方式列出以前版本的功能。找不到在SMB / CIFS共享上查看以前版本的解决方案。 Volrest,vssadmin,alphaVss等。一轮又一轮..甚至win32_shadowCopy都失败了,因为我们的目标机器是netapps。什么都没有。

然后,我根据这篇文章中的内容说,他们可以在Perl中使用SMB命令来查看它们。 https://mark.clow.es/?blog/2018/02/listing-shadow-copies

如果Perl可以做到,那么肯定有一些winAPI也可以。 FSCTL_SRV_ENUMERATE_SNAPSHOTS是所需的SMB命令。 https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/bffc70f9-b16a-453b-939a-0b6d3c9263af

最后找到了这个天才(上帝保佑kenjiuno),他为.NET创建了一个dll:https://github.com/HiraokaHyperTools/LibEnumRemotePreviousVersion

添加对kenjiuno dll的引用后,我将其命名为:

Dim s() as String = LibEnumRemotePreviousVersion.PreviousversionOnRemote("\\server\share")

它以@ GMT-blablabla返回所有以前的版本。然后,您所需要做的就是将想要的内容附加到UNC路径的末尾。

没有mklink,没有映射驱动器,没有..一切都可以正常工作,就像微软将自己的头放到.Net中一样,它应该像应该的那样简单。

答案 3 :(得分:0)

影子副本不是按文件夹存储的。这是按卷计算的。您可以通过在 HKLM\system\CurrentControlSet\Control\BackupRestore\FilesNotToSnapshot 中设置注册表项来排除在该卷上进行卷影复制的内容。你会在那里看到例子。请注意指示递归子目录的“/s”参数。另请注意,您不能在路径中间放置通配符。他们只能在最后。下面是我的脚本,用于枚举副本及其相关信息。

$SnapshotState=@("VSS_SS_UNKNOWN","VSS_SS_PREPARING","VSS_SS_PROCESSING_PREPARE","VSS_SS_PREPARED","VSS_SS_PROCESSING_PRECOMMIT","VSS_SS_PRECOMMITTED","VSS_SS_PROCESSING_COMMIT","VSS_SS_COMMITTED","VSS_SS_PROCESSING_POSTCOMMIT","VSS_SS_PROCESSING_PREFINALCOMMIT","VSS_SS_PREFINALCOMMITTED","VSS_SS_PROCESSING_POSTFINALCOMMIT","VSS_SS_CREATED","VSS_SS_ABORTED","VSS_SS_DELETED","VSS_SS_POSTCOMMITTED","VSS_SS_COUNT")
$Volumes=Get-Volume
$ShadowProvider=Get-WmiObject -Namespace "root\cimv2" -Class "Win32_ShadowProvider" | Select-Object -Property ID,Name
$ShadowOn=Get-WmiObject -Namespace "root\cimv2" -Class "Win32_ShadowOn" | Select-Object -Property Dependent,Antecedent
$ShadowOn | ForEach-Object { $_.Dependent=$_.Dependent.Replace("Win32_ShadowCopy.ID=",""); $_.Antecedent=$_.Antecedent.Replace("Win32_Volume.DeviceID=",""); $_.Dependent=$_.Dependent.Replace('"',""); $_.Antecedent=$_.Antecedent.Replace('"',""); $_.Antecedent=$_.Antecedent.Replace("\\","\") }
$ShadowCopy=Get-WmiObject -Namespace "root\cimv2" -Class "Win32_ShadowCopy"
$ShadowCopy=@($ShadowCopy)
for ($i=0; $i -lt $ShadowCopy.Count; $i++) {
  $DiffVolume=$ShadowOn | Where-Object { $_.Dependent -eq $ShadowCopy[$i].ID } | Select-Object -ExpandProperty Antecedent
  $DiffVolume=$Volumes | Where-Object { $_.Path -eq $DiffVolume } | Select-Object -ExpandProperty DriveLetter
  $ShadowCopy[$i] | Add-Member -MemberType NoteProperty -Name "DiffVolume" -Value $DiffVolume
  $DriveLetter=$Volumes | Where-Object { $_.Path -eq $ShadowCopy[$i].VolumeName } | Select-Object -ExpandProperty DriveLetter
  $ShadowCopy[$i] | Add-Member -MemberType NoteProperty -Name "Volume" -Value $DriveLetter
  $ShadowCopy[$i] | Add-Member -MemberType NoteProperty -Name "strState" -Value $SnapshotState[$ShadowCopy[$i].State]
  $ShadowCopy[$i] | Add-Member -MemberType NoteProperty -Name "CreateDate" -Value ([System.Management.ManagementDateTimeConverter]::ToDateTime($ShadowCopy[$i].InstallDate))
  $ShadowCopy[$i].PSObject.Properties.Remove("VolumeName")
  $ShadowCopy[$i] | Add-Member -MemberType NoteProperty -Name "Provider" -Value ($ShadowProvider | Where-Object { $_.ID -eq $ShadowCopy[$i].ProviderID } | Select-Object -ExpandProperty Name)
  $ShadowCopy[$i].PSObject.Properties.Remove("ProviderID")
}
$ShadowCopy | Select-Object Count,CreateDate,Volume,DiffVolume,strState,MaxSpace,UsedSpace,AllocatedSpace,Persistent,Differential,ClientAccessible,NoAutoRelease,NoWriters,ExposedLocally,ExposedRemotely,NotSurfaced,Transportable,Provider | Sort-Object -Property Count

答案 4 :(得分:0)

经过互联网上的多次尝试和复制粘贴代码示例, 我想出了这个解决方案,也许有人会觉得它有用。

      function Get_Snapshots
            {
            param (
                [ValidateScript({
                        if (-Not ($_ | Test-Path -PathType Container))
                        {
                            throw "Not a Diretory"
                        }       
                        return $true
                    })]
                [System.IO.FileInfo]$Path
            )
            
            
                if (-not ("Snapshot.GetSnapshot" -as [type]))
                {
                    Add-Type -Language VisualBasic  @"
                    Imports System
                    Imports System.Collections.Generic
                    Imports System.IO
                    Imports System.Runtime.InteropServices
                    Namespace Snapshot
                        Public Class GetSnapshot
                            <StructLayout(LayoutKind.Sequential)> Structure IOSTATUSBLOCK
                                Public Status As Integer
                                Public Information As Integer
                            End Structure
                            Declare Function NtFsControlFile Lib "ntdll" (ByVal FileHandle As Microsoft.Win32.SafeHandles.SafeFileHandle, ByVal Evennt As IntPtr, ByVal ApcRoutine As IntPtr, ByVal ApcContext As IntPtr, ByRef IoStatusBlock As IOSTATUSBLOCK, ByVal FsControlCode As Integer,  ByVal InputBuffer() As Byte,  ByVal InputBufferLength As Integer,  ByVal OutputBuffer() As Byte,  ByVal OutputBufferLength As Integer) As IntPtr
                            Declare Auto Function CreateFile Lib "kernel32.dll" (ByVal lpFileName As String,ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As IntPtr)As Microsoft.Win32.SafeHandles.SafeFileHandle
                        End Class
                    End Namespace   
            
"@
            }
                try{
                    $NtStatus = [System.Byte[]]::CreateInstance([System.Byte], 64000)
                    $NtStatusClean = [System.Byte[]]::CreateInstance([System.Byte], 64000)
                
                    $Filehandle = [Snapshot.GetSnapshot]::CreateFile([ref]$Path, 129, 1, [System.IntPtr]::Zero, 3, 33554432, [System.IntPtr]::Zero)     
                    
                    $objIOStatusBlock = [Activator]::CreateInstance([Snapshot.GetSnapshot+IOSTATUSBLOCK])
                                                                                
                    $intServerResponse = [Snapshot.GetSnapshot]::NtFsControlFile($Filehandle, [System.IntPtr]::Zero, [System.IntPtr]::Zero, [System.IntPtr]::Zero, [ref]$objIOStatusBlock, 1327204, $null, 0, $NtStatus, $NtStatus.Length);
                        
                    
                    $Filehandle.Dispose()
                        
                    if ($intServerResponse -ne 0)
                    {
                        return ("Error request was not successfull: " + $intServerResponse)
                    }
                    
                    [System.Array]::Copy($NtStatus, 12, $NtStatusClean, 0, ($NtStatusClean.Length - 12))    
                            
                    $Snapshots = ([System.Text.Encoding]::Unicode.GetString($NtStatusClean) -split "`0" | Where-Object { $_ -ne "" })
                    $Snapshots
                }
                catch 
                {
                    $Error[0]  
                }
             }

示例: Get_Snapshots h:\P12

@GMT-2021.08.05-08.30.01
@GMT-2021.08.04-14.00.08

之后我可以做一个“get-childitem h:\P12\@GMT-20xxx”