How to find and open previous versions of a folder programmatically (using PowerShell, WMI, etc)?

16,769

Solution 1

The volrest utility, available from the Windows Server 2003 Resource Kit Tools, can be used to list the previous versions of a folder. It worked for me on Windows 7 and should still work on Windows 8. Just be careful with your parameters, since it can also restore previous versions.

An example of use (from the below-quoted link):

C:\>volrest "\\test220\reports\Annual Reports 2004\doc.4.rtf"

VOLREST 1.1 - Previous Version command-line tool
(C) Copyright 2003 Microsoft Corp.

 Searching previous versions on \\test220\reports\annual report 2004\doc.4.rtf

07/01/2004  01:28 PM    37,786 \\test220\reports\@GMT-2004.07.01-18.34.35\annual 
                           report 2004\doc.4.rtf
07/01/2004  01:27 PM    37,740 \\test220\reports\@GMT-2004.07.01-18.28.02\annual 
                           report 2004\doc.4.rtf
07/01/2004  11:47 AM    37,690 \\test220\reports\@GMT-2004.07.01-18.24.41\annual 
                           report 2004\doc.4.rtf

            3 File(s)  113,216 bytes
            0 Dir(s)

With the output of this program, maybe used with the /B parameter for bare format, you should be able to construct a script that will explore one of the listed versions.

For more info see : Windows Server Hacks: Restoring Shadow Copies Using the Command Line.

Solution 2

Here's an example of how to use volrest in a batch file to find the path to the newest and oldest shadow copies on a local or remote server. The paths returned can be used directly without the need to use mklink. Tested locally on Windows Server 2019 and remotely from Windows 10.

:: Proof of concept for finding shadow copy paths on a local or remote server.
:: Requires volrest.exe from the Windows Server 2003 Resource Kit Tools:
:: https://www.microsoft.com/en-us/download/details.aspx?id=17657

@ECHO OFF
SET SERVER=LOCALHOST

:: Loop through output of volrest run against a test folder.  Note that volrest returns
:: items in reverse chronological order and skips shadow copies if the folder hasn't
:: changed between shadow copies.  I found that the Windows\Temp folder was updated
:: frequently enough for my purposes.
::
:: If we're run after the last shadow copy but BEFORE the Windows\Temp folder has been 
:: updated, then volrest won't list the latest shadow copy.  We can fix this by writing a 
:: dummy file to the Windows\Temp folder first and then deleting it.  Uncomment the 
:: following two commands if this might be an issue for you.

:: Optional code to force a dummy update to ensure latest shadow copy is found
:: TYPE NUL > \\%SERVER%\C$\Windows\Temp\ShadowCopyFind.tmp
:: DEL \\%SERVER%\C$\Windows\Temp\ShadowCopyFind.tmp

FOR /F "TOKENS=3 DELIMS=\" %%A IN ('volrest.exe /B \\%SERVER%\C$\Windows\Temp*') DO (
    IF NOT DEFINED GMT_TOKEN_NEWEST SET GMT_TOKEN_NEWEST=%%A
    SET GMT_TOKEN_OLDEST=%%A
)

ECHO Path to Newest Shadow Copy: \\%SERVER%\C$\%GMT_TOKEN_NEWEST%
ECHO Path to Oldest Shadow Copy: \\%SERVER%\C$\%GMT_TOKEN_OLDEST%

Sample output:

Path to Newest Shadow Copy: \\LOCALHOST\C$\@GMT-2020.05.05-16.30.02
Path to Oldest Shadow Copy: \\LOCALHOST\C$\@GMT-2020.03.20-22.30.01

I use this as part of a nightly robocopy job that I've scheduled to run after my Server's last shadow copy of the day. This lets me leverage the Previous Versions shadow copies my server is already creating, ensures that my robocopy job doesn't encounter any locked files, and provides a true "point in time" consistency.

Solution 3

Late reply, but I tried volrest and it doesn't seem to work on Windows 10. As the OP observed, the @GMT-yadayadayada magic folder doesn't appear until you bring the folder up in Explorer from the Previous Versions tab in Properties.

An approach that has worked for me is to use mklink. As administrator on the computer/server in question, open a Command Prompt and type vssadmin list shadows:

C:\WINDOWS\system32>vssadmin list shadows
vssadmin 1.1 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001-2013 Microsoft Corp.

