如何使用卷影副本进行备份


11

该计划是创建一个很大的I / O大量卷的卷影副本。它的容量为350GB,其中包含基于文件系统的全文本索引,该索引组织成百上千个文件夹,成千上万个微小文件需要保持一致的状态才能成功还原。

当前,索引器已停止,备份任务正在运行,然后重新启动索引器。这导致索引在备份过程中无法使用数小时。我想通过卷影副本进行一致的备份,理想情况下完全不必停止索引器。

因此,我已经为该卷打开了卷影复制并将其配置为每晚创建一次快照到另一个卷。

现在我有些茫然-如何访问卷影副本的整体,以便进行备份?我设想了一个只读驱动器,其中包含的文件与上次快照时的文件相同,但是也许工作原理完全不同。

操作系统是Windows Server 2003 SP2,备份软件是CommVault Galaxy 7.0。


编辑:请注意-同时-已创建了两个答案,以脚本的形式实现了必要的功能:


commvault星系是否已使用VSS创建备份?我依稀记得,CommVault的是第一个厂商impleent基于VSS备份解决方案之一
吉姆乙

@Jim:是的,但仅针对逐个文件的锁定文件。我需要的是驱动器上的所有文件处于一致状态。除非a)索引器不运行或b)我有快照副本(如VSS可以创建的快照副本),否则这不会发生。
Tomalak 2010年

VSS不能那样工作-它是VOLUME卷影副本。如果它使用VSS,则唯一的区别就是theat,这与您的持久快照备份软件使用临时快照不同。我想应用程序可以按文件删除快照,但不仅备份会不一致,而且即使是默认的Windows安装,备份时间也要几天左右。有关VSS处理工作原理的图,请参见msdn.microsoft.com/zh-cn/library/aa384589(VS.85).aspx。我会联系commvault,看看他们是否可以确保您的备份配置正确。
Jim B

Answers:


10

因此,本着重塑方向盘的精神,我向您介绍了Tomalak出色的脚本(请参见上文),但完全用Powershell重写了!我这样做的主要原因是为了传播Powershell的强大功能,还因为我整个生命都鄙视vbscript。

它的主要特征是功能相同,但由于种种原因,我的确实现了一些不同的功能。调试输出肯定更详细。

需要注意的一个非常重要的事情是,此版本检测操作系统版本和位数,并调用vshadow.exe的适当版本。我在下面提供了一个图表,以显示要使用的vshadow.exe版本,在何处获取以及如何命名。


这是用法信息:

VssSnapshot.ps1

Description:
  Create, mount or delete a Volume Shadow Copy Service (VSS) Shadow Copy (snapshot)

Usage:
  VssSnapshot.ps1 Create -Target <Path> -Volume <Volume> [-Debug]
  VssSnapshot.ps1 Delete -Target <Path> [-Debug]

Paremeters:
  Create  - Create a snapshot for the specified volume and mount it at the specified target
  Delete  - Unmount and delete the snapshot mounted at the specified target
  -Target - The path (quoted string) of the snapshot mount point
  -Volume - The volume (drive letter) to snapshot
  -Debug  - Enable debug output (optional)

Examples:
  VssSnapshot.ps1 Create -Target D:\Backup\DriveC -Volume C
  - Create a snapshot of volume C and mount it at "D:\Backup\DriveC"

  VssSnapshot.ps1 Delete -Target D:\Backup\DriveC
  - Unmount and delete a snapshot mounted at "D:\Backup\DriveC"

Advanced:
  VssSnapshot.ps1 create -t "c:\vss mount\c" -v C -d
  - Create a snapshot of volume C and mount it at "C:\Vss Mount\C"
  - example mounts snapshot on source volume (C: --> C:)
  - example uses shortform parameter names
  - example uses quoted paths with whitespace
  - example includes debug output

这是脚本:

# VssSnapshot.ps1
# http://serverfault.com/questions/119120/how-to-use-a-volume-shadow-copy-to-make-backups/119592#119592

Param ([String]$Action, [String]$Target, [String]$Volume, [Switch]$Debug)
$ScriptCommandLine = $MyInvocation.Line
$vshadowPath = "."

