A bit of black magic: How to assign drive letters to VSS shadow copies... on Windows XP !

A while back, I wrote a post on how to assign drive letters to shadow copies. On Windows Server 2003, the solution is simple, as there is already an API (called ExposeSnapshots()) to assign a drive letter to a shadow copy device. This API can be exercised through the "VSHADOW -el=..." command as well.

Unfortunately this solution doesn't work on Windows XP, simply because this ExposeSnapshots API is not implemented. Someone asked me whether this is possible on XP. Yes it is! However, you have to resort to some magic wizardry by using the less-known program DOSDEV.EXE (I wrote a detailed post about DOSDEV.EXE previously).

Let's create a shadow copy

In Windows XP, VSS assigns a hidden volume device to every shadow copy. The device looks like this: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1, and can be seen through the VSSADMIN LIST SHADOWS command whenever you have a shadow copy in the system.

However, most of the time, you don't have any shadow copies. Why? Shadow copies are volatile objects in XP, and they go away as soon as they are not needed anymore. They don't survive reboots either.

E:\>vssadmin list shadows
vssadmin 1.0 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001 Microsoft Corp.

No shadow copies present in the system.

However, this command returns normally no results on a regular XP system. How we can create a shadow copy? One simple way is to use NTBackup (which creates a shadow copy under the cover, as you might have noticed in the UI). Let's start NTBackup - while NTBackup is copying the files (but not after it finishes!) you can now see that we have some shadow copies:

E:\>vssadmin list shadows
vssadmin 1.0 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001 Microsoft Corp.

Contents of shadow copy set {81666ab2-39c3-4171-95de-c96b34d16e53}
 (The shadow copy set contained 4 shadow copies at creation time, 4 shadow copies exist now)