Contents of shadow copy set ID: {5a052a28-96de-4924-b669-9e671b5ce069}
   Contained 1 shadow copies at creation time: 4/07/2019 4:31:12 PM
      Shadow Copy ID: {aaeab260-fef9-4ddc-9190-78d226de07a7}
         Original Volume: (C:)\\?\Volume{010e4355-9f97-4911-99f7-4ef45974b946}\
         Shadow Copy Volume: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
         Originating Machine: DESKTOPPC.domain.local
         Service Machine: DESKTOPPC.domain.local
         Provider: 'Microsoft Software Shadow Copy provider 1.0'
         Type: ClientAccessibleWriters
         Attributes: Persistent, Client-accessible, No auto release, Differential, Auto recovered

Contents of shadow copy set ID: {f2494e05-cb0c-4161-aa67-a545fe562b50}
   Contained 1 shadow copies at creation time: 11/07/2019 3:00:16 AM
      Shadow Copy ID: {c3e0566b-0b39-4080-b5ae-ca6e2a2c56c4}
         Original Volume: (C:)\\?\Volume{010e4355-9f97-4911-99f7-4ef45974b946}\
         Shadow Copy Volume: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2
         Originating Machine: DESKTOPPC.domain.local
         Service Machine: DESKTOPPC.domain.local
         Provider: 'Microsoft Software Shadow Copy provider 1.0'
         Type: ClientAccessibleWriters
         Attributes: Persistent, Client-accessible, No auto release, Differential, Auto recovered

Contents of shadow copy set ID: {aa9f8acb-0a06-4584-9f9e-dee2269b88f3}
   Contained 1 shadow copies at creation time: 19/07/2019 3:45:20 AM
      Shadow Copy ID: {9e3044a8-19e9-4fa8-82ea-b97a836a71d2}
         Original Volume: (C:)\\?\Volume{010e4355-9f97-4911-99f7-4ef45974b946}\
         Shadow Copy Volume: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3
         Originating Machine: DESKTOPPC.domain.local
         Service Machine: DESKTOPPC.domain.local
         Provider: 'Microsoft Software Shadow Copy provider 1.0'
         Type: ClientAccessibleWriters
         Attributes: Persistent, Client-accessible, No auto release, Differential, Auto recovered

Look for the Shadow Copy Volume field, and use the following command to map the one you need to a new folder (in this case, the last one in the list):

C:\>mklink /d C:\vsstest \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\
symbolic link created for vsstest <<===>> \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\

Make sure you add the trailing backslash as I did above, or it won't work.

You will now have your own magic folder for accessing a previous version of your hard drive's contents:

C:\>dir vsstest
 Volume in drive C is Local Disk
 Volume Serial Number is DEAD-BEEF

 Directory of C:\vsstest

26/06/2018  12:49 PM             1,024 .rnd
01/07/2019  01:01 PM    <DIR>          apps
20/12/2018  10:51 AM    <DIR>          ESD
29/05/2019  09:16 PM    <DIR>          inetpub
29/01/2018  12:33 PM    <DIR>          Intel
19/03/2019  02:52 PM    <DIR>          PerfLogs
04/07/2019  04:32 PM    <DIR>          Program Files
16/07/2019  12:40 PM    <DIR>          Program Files (x86)
30/05/2019  11:26 AM    <DIR>          Scripts
14/06/2019  10:46 AM    <DIR>          temp
16/10/2018  01:12 PM    <DIR>          Tools
28/05/2019  09:19 AM    <DIR>          Users
18/06/2019  09:22 AM    <DIR>          VMs
11/07/2019  03:39 AM    <DIR>          Windows
               1 File(s)          1,024 bytes
              14 Dir(s)  107,573,796,864 bytes free

To remove it after you're done, use rmdir.

Solution 4

$DST_info = Get-WmiObject -Class Win32_TimeZone |select @{n='DST_end';e={get-date ([string]$_.StandardMonth+'/'+$_.StandardDay+'/'+(get-date).year) -f "MM/dd/yy"}},@{n='DST_Start';e={get-date ([string]$_.DaylightMonth+'/'+$_.DaylightDay+'/'+(get-date).year) -f "MM/dd/yy"}}
# DST_end  DST_Start
# -------  ---------
# 11/01/20 03/02/20
    
$shadows = Get-CimInstance -ClassName Win32_ShadowCopy -ComputerName MyFileServer
# $shadows | select installDate

foreach($shadow in $shadows)
{
  if ([datetime]$shadow.installdate -ge [datetime]$DST_info.DST_Start -and [datetime]$shadow.installdate -lt [datetime]$DST_info.DST_end) {$offset = 4} else {$offset = 5}
  ls ("K:\@GMT-" + (get-date (get-date $shadow.installdate).addhours($offset) -f "yyyy.MM.dd-HH.mm.ss"))
}

