如何使用卷影複製進行備份
計劃是創建一個相當大的、I/O 繁重的捲的捲影副本。它有 350GB,包含一個基於文件系統的全文索引,該索引組織在數百個文件夾和數十萬個需要處於一致狀態才能成功還原的小文件中。
目前索引器停止,備份任務執行,然后索引器重新啟動。這會導致索引在備份期間數小時不可用。我想通過卷影副本進行一致的備份,理想情況下根本不必停止索引器。
因此,我為該卷打開了卷影複製,並將其配置為每晚製作一次快照到不同的捲。
現在我有點不知所措 - 我怎樣才能訪問整個卷影副本,以便我可以進行備份?我設想一個只讀驅動器包含上次快照時的文件,但也許事情完全不同。
作業系統為 Windows Server 2003 SP2,備份軟體為 CommVault Galaxy 7.0。
編輯:請注意 - 同時 - 已經創建了兩個答案,它們以腳本的形式實現了必要的功能:
- VBScript(我自己)
- PowerShell(約翰·荷馬)
所以……我一直在研究一個小的 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 {volume list} - 管理持久的捲影副本 vshadow.exe -el={SnapID},dir - 將捲影副本公開為掛載點 vshadow.exe -ds={SnapID} - 刪除這個卷影副本
這是它的幫助螢幕:
VSS 快照創建/安裝工具 用法: cscript /nologo VssSnapshot.vbs /target:path { /volume:X | /解除安裝} [/調試] /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 05/03/2010 17:13:04 準備 VSS 掛載點... 05/03/2010 17:13:04 掛載點準備在:C:\VssSnapshot\MountPoints\E 05/03/2010 17:13:04 為卷創建 VSS 快照:E 2010 年 5 月 3 日 17:13:08 使用 ID 創建快照:{4ed3a907-c66f-4b20-bda0-9dcda3b667ec} 05/03/2010 17:13:08 VSS 快照掛載成功 05/03/2010 17:13:08 完成 C:\VssSnapshot>cscript /nologo VssSnapshot.vbs /target:MountPoints\E /unmount 05/03/2010 17:13:35 準備 VSS 掛載點... 05/03/2010 17:13:36 無事可做 05/03/2010 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使用它。我只要求您保留指向此處的連結完好無損。
因此,本著重新發明輪子的精神,我向您展示了 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 版本:
- 視窗 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 的 x64 版本的 vshadow.exe
- 視窗 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
- 視窗 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