# Functions
Function Check-Environment {
  Write-Dbg "Checking environment..."

  $UsageMsg = @'
VssSnapshot

Description:
  Create, mount or delete a Volume Shadow Copy Service (VSS) Shadow Copy (snapshot)

Usage:
  VssSnapshot.ps1 Create -Target <Path> -Volume <Volume> [-Debug]
  VssSnapshot.ps1 Delete -Target <Path> [-Debug]

Paremeters:
  Create  - Create a snapshot for the specified volume and mount it at the specified target
  Delete  - Unmount and delete the snapshot mounted at the specified target
  -Target - The path (quoted string) of the snapshot mount point
  -Volume - The volume (drive letter) to snapshot
  -Debug  - Enable debug output (optional)

Examples:
  VssSnapshot.ps1 Create -Target D:\Backup\DriveC -Volume C
  - Create a snapshot of volume C and mount it at "D:\Backup\DriveC"

  VssSnapshot.ps1 Delete -Target D:\Backup\DriveC
  - Unmount and delete a snapshot mounted at "D:\Backup\DriveC"

Advanced:
  VssSnapshot.ps1 create -t "c:\vss mount\c" -v C -d
  - Create a snapshot of volume C and mount it at "C:\Vss Mount\C"
  - example mounts snapshot on source volume (C: --> C:)
  - example uses shortform parameter names
  - example uses quoted paths with whitespace
  - example includes debug output
'@

  If ($Action -eq "Create" -And ($Target -And $Volume)) {
    $Script:Volume = (Get-PSDrive | Where-Object {$_.Name -eq ($Volume).Substring(0,1)}).Root
    If ($Volume -ne "") {
      Write-Dbg "Verified volume: $Volume"
    } Else {
      Write-Dbg "Cannot find the specified volume"
      Exit-Script "Cannot find the specified volume"
    }
    Write-Dbg "Argument check passed"
  } ElseIf ($Action -eq "Delete" -And $Target ) {
    Write-Dbg "Argument check passed"
  } Else {
    Write-Dbg "Invalid arguments: $ScriptCommandLine"
    Exit-Script "Invalid arguments`n`n$UsageMsg"
  }


  $WinVer = ((Get-WmiObject Win32_OperatingSystem).Version).Substring(0,3)
    Switch ($WinVer) {
    "5.2" {
      $vshadowExe = "vshadow_2003"
      $WinBit = ((Get-WmiObject Win32_Processor)[0]).AddressWidth
    }
    "6.0" {
      $vshadowExe = "vshadow_2008"
      $WinBit = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
    }
    "6.1" {
      $vshadowExe = "vshadow_2008R2"
      $WinBit = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
    }
    Default {
      Write-Dbg "Unable to determine OS version"
      Exit-Script "Unable to determine OS version"
    }
  }

  Switch ($WinBit) {
    {($_ -eq "32") -or ($_ -eq "32-bit")} {$vshadowExe += "_x86.exe"}
    {($_ -eq "64") -or ($_ -eq "64-bit")} {$vshadowExe += "_x64.exe"}
    Default {
      Write-Dbg "Unable to determine OS bitness"
      Exit-Script "Unable to determine OS bitness"
    }
  }

  $Script:vshadowExePath = Join-Path $vshadowPath $vshadowExe
  If (Test-Path $vshadowExePath) {
    Write-Dbg "Verified vshadow.exe: $vshadowExePath"
  } Else {
    Write-Dbg "Cannot find vshadow.exe: $vshadowExePath"
    Exit-Script "Cannot find vshadow.exe"
  }

  Write-Dbg "Environment ready"
}

