diff --git a/Databases/VSSTester/DiskShadow/Invoke-CreateDiskShadowFile.ps1 b/Databases/VSSTester/DiskShadow/Invoke-CreateDiskShadowFile.ps1 index 57a67598e1..5f1ccb5b4c 100644 --- a/Databases/VSSTester/DiskShadow/Invoke-CreateDiskShadowFile.ps1 +++ b/Databases/VSSTester/DiskShadow/Invoke-CreateDiskShadowFile.ps1 @@ -2,32 +2,30 @@ # Licensed under the MIT License. function Invoke-CreateDiskShadowFile { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWMICmdlet', '', Justification = 'Required to get drives on old systems')] [OutputType([string[]])] param( [Parameter(Mandatory = $true)] [string] $OutputPath, - [Parameter(Mandatory = $true)] [string] $ServerName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = "BackupByDatabase")] [object[]] $Databases, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = "BackupByDatabase")] [object] $DatabaseToBackup, - [Parameter(Mandatory = $true)] - [string] - $DatabaseDriveLetter, + [Parameter(Mandatory = $true, ParameterSetName = "BackupByVolume")] + [object[]] + $VolumesToBackup, [Parameter(Mandatory = $true)] - [string] - $LogDriveLetter + [string[]] + $DriveLetters ) function Out-DHSFile { @@ -74,171 +72,124 @@ function Invoke-CreateDiskShadowFile { Out-DHSFile "writer exclude {a65faa63-5ea8-4ebc-9dbd-a0c4db26912a}" Out-DHSFile " " - # add databases to exclude - # ------------------------ - foreach ($db in $Databases) { - if ($db.Identity -ne $DatabaseToBackup.Identity) { - if ($db.Server.Name -eq $ServerName) { - Out-DHSFile "writer exclude `"Microsoft Exchange Writer:\Microsoft Exchange Server\Microsoft Information Store\$serverName\$($db.Guid)`"" - } else { - #if passive copy, add it with replica in the string - Out-DHSFile "writer exclude `"Microsoft Exchange Replica Writer:\Microsoft Exchange Server\Microsoft Information Store\Replica\$serverName\$($db.Guid)`"" + if ($DatabaseToBackup) { + # add databases to exclude + # ------------------------ + foreach ($db in $Databases) { + if ($db.Identity -ne $DatabaseToBackup.Identity) { + if ($db.Server.Name -eq $ServerName) { + Out-DHSFile "writer exclude `"Microsoft Exchange Writer:\Microsoft Exchange Server\Microsoft Information Store\$serverName\$($db.Guid)`"" + } else { + #if passive copy, add it with replica in the string + Out-DHSFile "writer exclude `"Microsoft Exchange Replica Writer:\Microsoft Exchange Server\Microsoft Information Store\Replica\$serverName\$($db.Guid)`"" + } } } } + Out-DHSFile " " Out-DHSFile "Begin backup" - # add the volumes for the included database - # ----------------------------------------- - #gets a list of mount points on local server - $mpVolumes = Get-WmiObject -Query "select name, DeviceId from win32_volume where DriveType=3 AND DriveLetter=NULL" - $deviceIDs = @() - - $dbMP = $false - $logMP = $false - - #if no MountPoints ($mpVolumes) causes null-valued error, need to handle - if ($null -ne $mpVolumes) { - foreach ($mp in $mpVolumes) { - $mpName = (($mp.name).substring(0, $mp.name.length - 1)) - #if following mount point path exists in database path use deviceID in DiskShadow config file - if ($DatabaseToBackup.EdbFilePath.PathName.StartsWith($mpName, [System.StringComparison]::OrdinalIgnoreCase)) { - Write-Host " Mount point: $($mp.name) in use for database path: " - #Write-host "Yes. I am a database in MountPoint" - Write-Host " The selected database path is: $($DatabaseToBackup.EdbFilePath.PathName)" - $dbEdbVol = $mp.DeviceId - Write-Host " adding deviceID to file: $dbEdbVol" - - #add device ID to array - $deviceID1 = $mp.DeviceID - $dbMP = $true + if ($DatabaseToBackup) { + # add the volumes for the included database + # ----------------------------------------- + #gets a list of mount points on local server + $mpVolumes = Get-CimInstance -Query "select name, DeviceId from win32_volume where DriveType=3 AND DriveLetter=NULL" + $deviceIDs = @() + + $dbMP = $false + $logMP = $false + + #if no MountPoints ($mpVolumes) causes null-valued error, need to handle + if ($null -ne $mpVolumes) { + foreach ($mp in $mpVolumes) { + $mpName = (($mp.name).substring(0, $mp.name.length - 1)) + #if following mount point path exists in database path use deviceID in DiskShadow config file + if ($DatabaseToBackup.EdbFilePath.PathName.StartsWith($mpName, [System.StringComparison]::OrdinalIgnoreCase)) { + Write-Host " Mount point: $($mp.name) in use for database path: " + Write-Host " The selected database path is: $($DatabaseToBackup.EdbFilePath.PathName)" + $dbEdbVol = $mp.DeviceId + Write-Host " adding deviceID to file: $dbEdbVol" + + #add device ID to array + $deviceID1 = $mp.DeviceID + $dbMP = $true + } + + #if following mount point path exists in log path use deviceID in DiskShadow config file + if ($DatabaseToBackup.LogFolderPath.PathName.ToLower().Contains($mpName.ToLower())) { + Write-Host + Write-Host " Mount point: $($mp.name) in use for log path: " + Write-Host " The log folder path of selected database is: $($DatabaseToBackup.LogFolderPath.PathName)" + $dbLogVol = $mp.DeviceId + Write-Host " adding deviceID to file: $dbLogVol" + $deviceID2 = $mp.DeviceID + $logMP = $true + } } + } - #if following mount point path exists in log path use deviceID in DiskShadow config file - if ($DatabaseToBackup.LogFolderPath.PathName.ToLower().Contains($mpName.ToLower())) { - Write-Host - Write-Host " Mount point: $($mp.name) in use for log path: " - #Write-host "Yes. My logs are in a MountPoint" - Write-Host " The log folder path of selected database is: $($DatabaseToBackup.LogFolderPath.PathName)" - $dbLogVol = $mp.DeviceId - Write-Host " adding deviceID to file: $dbLogVol" - $deviceID2 = $mp.DeviceID - $logMP = $true - } + if ($dbMP -eq $false) { + $dbEdbVol = ($DatabaseToBackup.EdbFilePath.PathName).substring(0, 2) + Write-Host " The selected database path is '$($DatabaseToBackup.EdbFilePath.PathName)' so adding volume $dbEdbVol to backup scope" + $deviceID1 = $dbEdbVol } - $deviceIDs = $deviceID1, $deviceID2 - } - if ($dbMP -eq $false) { - $dbEdbVol = ($DatabaseToBackup.EdbFilePath.PathName).substring(0, 2) - Write-Host " The selected database path is '$($DatabaseToBackup.EdbFilePath.PathName)' so adding volume $dbEdbVol to backup scope" - $deviceID1 = $dbEdbVol - } + if ($logMP -eq $false) { + $dbLogVol = ($DatabaseToBackup.LogFolderPath.PathName).substring(0, 2) + Write-Host " The selected database log folder path is '$($DatabaseToBackup.LogFolderPath.PathName)' so adding volume $dbLogVol to backup scope" + $deviceID2 = $dbLogVol + } - if ($logMP -eq $false) { - $dbLogVol = ($DatabaseToBackup.LogFolderPath.PathName).substring(0, 2) - Write-Host " The selected database log folder path is '$($DatabaseToBackup.LogFolderPath.PathName)' so adding volume $dbLogVol to backup scope" - $deviceID2 = $dbLogVol + $deviceIDs = @($deviceID1) + if ($deviceID2 -ne $deviceID1) { + $deviceIDs += $deviceID2 + } + } else { + $validVolumes = Get-CimInstance -Query "select name, DeviceId from win32_volume where DriveType=3" | + Where-Object { $_.Name -match "^\w:" } | Select-Object Name, DeviceID + $deviceIDs = @() + foreach ($v in $VolumesToBackup) { + $volToBackup = $validVolumes | Where-Object { $_.Name -eq $v } + if ($null -eq $volToBackup) { + Write-Warning "Failed to find volume by name: $v. Available volumes:`n$([string]::Join("`n", $validVolumes))" + exit + } + + $deviceIDs += $volToBackup.DeviceID + } } # Here is where we start adding the appropriate volumes or MountPoints to the DiskShadow config file # We make sure that we add only one Logical volume when we detect the EDB and log files # are on the same volume - Write-Host - $deviceIDs = $deviceID1, $deviceID2 - $comp = [string]::Compare($deviceID1, $deviceID2, $True) - if ($comp -eq 0) { - $dID = $deviceIDs[0] - Write-Debug -Message ('$dID = ' + $dID.ToString()) - Write-Debug "When the database and log files are on the same volume, we add the volume only once" - if ($dID.length -gt "2") { - $addVol = "add volume $dID alias vss_test_" + ($dID).ToString().substring(11, 8) - Write-Host $addVol - Out-DHSFile $addVol - } else { - $addVol = "add volume $dID alias vss_test_" + ($dID).ToString().substring(0, 1) - Write-Host $addVol - Out-DHSFile $addVol - } - } else { - Write-Host " " - foreach ($device in $deviceIDs) { - if ($device.length -gt "2") { - Write-Host " Adding the Mount Point for DSH file" - $addVol = "add volume $device alias vss_test_" + ($device).ToString().substring(11, 8) - Write-Host " $addVol" - Out-DHSFile $addVol - } else { - Write-Host " Adding the volume for DSH file" - $addVol = "add volume $device alias vss_test_" + ($device).ToString().substring(0, 1) - Write-Host " $addVol" - Out-DHSFile $addVol - } - } + for ($i = 0; $i -lt $deviceIDs.Count; $i++) { + $id = $deviceIDs[$i] + Write-Debug -Message ('$id = ' + $id.ToString()) + $addVol = "add volume $id alias vss_test_$i" + Write-Host $addVol + Out-DHSFile $addVol } + Out-DHSFile "create" Out-DHSFile " " Write-Host "$(Get-Date) Getting drive letters for exposing backup snapshot" - # check to see if the drives are the same for both database and logs - # if the same volume is used, only one drive letter is needed for exposure - # if two volumes are used, two drive letters are needed - - $matchCondition = "^[a-z]:$" - Write-Debug $matchCondition - - $dbSnapVol = $DatabaseDriveLetter - if ($comp -eq 0) { - $logSnapVol = $dbSnapVol - Write-Host " Since the same volume is used for this database's EDB and logs, we only need a single drive" - Write-Host " letter to expose the backup snapshot." - } else { - $logSnapVol = $LogDriveLetter - Write-Host " Since different volumes are used for this database's EDB and logs, we need two drive" - Write-Host " letters to expose the backup snapshot." - } - - Write-Debug "dbSnapVol: $dbSnapVol | logSnapVol: $logSnapVol" - # expose the drives - # if volumes are the same only one entry is needed - if ($dbEdbVol -eq $dbLogVol) { - if ($dbEdbVol.length -gt "2") { - $dbVolStr = "expose %vss_test_" + ($dbEdbVol).substring(11, 8) + "% $($dbSnapVol):" - Out-DHSFile $dbVolStr - } else { - $dbVolStr = "expose %vss_test_" + ($dbEdbVol).substring(0, 1) + "% $($dbSnapVol):" - Out-DHSFile $dbVolStr - } - } else { - # volumes are different, getting both - # if MountPoint use first part of string, if not use first letter - if ($dbEdbVol.length -gt "2") { - $dbVolStr = "expose %vss_test_" + ($dbEdbVol).substring(11, 8) + "% $($dbSnapVol)" - Out-DHSFile $dbVolStr - } else { - $dbVolStr = "expose %vss_test_" + ($dbEdbVol).substring(0, 1) + "% $($dbSnapVol)" - Out-DHSFile $dbVolStr - } + if ($deviceIDs.Count -lt $DriveLetters.Count) { + Write-Warning "Determined that we need $($deviceIDs.Count) drive letters to expose the snapshots, but only $($DriveLetters.Count) were provided. Exiting." + exit + } - # if MountPoint use first part of string, if not use first letter - if ($dbLogVol.length -gt "2") { - $logVolStr = "expose %vss_test_" + ($dbLogVol).substring(11, 8) + "% $($logSnapVol):" - Out-DHSFile $logVolStr - } else { - $logVolStr = "expose %vss_test_" + ($dbLogVol).substring(0, 1) + "% $($logSnapVol):" - Out-DHSFile $logVolStr - } + for ($i = 0; $i -lt $deviceIDs.Count; $i++) { + $dbVolStr = "expose %vss_test_$($i)% $($DriveLetters[$i]):" + Out-DHSFile $dbVolStr } # ending data of file Out-DHSFile "end backup" - if ($dbSnapVol -eq $logSnapVol) { - return @($dbSnapVol) - } else { - return @($dbSnapVol, $logSnapVol) - } + # return the drive letters we used + return $DriveLetters | Select-Object -First ($deviceIDs.Count) } diff --git a/Databases/VSSTester/DiskShadow/Invoke-DiskShadow.ps1 b/Databases/VSSTester/DiskShadow/Invoke-DiskShadow.ps1 index 32844758e8..a121d9fb4e 100644 --- a/Databases/VSSTester/DiskShadow/Invoke-DiskShadow.ps1 +++ b/Databases/VSSTester/DiskShadow/Invoke-DiskShadow.ps1 @@ -8,14 +8,10 @@ function Invoke-DiskShadow { param( [Parameter(Mandatory = $true)] [string] - $OutputPath, - - [Parameter(Mandatory = $true)] - [object] - $DatabaseToBackup + $OutputPath ) - Write-Host "$(Get-Date) Starting DiskShadow copy of Exchange database: $Database" + Write-Host "$(Get-Date) Starting DiskShadow copy." Write-Host " Running the following command:" Write-Host " `"C:\Windows\System32\DiskShadow.exe /s $OutputPath\DiskShadow.dsh /l $OutputPath\DiskShadow.log`"" diff --git a/Databases/VSSTester/Logging/Invoke-DisableExtraTracing.ps1 b/Databases/VSSTester/Logging/Invoke-DisableExtraTracing.ps1 index 05f9428764..a183c1ef1b 100644 --- a/Databases/VSSTester/Logging/Invoke-DisableExtraTracing.ps1 +++ b/Databases/VSSTester/Logging/Invoke-DisableExtraTracing.ps1 @@ -15,7 +15,7 @@ function Invoke-DisableExTRATracing { [string] $ServerName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [object] $DatabaseToBackup, @@ -24,9 +24,8 @@ function Invoke-DisableExTRATracing { $OutputPath ) Write-Host "$(Get-Date) Disabling ExTRA Tracing..." - $dbMountedOn = $DatabaseToBackup.Server.Name - if ($dbMountedOn -eq "$ServerName") { - #stop active copy + $traceLocalServerOnly = $null -eq $DatabaseToBackup -or $DatabaseToBackup.Server.Name -eq $ServerName + if ($traceLocalServerOnly) { Write-Host Write-Host " Stopping Exchange Trace data collector on $ServerName..." logman stop vssTester -s $ServerName @@ -35,6 +34,7 @@ function Invoke-DisableExTRATracing { Write-Host } else { #stop passive copy + $dbMountedOn = $DatabaseToBackup.Server.Name Write-Host " Stopping Exchange Trace data collector on $ServerName..." logman stop vssTester-Passive -s $ServerName Write-Host " Deleting Exchange Trace data collector on $ServerName..." diff --git a/Databases/VSSTester/Logging/Invoke-EnableExtraTracing.ps1 b/Databases/VSSTester/Logging/Invoke-EnableExtraTracing.ps1 index 7c51a55ddf..3c3b366b3f 100644 --- a/Databases/VSSTester/Logging/Invoke-EnableExtraTracing.ps1 +++ b/Databases/VSSTester/Logging/Invoke-EnableExtraTracing.ps1 @@ -8,7 +8,7 @@ function Invoke-EnableExTRATracing { [string] $ServerName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [object] $DatabaseToBackup, @@ -53,10 +53,9 @@ function Invoke-EnableExTRATracing { } } - $dbMountedOn = $DatabaseToBackup.Server.Name + $traceLocalServerOnly = $null -eq $DatabaseToBackup -or $DatabaseToBackup.Server.Name -eq $ServerName - #active server, only get tracing from active node - if ($dbMountedOn -eq $ServerName) { + if ($traceLocalServerOnly) { Write-Host "Creating Exchange Trace data collector set..." Invoke-ExtraTracingCreate -ComputerName $ServerName -LogmanName "VSSTester" -OutputPath $OutputPath Write-Host "Starting Exchange Trace data collector..." @@ -70,6 +69,7 @@ function Invoke-EnableExTRATracing { Write-Host } else { #passive server, get tracing from both active and passive nodes + $dbMountedOn = $DatabaseToBackup.Server.Name Write-Host "Copying the ExTRA config file 'EnabledTraces.config' file to $dbMountedOn..." #copy EnabledTraces.config from current passive copy to active copy server Copy-Item "c:\EnabledTraces.Config" "\\$dbMountedOn\c$\EnabledTraces.config" -Force diff --git a/Databases/VSSTester/VSSTester.ps1 b/Databases/VSSTester/VSSTester.ps1 index cd746f1cd8..ded23979ba 100644 --- a/Databases/VSSTester/VSSTester.ps1 +++ b/Databases/VSSTester/VSSTester.ps1 @@ -13,7 +13,7 @@ Enables tracing of the specified database. The user may then attempt a backup of that database and use Ctrl-C to stop data collection after the backup attempt completes. .EXAMPLE - .\VSSTester -DiskShadow -DatabaseName "Mailbox Database 1637196748" -DatabaseDriveLetter M -LogDriveLetter N + .\VSSTester -DiskShadow -DatabaseName "Mailbox Database 1637196748" -ExposeSnapshotsOnDriveLetters M, N Enables tracing and then uses DiskShadow to snapshot the specified database. If the database and logs are on the same drive, the snapshot is exposed as M: drive. If they are on separate drives, the snapshots are exposed as M: and N:. The user is prompted to stop data collection and should typically wait until @@ -32,7 +32,8 @@ param( $TraceOnly, # Enable tracing and perform a database snapshot with DiskShadow. - [Parameter(Mandatory = $true, ParameterSetName = "DiskShadow")] + [Parameter(Mandatory = $true, ParameterSetName = "DiskShadowByDatabase")] + [Parameter(Mandatory = $true, ParameterSetName = "DiskShadowByVolume")] [switch] $DiskShadow, @@ -41,36 +42,52 @@ param( [switch] $WaitForWriterFailure, - # Name of the database to focus tracing on. + # Name of the database to focus tracing on and/or snapshot. [Parameter(Mandatory = $true, ParameterSetName = "TraceOnly")] - [Parameter(Mandatory = $true, ParameterSetName = "DiskShadow")] + [Parameter(Mandatory = $true, ParameterSetName = "DiskShadowByDatabase")] [Parameter(Mandatory = $true, ParameterSetName = "WaitForWriterFailure")] [string] $DatabaseName, - # Drive letter on which to expose the database snapshot. - [Parameter(Mandatory = $true, ParameterSetName = "DiskShadow")] - [ValidateLength(1, 1)] - [string] - $DatabaseDriveLetter, + # Names of the volumes to snapshot. + [Parameter(Mandatory = $true, ParameterSetName = "DiskShadowByVolume")] + [ValidateCount(1, 2)] + [ValidateScript({ + $validVolumeNames = @((Get-CimInstance -Query "select name, DeviceId from win32_volume where DriveType=3" | + Where-Object { $_.Name -match "^\w:" }).Name) + if ($validVolumeNames -contains $_) { + $true + } else { + throw "Invalid volume specified. Please specify one of the following values:`n$([string]::Join("`n", $validVolumeNames))" + } + })] + [string[]] + $VolumesToBackup, - # Drive letter on which to expose the log snapshot. Only used when the log volume - # is different than the database volume. - [Parameter(Mandatory = $true, ParameterSetName = "DiskShadow")] + # Drive letters on which to expose the snapshots. + [Parameter(Mandatory = $true, ParameterSetName = "DiskShadowByDatabase")] + [Parameter(Mandatory = $true, ParameterSetName = "DiskShadowByVolume")] [ValidateLength(1, 1)] - [string] - $LogDriveLetter, + [ValidateCount(1, 2)] + [string[]] + $ExposeSnapshotsOnDriveLetters, # Path in which to put the collected traces. A subfolder named with the time of # the data collection is created in this path, and all files are put in that subfolder. # Defaults to the folder the script is in. [Parameter(Mandatory = $false, ParameterSetName = "TraceOnly")] - [Parameter(Mandatory = $false, ParameterSetName = "DiskShadow")] + [Parameter(Mandatory = $false, ParameterSetName = "DiskShadowByDatabase")] + [Parameter(Mandatory = $false, ParameterSetName = "DiskShadowByVolume")] [Parameter(Mandatory = $false, ParameterSetName = "WaitForWriterFailure")] [string] $LoggingPath = $PSScriptRoot ) +if ($VolumesToBackup -and ($VolumesToBackup.Count -ne $ExposeSnapshotsOnDriveLetters.Count)) { + Write-Host "The count of VolumesToBackup must match the count of ExposeSnapshotsOnDriveLetters." + exit +} + . $PSScriptRoot\..\..\Shared\ScriptUpdateFunctions\Get-ScriptUpdateAvailable.ps1 . $PSScriptRoot\..\..\Shared\Confirm-ExchangeShell.ps1 . .\DiskShadow\Invoke-CreateDiskShadowFile.ps1 @@ -130,32 +147,43 @@ try { Get-ExchangeVersion -ServerName $serverName Get-VSSWritersBefore -OutputPath $LoggingPath - $databases = Get-Databases -ServerName $serverName - $dbForBackup = $databases | Where-Object { $_.Name -eq $DatabaseName } - if ($null -eq $dbForBackup) { - Write-Warning "The specified database $DatabaseName does not exist on this server. Please enter a valid database name." - exit - } - Get-CopyStatus -ServerName $serverName -Database $dbForBackup -OutputPath $LoggingPath + if ($DatabaseName) { + $databases = Get-Databases -ServerName $serverName + $dbForBackup = $databases | Where-Object { $_.Name -eq $DatabaseName } + if ($null -eq $dbForBackup) { + Write-Warning "The specified database $DatabaseName does not exist on this server. Please enter a valid database name." + exit + } + + Get-CopyStatus -ServerName $serverName -Database $dbForBackup -OutputPath $LoggingPath + } if ($DiskShadow) { - $p = @{ - OutputPath = $LoggingPath - ServerName = $serverName - Databases = $databases - DatabaseToBackup = $dbForBackup - DatabaseDriveLetter = $DatabaseDriveLetter - LogDriveLetter = $LogDriveLetter + if ($DatabaseName) { + $p = @{ + OutputPath = $LoggingPath + ServerName = $serverName + Databases = $databases + DatabaseToBackup = $dbForBackup + DriveLetters = $ExposeSnapshotsOnDriveLetters + } + } else { + $p = @{ + OutputPath = $LoggingPath + ServerName = $serverName + VolumesToBackup = $VolumesToBackup + DriveLetters = $ExposeSnapshotsOnDriveLetters + } } - Write-Host "$p" + $p | Out-Host $exposedDrives = Invoke-CreateDiskShadowFile @p } Invoke-EnableDiagnosticsLogging Invoke-EnableVSSTracing -OutputPath $LoggingPath -Circular $WaitForWriterFailure Invoke-CreateExTRATracingConfig - Invoke-EnableExTRATracing -ServerName $serverName -Database $dbForBackup -OutputPath $LoggingPath -Circular $WaitForWriterFailure + Invoke-EnableExTRATracing -ServerName $serverName -DatabaseToBackup $dbForBackup -OutputPath $LoggingPath -Circular $WaitForWriterFailure $collectEventLogs = $false @@ -164,7 +192,7 @@ try { # Always collect event logs for this scenario $collectEventLogs = $true - Invoke-DiskShadow -OutputPath $LoggingPath -DatabaseToBackup $dbForBackup + Invoke-DiskShadow -OutputPath $LoggingPath Invoke-RemoveExposedDrives -OutputPath $LoggingPath -ExposedDrives $exposedDrives } elseif ($TraceOnly) { # Always collect event logs for this scenario diff --git a/docs/Databases/VSSTester.md b/docs/Databases/VSSTester.md index f2169b6fba..777a61041d 100644 --- a/docs/Databases/VSSTester.md +++ b/docs/Databases/VSSTester.md @@ -13,13 +13,21 @@ and use Ctrl-C to stop data collection after the backup attempt completes. ### Trace a snapshot using the DiskShadow tool -`.\VSSTester -DiskShadow -DatabaseName "Mailbox Database 1637196748" -DatabaseDriveLetter M -LogDriveLetter N` +`.\VSSTester -DiskShadow -DatabaseName "Mailbox Database 1637196748" -ExposeSnapshotsOnDriveLetters M, N` Enables tracing and then uses DiskShadow to snapshot the specified database. If the database and logs are on the same drive, the snapshot is exposed as M: drive. If they are on separate drives, the snapshots are exposed as M: and N:. The user is prompted to stop data collection and should typically wait until log truncation has occurred before doing so, so that the truncation is traced. +### Trace a snapshot using the DiskShadow tool by volume instead of by Database + +`.\VSSTester -DiskShadow -VolumesToBackup D:\, E:\ -ExposeSnapshotsOnDriveLetters M, N` + +Enables tracing and then uses DiskShadow to snapshot the specified volumes. To see a list of available +volumes, including mount points, pass an invalid volume name, such as `-VolumesToBackup foo`. The error +will show the available volumes. Volume names must be typed exactly as shown in that output. + ### Trace in circular mode until the Microsoft Exchange Writer fails `.\VSSTester -WaitForWriterFailure -DatabaseName "Mailbox Database 1637196748"`