'MS Software Shadow Copy provider 1.0' shadow copy {db4c6c25-245b-411f-b7c3-ebfeaae9dd3b} on volume [\\?\Volume{baa1a457-cda5-11d9-b6b9-000129ff5ec6}\](file://\\?\Volume%7Bbaa1a457-cda5-11d9-b6b9-000129ff5ec6%7D\)
'MS Software Shadow Copy provider 1.0' shadow copy {72500904-066c-4995-a6bb-a80e08bfb9dd} on volume [\\?\Volume{60b38509-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b38509-f955-11d8-bdab-806d6172696f%7D\)
'MS Software Shadow Copy provider 1.0' shadow copy {2c9df462-ec28-4834-a91a-3edc0791c44f} on volume [\\?\Volume{60b3850a-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b3850a-f955-11d8-bdab-806d6172696f%7D\)
'MS Software Shadow Copy provider 1.0' shadow copy {77b09b45-df9e-407d-9a43-96d8fc19d0a0} on volume [\\?\Volume{60b3850b-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b3850b-f955-11d8-bdab-806d6172696f%7D\)

Well, that's not quite helpful - we know that we have some shadow copies, but we can't see the actual devices. However, we can see the devices by running, say "VSHADOW -q" which enumerates them directly through the VSS API:

E:\>vshadow -q

VSHADOW.EXE 2.0 - Volume Shadow Copy sample client
Copyright (C) 2004 Microsoft Corporation. All rights reserved.

(Option: Query all shadow copies)

Querying all shadow copies in the system ...

* SNAPSHOT ID = {db4c6c25-245b-411f-b7c3-ebfeaae9dd3b} ...
   - Shadow copy Set: {81666ab2-39c3-4171-95de-c96b34d16e53}
   - Original count of shadow copies = 4
   - Original Volume name: [\\?\Volume{baa1a457-cda5-11d9-b6b9-000129ff5ec6}\](file://\\?\Volume%7Bbaa1a457-cda5-11d9-b6b9-000129ff5ec6%7D\) [H:\]
   - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy4
   - Originating machine: (null)
   - Service machine: (null)
   - Not Exposed
   - Provider id: {b5946137-7b9f-4925-af80-51abd60b20d5}
   - Attributes:  Auto_Release

* SNAPSHOT ID = {72500904-066c-4995-a6bb-a80e08bfb9dd} ...
   - Shadow copy Set: {81666ab2-39c3-4171-95de-c96b34d16e53}
   - Original count of shadow copies = 4
   - Original Volume name: [\\?\Volume{60b38509-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b38509-f955-11d8-bdab-806d6172696f%7D\) [C:\]
   - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
   - Originating machine: (null)
   - Service machine: (null)
   - Not Exposed
   - Provider id: {b5946137-7b9f-4925-af80-51abd60b20d5}
   - Attributes:  Auto_Release

* SNAPSHOT ID = {2c9df462-ec28-4834-a91a-3edc0791c44f} ...
   - Shadow copy Set: {81666ab2-39c3-4171-95de-c96b34d16e53}
   - Original count of shadow copies = 4
   - Original Volume name: [\\?\Volume{60b3850a-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b3850a-f955-11d8-bdab-806d6172696f%7D\) [D:\]
   - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2
   - Originating machine: (null)
   - Service machine: (null)
   - Not Exposed
   - Provider id: {b5946137-7b9f-4925-af80-51abd60b20d5}
   - Attributes:  Auto_Release

* SNAPSHOT ID = {77b09b45-df9e-407d-9a43-96d8fc19d0a0} ...
   - Shadow copy Set: {81666ab2-39c3-4171-95de-c96b34d16e53}
   - Original count of shadow copies = 4
   - Original Volume name: [\\?\Volume{60b3850b-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b3850b-f955-11d8-bdab-806d6172696f%7D\) [E:\]
   - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3
   - Originating machine: (null)
   - Service machine: (null)
   - Not Exposed
   - Provider id: {b5946137-7b9f-4925-af80-51abd60b20d5}
   - Attributes:  Auto_Release

Now, while NTBackup is still running you can assign drive letters to these shadow copies using DOSDEV.EXE. Let's take for example the first shadow copy:

E:\>dosdev v: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy4
Current definition: v: = \??\GLOBALROOT\Device\HarddiskVolumeShadowCopy4

E:\>dir v:
 Volume in drive V is New Volume
 Volume Serial Number is B8AA-DD03

 Directory of V:\

06/21/2005  01:16 AM    <DIR>          ATI
11/16/2005  10:47 PM                 0 AUTOEXEC.BAT
12/19/2005  12:45 PM               329 boot.ini
11/16/2005  10:42 PM               211 boot_c.ini
06/21/2005  01:17 AM    <DIR>          Castle Infinity Download Data
11/16/2005  10:47 PM                 0 CONFIG.SYS
11/16/2005  10:51 PM    <DIR>          Documents and Settings
12/15/2005  11:56 PM    <DIR>          garbage
06/21/2005  01:53 AM    <DIR>          infinity
12/15/2005  09:08 PM    <DIR>          Kits
01/17/2006  11:44 PM    <DIR>          Program Files
06/19/2005  07:56 PM    <DIR>          Store
01/11/2006  07:52 PM    <DIR>          WINDOWS
               4 File(s)            540 bytes
               9 Dir(s)  70,541,107,200 bytes free

That's it!

 

How to create/access shadow copies in a script

OK - that was good enough to get us started, but this method is not appropriate in a scripting environment. What if we want to create shadow copies in a script, on XP?

We can use VSHADOW.EXE again. We need a few tricks again.

First - how do we specify the shadow copy device in a script? Well, VSHADOW can optionally save the definitions of some shadow copy properties in a generated CMD file. So, if we run the command "VSHADOW -script=vss-setvar.cmd C:" then we will have a generated vss-setvar.cmd file which contains the temporary shadow copy device:

E:\>type vss-setvar.cmd
@echo.
@echo [This script is generated by VSHADOW.EXE for the shadow set {e748cc90-8fe9-4e49-8caf-57db1dbcbeed}]
@echo.

SET SHADOW_SET_ID={e748cc90-8fe9-4e49-8caf-57db1dbcbeed}
SET SHADOW_ID_1={9882eb9b-fbda-4625-b8c5-4a545108456d}
SET SHADOW_DEVICE_1=\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1

Here, we conveniently have the shadow copy device saved in an environment variable.

The second trick is that, in XP, the only way to access shadow copies is during the execution of the program that creates them. So, if you run "VSHADOW C:" then you can see the snapshot device only while the VSHADOW.EXE process is still running. (similarly, if you run NTBackup, then you can only see its shadow copies during the lifetime of NTBackup.exe process)

How we get access to our shadow copy in this specific interval of time? Fortunately, we can execute this script during snapshot creation, with the other "-exec" option of VSHADOW. For example the command "VSHADOW -exec=MyScript.cmd C:" will execute the script MyScript.cmd while the shadow copy is still active. We can even use in this script the other generated CMD script containing the environment variables (complicated, isn't it?). Like this:

E:\>type vss-exec.cmd
call %~dp0\vss-setvar.cmd

:: Define temporary drive letter
dosdev X: %SHADOW_DEVICE_1%

:: Try to execute some commands on the snapshot device
fsutil fsinfo volumeinfo X:
dir x:\autoexec.bat

:: Delete temporary drive letter
dosdev -r -d X:

Here we complete the full circle - first, we read the definition from the vss-setvar.cmd command file, second we define a drive letter for the device, and finally we exercise the shadow copy, before deleting the drive letter definition.

We can execute the full thing through VSHADOW.EXE, naturally:

E:\>vshadow -script=vss-setvar.cmd -exec=vss-exec.cmd c:

VSHADOW.EXE 2.0 - Volume Shadow Copy sample client
Copyright (C) 2004 Microsoft Corporation. All rights reserved.

(Option: Generate SETVAR script 'vss-setvar.cmd')
(Option: Execute binary/script after shadow creation 'vss-exec.cmd')
(Option: Create shadow copy set)
(Gathering writer metadata...)
(Waiting for the asynchronous operation to finish...)
Initialize writer metadata ...
Discover directly excluded components ...
- Excluding writer 'MSDEWriter' since it has no selected components for restore.
Discover components that reside outside the shadow set ...
- Component '\Config Directory' from writer 'Microsoft Writer (Service State)' is excluded from backup (it requires E:\ in the shadow set)
- Component '\Event Logs' from writer 'Microsoft Writer (Service State)' is excluded from backup (it requires E:\ in the shadow set)
- Component '\COM+ Registration Database' from writer 'Microsoft Writer (Bootable State)' is excluded from backup (it requires E:\ in the shadow set)
- Component '\Registry' from writer 'Microsoft Writer (Bootable State)' is excluded from backup (it requires E:\ in the shadow set)
- Component '\WMI' from writer 'WMI Writer' is excluded from backup (it requires E:\ in the shadow set)
Discover all excluded components ...
Discover excluded writers ...
- The writer 'Microsoft Writer (Service State)' is now entirely excluded from the backup:
  (the top-level non-selectable component '\Config Directory' is an excluded component)
- The writer 'Microsoft Writer (Bootable State)' is now entirely excluded from the backup:
  (it does not contain any components that can be potentially included in the backup)
- The writer 'WMI Writer' is now entirely excluded from the backup:
  (it does not contain any components that can be potentially included in the backup)
Discover explicitly included components ...
Verifying explicitly specified writers/components ...
Select explicitly included components ...
Creating shadow set {e748cc90-8fe9-4e49-8caf-57db1dbcbeed} ...
- Adding volume [\\?\Volume{60b38509-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b38509-f955-11d8-bdab-806d6172696f%7D\) [C:\] to the shadow set...
Preparing for backup ...
(Waiting for the asynchronous operation to finish...)
(Waiting for the asynchronous operation to finish...)
Creating the shadow (DoSnapshotSet) ...
(Waiting for the asynchronous operation to finish...)
(Waiting for the asynchronous operation to finish...)
Shadow copy set succesfully created.

List of created shadow copies:

Querying all shadow copies with the SnapshotSetID {e748cc90-8fe9-4e49-8caf-57db1dbcbeed} ...

* SNAPSHOT ID = {9882eb9b-fbda-4625-b8c5-4a545108456d} ...
   - Shadow copy Set: {e748cc90-8fe9-4e49-8caf-57db1dbcbeed}
   - Original count of shadow copies = 1
   - Original Volume name: [\\?\Volume{60b38509-f955-11d8-bdab-806d6172696f}\](file://\\?\Volume%7B60b38509-f955-11d8-bdab-806d6172696f%7D\) [C:\]
   - Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
   - Originating machine: (null)
   - Service machine: (null)
   - Not Exposed
   - Provider id: {b5946137-7b9f-4925-af80-51abd60b20d5}
   - Attributes:  Auto_Release

Generating the SETVAR script (vss-setvar.cmd) ...
Executing command 'vss-exec.cmd' ...
-----------------------------------------------------

E:\>call E:\\vss-setvar.cmd

[This script is generated by VSHADOW.EXE for the shadow set {e748cc90-8fe9-4e49-8caf-57db1dbcbeed}]

E:\>SET SHADOW_SET_ID={e748cc90-8fe9-4e49-8caf-57db1dbcbeed}

E:\>SET SHADOW_ID_1={9882eb9b-fbda-4625-b8c5-4a545108456d}

E:\>SET SHADOW_DEVICE_1=\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1

E:\>dosdev X: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
Current definition: X: = \??\GLOBALROOT\Device\HarddiskVolumeShadowCopy1

E:\>fsutil fsinfo volumeinfo X:
Volume Name :
Volume Serial Number : 0xfccde1d0
Max Component Length : 255
File System Name : NTFS
Supports Case-sensitive filenames
Preserves Case of filenames
Supports Unicode in filenames
Preserves & Enforces ACL's
Supports file-based Compression
Supports Disk Quotas
Supports Sparse files
Supports Reparse Points
Supports Object Identifiers
Supports Encrypted File System
Supports Named Streams

E:\>dir x:\autoexec.bat
Volume in drive X has no label.
Volume Serial Number is FCCD-E1D0

 Directory of x:\

01/17/2004 02:55 PM 18 AUTOEXEC.BAT
1 File(s) 18 bytes
0 Dir(s) 24,090,845,184 bytes free

E:\>dosdev -r -d X:
Current definition: X: = \??\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
X: deleted.
-----------------------------------------------------
- Mark all writers as succesfully backed up...
Completing the backup (BackupComplete) ...
(Waiting for the asynchronous operation to finish...)
(Waiting for the asynchronous operation to finish...)

Snapshot creation done.

And, that's it - now we have a fully scriptable method to access shadow copies.

Applications? You can use these shadow copies as regular volumes, and even define your own backup scripts to access them (for example you can usethem through robocopy or rsync, etc)