Function Prepare-Target {
  Write-Log "Preparing target..."
  Write-Dbg "Preparing target $Target"


  If (!(Test-Path (Split-Path $Target -Parent))) {
  Write-Dbg "Target parent does not exist"
  Exit-Script "Invalid target $Target"
  }
  If ((Test-Path $Target)) {
    Write-Dbg "Target already exists"
    If (@(Get-ChildItem $Target).Count -eq 0) {
      Write-Dbg "Target is empty"
    } Else {
      Write-Dbg "Target is not empty"
      Exit-Script "Target contains files/folders"
    }
  } Else {
    Write-Dbg "Target does not exist. Prompting user..."
    $PromptYes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Create target folder"
    $PromptNo = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Do not create target folder"
    $PromptOptions = [System.Management.Automation.Host.ChoiceDescription[]]($PromptYes, $PromptNo)
    $PromptResult = $Host.UI.PromptForChoice("Create folder", "The target folder `"$target`" does not exist.`nWould you like to create the folder?", $PromptOptions, 0) 
    Switch ($PromptResult) {
      0 {
        Write-Dbg "User Accepted. Creating target..."
        $Null = New-Item -Path (Split-Path $Target -Parent) -Name (Split-Path $Target -Leaf) -ItemType "Directory"
      }
      1 {
        Write-Dbg "User declined. Exiting..."
        Exit-Script "Target does not exist"
      }
    }
  }
  Write-Log "Target ""$Target"" ready"
  Write-Dbg """$Target"" ready"
}

Function Create-Snapshot {
  Write-Log "Creating snapshot..."
  Write-Dbg "Creating snapshot of $Volume"
  $Cmd = "$vshadowExePath -p $Volume"
  $CmdResult = Run-Command $Cmd -AsString

  Write-Dbg "Snapshot created successfully"

  $SnapshotID = $CmdResult -Match 'SNAPSHOT ID = (\{[^}]{36}\})'
  If ($SnapshotID) {
    $SnapshotID = $Matches[1]
    Write-Dbg "SnapshotID: $SnapshotID"
    Write-Log "Snapshot $SnapshotID created"
  } Else {
    Write-Dbg "Unable to determine SnapshotID"
    Exit-Script "Unable to determine SnapshotID"
  }

  Return $SnapshotID
}

Function Mount-Snapshot ($SnapshotID) {
  Write-Log "Mounting snapshot..."
  Write-Dbg "Mounting $SnapshotID at ""$Target"""

  $Cmd = "$vshadowExePath `"-el=$SnapshotId,$Target`"" #Must use escaped quotes because Invoke-Expression gets all weird about curly braces
  $CmdResult = Run-Command $Cmd

  Write-Log "Snapshot $SnapshotID mounted at target ""$Target"""
  Write-Dbg "$SnapshotID mounted at ""$Target"""
}

Function Delete-Snapshot {
  Write-Log "Deleting snapshot..."
  Write-Dbg "Deleting snapshot at target ""$Target"""

  $SnapshotID = Get-SnapshotIdbyTarget

  $Cmd = "$vshadowExePath `"-ds=$SnapshotId`""
  $CmdResult = Run-Command $Cmd

  Write-Log "Snapshot $SnapshotID deleted at target ""$Target"""
  Write-Dbg "$SnapshotID deleted at ""$Target"""
}

Function Get-SnapshotIdbyTarget {
  Write-Dbg "Finding SnapshotID for $Target"

  $Cmd = "$vshadowExePath -q"
  $CmdResult = Run-Command $Cmd -AsString

  $TargetRegEx = '(?i)' + $Target.Replace('\','\\') + '\\?\r'
  $Snapshots = ($CmdResult.Split('*')) -Match $TargetRegEx | Out-String

  If ($Snapshots) {
    $Null = $Snapshots -Match '(\{[^}]{36}\})'
    $SnapshotID = $Matches[0]
  } Else {
    Write-Dbg "Unable to determine SnapshotID for target $Target"
    Exit-Script "Unable to determine SnapshotID"
  }  

  Write-Dbg "SnapshotID: $SnapshotID"

  Return $SnapshotID
}

Function Run-Command ([String]$Cmd, [Switch]$AsString=$False, [Switch]$AsArray=$False) {
  Write-Dbg "Running: $Cmd"

  $CmdOutputArray = Invoke-Expression $Cmd
  $CmdOutputString = $CmdOutputArray | Out-String
  $CmdErrorCode = $LASTEXITCODE

  If ($CmdErrorCode -eq 0 ) {
    Write-Dbg "Command successful. Exit code: $CmdErrorCode"
    Write-Dbg $CmdOutputString
  } Else {
    Write-Dbg "Command failed. Exit code: $CmdErrorCode"
    Write-Dbg $CmdOutputString
    Exit-Script "Command failed. Exit code: $CmdErrorCode"
  }

  If (!($AsString -or $AsArray)) {
    Return $CmdErrorCode
  } ElseIf ($AsString) {
    Return $CmdOutputString
  } ElseIf ($AsArray) {
    Return $CmdOutputArray
  }
}

Function Write-Msg ([String]$Message) {
  If ($Message -ne "") {
    Write-Host $Message
  }
}

Function Write-Log ([String]$Message) {
  Write-Msg "[$(Get-Date -Format G)] $Message"
}

Function Write-Dbg ([String]$Message) {
  If ($Debug) {
    Write-Msg ("-" * 80)
    Write-Msg "[DEBUG] $Message"
    Write-Msg ("-" * 80)
  }
}

Function Exit-Script ([String]$Message) {
  If ($Message -ne "") {
    Write-Msg "`n[FATAL ERROR] $Message`n"
  }
  Exit 1
}

# Main
Write-Log "VssSnapshot started"
Check-Environment

Switch ($Action) {
  "Create" {
    Prepare-Target
    $SnapshotID = Create-Snapshot
    Mount-Snapshot $SnapshotID
  }
  "Delete" {
    Delete-Snapshot
  }
}

Write-Log "VssSnapshot finished"

这是要使用的vshadow.exe版本:

  1. Windows 2003 / 2003R2
    • 卷影复制服务SDK 7.2
    • x86:C:\ Program Files \ Microsoft \ VSSSDK72 \ TestApps \ vshadow \ bin \ release-server \ vshadow.exe
      • 重命名为:vshadow_2003_x86.exe
    • x64:我无法为Windows 2003 x64找到vshadow.exe的x64版本
  2. Windows 2008
    • Windows Server 2008和.NET Framework 3.5的Windows SDK
    • x86:C:\ Program Files \ Microsoft SDKs \ Windows \ v6.1 \ Bin \ vsstools \ vshadow.exe
      • 重命名为:vshadow_2008_x86.exe
    • x64:C:\ Program Files \ Microsoft SDKs \ Windows \ v6.1 \ Bin \ x64 \ vsstools \ vshadow.exe
      • 重命名为:vshadow_2008_x64.exe
  3. Windows 2008R2
    • 适用于Windows 7和.NET Framework 4的Microsoft Windows SDK
    • x86:C:\ Program Files(x86)\ Microsoft SDKs \ Windows \ v7.0A \ Bin \ vsstools \ vshadow.exe
      • 重命名为:vshadow_2008R2_x86.exe
    • x64:C:\ Program Files(x86)\ Microsoft SDKs \ Windows \ v7.0A \ Bin \ x64 \ vsstools \ vshadow.exe
      • 重命名为:vshadow_2008R2_x64.exe

2
顺便说一句...我能够将Arcserve用作穷人的打开文件备份,以此作为备份解决方案的一部分。这比为每台服务器支付800美元的代理许可证要好。如果有人感兴趣,我会在这里发布。
约翰·荷马

+1这真是太神奇了。感谢您抽出宝贵的时间将此内容移植到ps(尽管您对VBS感到讨厌)并在这里分享。我希望更多的人会发现它有用,因为这肯定值得不止一次投票。
Tomalak

9

所以……我一直在研究一个可以执行以下操作的VBScript:

  • 拍摄持久的VSS快照
  • 将它们安装到文件夹(然后可以从中备份文件)
  • 卸载VSS快照

它依赖于vshadow.exe文档),它是Microsoft提供的Volume Shadow Copy Service SDK 7.2的一部分。我一直在使用以下版本:“ VSHADOW.EXE 2.2-卷影复制示例客户端,版权所有(C)2005 Microsoft Corporation。

基本上,这是围绕这四个vshadow命令的简洁小包装:

vshadow.exe -q-列出系统中的所有卷影副本
vshadow.exe -p {卷列表}-管理持久卷影副本
vshadow.exe -el = {SnapID},dir-将卷影副本公开为安装点
vshadow.exe -ds = {SnapID}-删除此卷影副本

这是其帮助屏幕:

VSS快照创建/安装工具

用法:
cscript / nologo VssSnapshot.vbs / target:path {/ volume:X | / unmount} [/ debug]

/ volume-要快照的卷的驱动器号
/ target-将快照安装到的路径(绝对或相对)
/ debug-在调试输出上切换

例子:
cscript / nologo VssSnapshot.vbs / target:C:\ Backup \ DriveD / volume:D
cscript / nologo VssSnapshot.vbs / target:C:\ Backup \ DriveD / unmount

提示:在拍摄新快照之前无需卸载。

这里是一些示例输出:

C:\ VssSnapshot> cscript / nologo VssSnapshot.vbs / target:MountPoints \ E / volume:E
2010年5月3日17:13:04准备VSS安装点...
2010年5月3日17:13:04挂载点准备在:C:\ VssSnapshot \ MountPoints \ E
05/03/2010 17:13:04为卷E创建VSS快照
2010年5月3日17:13:08创建了ID为{4ed3a907-c66f-4b20-bda0-9dcda3b667ec}的快照
05/03/2010 17:13:08 VSS快照已成功安装
2010年5月3日17:13:08完成

C:\ VssSnapshot> cscript / nologo VssSnapshot.vbs / target:MountPoints \ E / unmount
2010年5月3日17:13:35准备VSS安装点...
05/03/2010 17:13:36没什么可做的
2010年5月3日17:13:36完成

这是脚本本身。通常免责声明适用:本软件按原样提供,我不作任何保证,如果有任何问题造成任何干扰,唯一的责任是您自己使用,风险自负。我已经对其进行了相当全面的测试,并且对我来说效果很好。请通过以下评论随时将任何错误通知我。

''# VssSnapshot.vbs
''# http://serverfault.com/questions/119120/how-to-use-a-volume-shadow-copy-to-make-backups/119592#119592
Option Explicit

Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")

''# -- MAIN SCRIPT -------------------------------------------
Dim args, snapshotId, targetPath, success
Set args = WScript.Arguments.Named
CheckEnvironment

Log "preparing VSS mount point..."
targetPath = PrepareVssMountPoint(args("target"))

If args.Exists("unmount") Then
  Log "nothing else to do"
ElseIf targetPath <> vbEmpty Then
  Log "mount point prepared at: " & targetPath
  Log "creating VSS snapshot for volume: " & args("volume")
  snapshotId = CreateVssSnapshot(args("volume"))

  If snapshotId <> vbEmpty Then
    Log "snapshot created with ID: " & snapshotId
    success = MountVssSnapshot(snapshotId, targetPath)
    If success Then
      Log "VSS snapshot mounted sucessfully"
    Else
      Die "failed to mount snapshot"
    End If
  Else
    Die "failed to create snapshot"
  End If
Else
  Die "failed to prepare mount point"
End If

Log "finished"

''# -- FUNCTIONS ---------------------------------------------
Function PrepareVssMountPoint(target) ''# As String
  Dim cmd, result, outArray
  Dim path, snapshot, snapshotId
  Dim re, matches, match

  PrepareVssMountPoint = VbEmpty
  target = fso.GetAbsolutePathName(target)

  If Not fso.FolderExists(fso.GetParentFolderName(target)) Then 
    Die "Invalid mount point: " & target
  End If

  ''# create or unmount (=delete existing snapshot) mountpoint
  If Not fso.FolderExists(target) Then
    If Not args.Exists("unmount") Then fso.CreateFolder target
  Else
    Set re = New RegExp
    re.MultiLine = False
    re.Pattern = "- Exposed locally as: ([^\r\n]*)"

    cmd = "vshadow -q"
    result = RunCommand(cmd, false)
    outarray = Split(result, "*")

    For Each snapshot In outArray
      snapshotId = ParseSnapshotId(snapshot)
      If snapshotId <> vbEmpty Then
        Set matches = re.Execute(snapshot)
        If matches.Count = 1 Then
          path = Trim(matches(0).SubMatches(0))
          If fso.GetAbsolutePathName(path) = target Then
            cmd = "vshadow -ds=" & snapshotId
            RunCommand cmd, true
            Exit For
          End If
        End If
      End If
    Next

    If args.Exists("unmount") Then fso.DeleteFolder target
  End If

  PrepareVssMountPoint = target
End Function

Function CreateVssSnapshot(volume) ''# As String
  Dim cmd, result

  If Not fso.DriveExists(volume) Then
    Die "Drive " & volume & " does not exist."
  End If

  cmd = "vshadow -p " & Replace(UCase(volume), ":", "") & ":"
  result = RunCommand(cmd, false)
  CreateVssSnapshot = ParseSnapshotId(result)
End Function

Function MountVssSnapshot(snapshotId, target) ''# As Boolean
  Dim cmd, result

  If fso.FolderExists(targetPath) Then
    cmd = "vshadow -el=" & snapshotId & "," & targetPath
    result = RunCommand(cmd, true)
  Else
    Die "Mountpoint does not exist: " & target
  End If

  MountVssSnapshot = (result = "0")
End Function

Function ParseSnapshotId(output) ''# As String
  Dim re, matches, match

  Set re = New RegExp
  re.Pattern = "SNAPSHOT ID = (\{[^}]{36}\})"
  Set matches = re.Execute(output)

  If matches.Count = 1 Then
    ParseSnapshotId = matches(0).SubMatches(0)
  Else
    ParseSnapshotId = vbEmpty
  End If
End Function

Function RunCommand(cmd, exitCodeOnly) ''# As String
  Dim shell, process, output

  Dbg "Running: " & cmd

  Set shell = CreateObject("WScript.Shell")

  On Error Resume Next
  Set process = Shell.Exec(cmd)
  If Err.Number <> 0 Then
    Die Hex(Err.Number) & " - " & Err.Description
  End If
  On Error GoTo 0

  Do While process.Status = 0
    WScript.Sleep 100
  Loop
  output = Process.StdOut.ReadAll

  If process.ExitCode = 0 Then 
    Dbg "OK"
    Dbg output
  Else
    Dbg "Failed with ERRORLEVEL " & process.ExitCode
    Dbg output
    If Not process.StdErr.AtEndOfStream Then 
      Dbg process.StdErr.ReadAll
    End If
  End If  

  If exitCodeOnly Then
    Runcommand = process.ExitCode
  Else
    RunCommand = output
  End If
End Function

Sub CheckEnvironment
  Dim argsOk

  If LCase(fso.GetFileName(WScript.FullName)) <> "cscript.exe" Then
    Say "Please execute me on the command line via cscript.exe!"
    Die ""
  End If

  argsOk = args.Exists("target")
  argsOk = argsOk And (args.Exists("volume") Or args.Exists("unmount"))

  If Not argsOk Then
    Say "VSS Snapshot Create/Mount Tool" & vbNewLine & _
        vbNewLine & _
        "Usage: " & vbNewLine & _
        "cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
          " /target:path { /volume:X | /unmount } [/debug]" & _
        vbNewLine & vbNewLine & _
        "/volume  - drive letter of the volume to snapshot" & _
        vbNewLine & _
        "/target  - the path (absolute or relative) to mount the snapshot to" & _
        vbNewLine & _
        "/debug   - swich on debug output" & _
        vbNewLine & vbNewLine & _
        "Examples: " & vbNewLine & _
        "cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
          " /target:C:\Backup\DriveD /volume:D" &  vbNewLine & _
        "cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
          " /target:C:\Backup\DriveD /unmount" & _
        vbNewLine & vbNewLine & _
        "Hint: No need to unmount before taking a new snapshot." & vbNewLine

    Die ""
  End If
End Sub

Sub Say(message)
  If message <> "" Then WScript.Echo message
End Sub

Sub Log(message)
  Say FormatDateTime(Now()) & " " & message
End Sub

Sub Dbg(message)
  If args.Exists("debug") Then 
    Say String(75, "-")
    Say "DEBUG: " & message
  End If
End Sub

Sub Die(message)
  If message <> "" Then Say "FATAL ERROR: " & message
  WScript.Quit 1
End Sub

我希望这对某人有帮助。随时根据cc-by-sa使用它。我要问的是,您保留指向此处的链接完整无缺。


您是否已将数据从此灾难恢复到新系统?进行备份很容易。从中恢复有时并不多。
罗伯·摩尔

@Robert:对于这种方法以及任何其他类型的备份,都是如此。我将通过分期进行跟进。
Tomalak 2010年

1
+1表示不接受“否”,并坚持不懈地证明存在可行的解决方案,其他一些发帖人可能会提供这种解决方案,而不是回答无法解决。
克里斯·马格努森

最终是否提供了可恢复的备份?它可以与Robocopy一起使用吗?
凯夫

1
@Kev:是的,但是您必须自己进行测试。如果您发现问题,请在这里告诉我。您可以使用Robocopy或您喜欢的任何其他工具,挂载的卷的行为类似于普通驱动器。
Tomalak 2010年

6
  1. 使用命令vssadmin list shadows列出所有可用的卷影副本。您将得到这样的输出...
C:\> vssadmin列出阴影
vssadmin 1.1-卷影复制服务管理命令行工具
(C)版权所有2001 Microsoft Corp.

卷影副本集ID的内容:{b6f6fb45-bedd-4b77-8f51-14292ee921f3}
   在创建时包含1个卷影副本:2016/9/25下午12:14:23
      卷影副本ID:{321930d4-0442-4cc6-b2aa-ec47f21d0eb1}
         原始音量:(C:)\\?\音量{ad1dd231-1200-11de-b1df-806e6f6e6963} \
         卷影副本卷:\\?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy68
         原始机器:joshweb.josh.com
         服务机:joshweb.josh.com
         提供程序:“ Microsoft软件卷影复制提供程序1.0”
         类型:ClientAccessible
         属性:持久,可访问客户端,无自动发布,无编写器,差异

卷影副本集ID的内容:{c4fd8646-57b3-4b39-be75-47dc8e7f881d}
   在创建时间包含1个卷影副本:2016年8月25日7:00:18
      卷影副本ID:{fa5da100-5d90-493c-89b1-5c27874a23c6}
         原始卷:(E:)\\?\卷{4ec17949-12b6-11de-8872-00235428b661} \
         卷影副本卷:\\?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy3
         原始机器:joshweb.josh.com
         服务机:joshweb.josh.com
         提供程序:“ Microsoft软件卷影复制提供程序1.0”
         类型:ClientAccessible
         属性:持久,可访问客户端,无自动发布,无编写器,差异

C:\
  1. 记下Shadow Copy Volume所需的卷影副本的名称(最容易到剪贴板)。

  2. 装载卷影副本

在Windows 2003上...

如果您还没有2003版资源工具包工具,则需要下载它。

输入命令...

链接的c:\ shadow \\?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy69 \

...其中c:\shadow是您希望卷影副本出现的路径,也是您在\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy69上方复制的名称。请注意,必须在卷影副本名称的末尾添加反斜杠!

在Windows 2008及更高版本上...

输入命令...

mklink c:\ shadow \\?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy69 \

...其中c:\shadow是您希望卷影副本出现的路径,也是您在\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy69上方复制的名称。请注意,必须在卷影副本名称的末尾添加反斜杠!

  1. 使用所需的任何工具(包括Windows资源管理器或XCOPY)从中访问文件c:\shadow

因此...要使其自动化,您需要解析来自的输出list shadows
凯夫

我喜欢这个答案,但是在安装\\?\ GLOBALROOT \ Device \ HarddiskVolumeShadowCopy_n_时,它对我来说不是很有效,而是我使用了来自根共享(例如C $)的引用文件和快照时间mklink / DD:\ TempMount \\ localhost \ C $ \ @ GMT-2011.01.01-06.00.08-不幸的是,这可能是手动操作,但对于紧急情况,它可以工作。
刘易斯

2

您误会了VSS如何与文件系统一起使用(它与数据库一起使用的方式完全不同)。在文件系统上,VSS用于实现“先前版本”功能,该功能仅用于在预定义的时间点对文件和文件夹的更改进行快照,以通过客户端中的“先前版本”选项卡进行恢复。然后,将这些更改与卷上的数据合并以构建恢复集。因此,它取决于仍然存在的原始卷才能执行恢复,换句话说,这对于正确的备份和还原是无用的。

我认为您需要退后一步,然后再考虑要做什么。

350 GB的数据确实不是很多,我敢打赌,每天被主动使用的数据所占的百分比非常低。您是否考虑过仅在周末使用完整备份进行每晚差异备份?还是使用计划的DFS复制到备用存储以获取“快照”(然后备份)?


就差异备份而言,每天的更改量约为60GB。定期的服务中断时间足够长,偶尔会惹恼用户,也许“小时数”有些夸张。我的观点是-当我将VSS快照备份到磁带时,便拥有了成功还原数据所需的一切。我正在编写一个脚本,该脚本可以满足当前的需求,看起来很有希望。完成后我会在这里发布。
Tomalak

@mh:我已经发布了我的脚本。它已经变得比我预期的要大一些,但是它运作良好并且使用方便。看一看!:)
Tomalak 2010年