Solution 5

I've found a solution using .NET.

I searched and searched for the ability to list previous versions programmatically, but could not find a solution for viewing previous versions on an SMB / CIFS share. Volrest, vssadmin, alphaVss, etc. Even win32_shadowCopy failed because our target machines are netapps. Nothing worked.

Then I found this post that says they can use SMB commands in Perl to view them. If Perl can do it, surely WinAPI could also. FSCTL_SRV_ENUMERATE_SNAPSHOTS is the SMB command needed.

Finally, I found this DLL created by kenjiuno for .NET. After adding a reference to kenjiuno's DLL, I called it:

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

It returned all previous versions as @GMT-blablabla. Then all you need to do is append the one you want to the end of your UNC path.

No mklink, no mapping drives, etc. Everything works exactly and simply.

Share:
16,769
Vladimir Reshetnikov
Author by

Vladimir Reshetnikov

Updated on September 18, 2022

Comments

  • Vladimir Reshetnikov
    Vladimir Reshetnikov over 1 year

    I am running Windows 8 Enterprise x64. When I open \\localhost\c$ as a network folder, and then using a context menu open the Properties window of a subfolder (e.g. \\localhost\c$\Deploy as in the example below), there is the Previous Versions tab where I can see a list of available previous versions of the folder, along with corresponding timestamps:

    Previous Versions Tab


    If I select a version and click the Open button, a new Explorer window is opened where I can browse the selected previous version of the folder:

    Location on General Tab


    The address bar displays a location where a timestamp (in a long human-readable form) is appended to each folder name. This location, if copied from there, cannot be directly used as a valid path in another Explorer window or a command line tool. But if I open the Properties window of a subfloder, then it displays a location of the subfolder in a form like \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy. This form can actually be used both in the Explorer and the command line:

    C:\>dir \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy /s
     Volume in drive \\localhost\c$ is OSDisk
     Volume Serial Number is ����-����
    
     Directory of \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy
    
    04/11/2013  10:53 AM    <DIR>          .
    04/11/2013  10:53 AM    <DIR>          ..
    04/11/2013  10:53 AM    <DIR>          Tools
                   0 File(s)              0 bytes
    
     Directory of \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy\Tools
    
    04/11/2013  10:53 AM    <DIR>          .
    04/11/2013  10:53 AM    <DIR>          ..
    04/11/2013  10:53 AM    <DIR>          x64
                   0 File(s)              0 bytes
    
     Directory of \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy\Tools\x64
    
    04/11/2013  10:53 AM    <DIR>          .
    04/11/2013  10:53 AM    <DIR>          ..
    08/30/2012  06:10 PM           325,272 ��������.dll
                   1 File(s)        325,272 bytes
    
         Total Files Listed:
                   1 File(s)        325,272 bytes
                   8 Dir(s)  70,546,321,408 bytes free
    

    And in PowerShell too:

    PS C:\> pushd \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy
    PS Microsoft.PowerShell.Core\FileSystem::\\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy> ls -r
    
    
        Directory: \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy
    
    
    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    d----         4/11/2013  10:53 AM            Tools
    
    
        Directory: \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy\Tools
    
    
    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    d----         4/11/2013  10:53 AM            x64
    
    
        Directory: \\localhost\c$\@GMT-2013.08.27-04.01.18\Deploy\Tools\x64
    
    
    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    -a---         8/30/2012   6:10 PM     325272 ��������.dll
    

    It looks like the folder with a magic name @GMT-2013.08.27-04.01.18 (presumably representing a timestamp in the GMT time zone) behaves as if it actually existed there, except that you cannot discover its existence using the dir command unless you already know its name. All files and folders below this folder are read-only: nothing can be created, deleted, renamed or changed there (including file/folder attributes and permissions). If you are an administrator, but do not have permissions to view certain files, you cannot change that, unless you first manage to copy a containing folder to a non-readonly location.

    Question: Is it possible to get the list of versions of a certain folder, like the one shown on the first screenshot, and open one of them in a new Explorer window programmatically (using PowerShell, WMI, WSH, BAT, Win32 API, etc)? Is it possible to get the list of corresponding folders with magic names like @GMT-2013.08.27-04.01.18 programmatically?

  • Kirt Carson
    Kirt Carson over 3 years
    Get-CimInstance -ClassName Win32_ShadowCopy -ComputerName MyFileServer | select InstallDate will provide local time information