Volume shadow copies can help you to:
- recover a file, a directory or a volume, or Windows
- find additional artifacts when conducting a live incident response.
- etc.
It may be worth reading VISTA and Windows 7 Shadow Volume Forensics
All the demos, I’ve seen so far were using the built-in DOS mklink command to mount a volume shadow copy and vssadmin to list shadow copies. While playing with vssadmin, I’ve found a use of case of the context parameter of the Select-String cmdlet.
vssadmin list shadows | Select-String -Pattern "shadow copies at creation time" -Context 0,3 | ForEach-Object { [pscustomobject]@{ Path = (($_.Context.PostContext -split "\r\n")[2] -split ':')[1].Trim(); InstallDate = ($_.Line -split ':\s',2)[1]; } }
Ugly, I know. Let’s forget about this, there’s a very simple way return the list volume shadow copies on Windows as objects.
Last year, Boe Prox wrote an excellent article where he showed how to Create a Symbolic Link using PowerShell. Kudos to him, I’ll reuse his brilliant code 😀
Unfortunately, he didn’t show how to remove these symbolic links. The following MSDN article tells us how:
To remove a symbolic link, delete the file (using DeleteFile or similar APIs) or remove the directory (using RemoveDirectory or similar APIs) depending on what type of symbolic link is used.
Now let’s see what I propose to mount and dismount volume shadow copies:
Function Mount-VolumeShadowCopy { <# .SYNOPSIS Mount a volume shadow copy. .DESCRIPTION Mount a volume shadow copy. .PARAMETER ShadowPath Path of volume shadow copies submitted as an array of strings .PARAMETER Destination Target folder that will contain mounted volume shadow copies .EXAMPLE Get-CimInstance -ClassName Win32_ShadowCopy | Mount-VolumeShadowCopy -Destination C:\VSS -Verbose #> [CmdletBinding()] Param( [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)] [ValidatePattern('\\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy\d{1,}')] [Alias("DeviceObject")] [String[]]$ShadowPath, [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ -PathType Container } )] [String]$Destination ) Begin { Try { $null = [mklink.symlink] } Catch { Add-Type @" using System; using System.Runtime.InteropServices; namespace mklink { public class symlink { [DllImport("kernel32.dll")] public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); } } "@ } } Process { $ShadowPath | ForEach-Object -Process { if ($($_).EndsWith("\")) { $sPath = $_ } else { $sPath = "$($_)\" } $tPath = Join-Path -Path $Destination -ChildPath ( '{0}-{1}' -f (Split-Path -Path $sPath -Leaf),[GUID]::NewGuid().Guid ) try { if ( [mklink.symlink]::CreateSymbolicLink($tPath,$sPath,1) ) { Write-Verbose -Message "Successfully mounted $sPath to $tPath" } else { Write-Warning -Message "Failed to mount $sPath" } } catch { Write-Warning -Message "Failed to mount $sPath because $($_.Exception.Message)" } } } End {} } Function Dismount-VolumeShadowCopy { <# .SYNOPSIS Dismount a volume shadow copy. .DESCRIPTION Dismount a volume shadow copy. .PARAMETER Path Path of volume shadow copies mount points submitted as an array of strings .EXAMPLE Get-ChildItem -Path C:\VSS | Dismount-VolumeShadowCopy -Verbose #> [CmdletBinding()] Param( [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)] [Alias("FullName")] [string[]]$Path ) Begin { } Process { $Path | ForEach-Object -Process { $sPath = $_ if (Test-Path -Path $sPath -PathType Container) { if ((Get-Item -Path $sPath).Attributes -band [System.IO.FileAttributes]::ReparsePoint) { try { [System.IO.Directory]::Delete($sPath,$false) | Out-Null Write-Verbose -Message "Successfully dismounted $sPath" } catch { Write-Warning -Message "Failed to dismount $sPath because $($_.Exception.Message)" } } else { Write-Warning -Message "The path $sPath isn't a reparsepoint" } } else { Write-Warning -Message "The path $sPath isn't a directory" } } } End {} }
Let’s see these two functions in action:
- Mount all volume shadow copies
Get-CimInstance -ClassName Win32_ShadowCopy | Mount-VolumeShadowCopy -Destination C:\VSS -Verbose
Get-ChildItem -Path C:\VSS | Dismount-VolumeShadowCopy -Verbose
PowerShell rocks! No doubt 😎
Pingback: « rakhesh.com
Pingback: Shadow copy készítése Powershell-lel | Informatikai Tippek
Pingback: Native powershell support for VSS snapshot mounting | mbrownnyc
Hi dude,
very nice post! but… is it possible to mount shadow copies from a remote computer?
Hi,
Yes, you can probably execute the code through PowerShell remoting as a scriptblock. I haven’t tried it myself but you could try
If the above works, you can then access the shadow copies of the target computer through the path \\target\c$\VSS
Pingback: Attack surface reduction rule triggers a mess on Friday the 13 @ AskWoody
Pingback: Assault floor discount rule triggers a multitude on Friday the 13 @ AskWoody | Tech Mastery