1
-1您误解了这个问题。他没有尝试使用VSS作为备份源,而是试图使用VSS创建其文件的只读时间点快照,然后可以将其传输到磁带驱动器或其他某种介质。我不明白为什么这不是该技术的好用例?
克里斯·马格努森

2

希望这是您想要的:

diskshadow -s vssbackup.cfg

vssbackup.cfg:

set context persistent
set metadata E:\backup\result.cab
set verbose on
begin backup
     add volume C: alias ConfigVolume
     create
     EXPOSE %ConfigVolume% Y:
     # Y is your VSS drive
     # run your backup script here
     delete shadows exposed Y:
end backup

diskshadow是Windows Server 2008,AFAIK。
Tomalak 2010年

@jackbean:我创建了一个与Windows 2003类似的脚本,因为到目前为止,我在Internet上没有令人信服的内容。看看我的答案。
Tomalak 2010年

抱歉,我知道这是针对2008年的,但不知何故,我有2008 R2。
jackbean

0

使用VSS API,可以对卷进行“快照”。然后,您必须挂载该快照才能从中复制快照。我熟悉一个已经过时的产品,尽管文件是由实时文件系统中的其他进程专门打开的,但该产品仍使用此技术来复制数据。如果VSS快照中的文件是由未与VSS API集成的应用程序编写的,则可能引发有效问题。可能还有其他提供类似功能的产品。


@Fred:那就是我使用VBScript和Microsoft命令行工具所做的。看我的答案。
Tomalak 2010年

-1

简短的回答:不能。

稍长的答案:卷影复制服务可以通过其API以编程方式使用,以允许备份打开的文件,但是该服务不能创建系统的完整快照,而只能创建部分快照。


2
我拒绝相信这是不可能的。我不需要完整的“系统快照”,只需一个卷的时间点副本。我大致知道卷影复制在内部如何工作,并且我知道它可以用于对使用中的文件进行备份(网络上的突出示例是Exchange或SQL数据库)。
Tomalak 2010年

1
@约翰:事实证明我可以。看看我的答案!
Tomalak 2010年

我发现您使用的API与备份软件非常相似。因此,当您使用VSS服务时,它与使用卷影复制完全不同。但是,如果它满足您的要求,那么这才是真正重要的。做得好。
约翰·加迪尼尔

1
您的简短回答和长期回答都是错误的,即使“卷影复制”一词即使有点含糊不清,也足以表明用户正在寻找什么。zh.wikipedia.org/wiki/Shadow_Copy
克里斯·马格努森

1
也许是你的权利。我不明白当OP找到一种可以执行他所描述的方法时,您的回答“您不能”是正确的。您的长答案与所问的问题无关,因为即使api仅允许“部分快照”,您仍然可以在某个时间点装入整个卷的表示形式,并根据需要备份它。如果您能澄清您在原始帖子中的意思,以便对其进行编辑以解决OP能够完成的工作,那么我将很乐意删除不赞成票,并在信息相关的情况下增加赞成。
克里斯·马格努森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.