ShadowCopyHandling.psm1

function Get-ShadowCopy {
    <#
    .SYNOPSIS
    Show all Shadow Copies
    .DESCRIPTION
    Shows all Shadow Copies on a system
    .NOTES
    A function for each message type is present so addition tasks can be competed when a message of a specific type is written.
 
    Copyright (C) MosaicMK Software LLC - All Rights Reserved
    Unauthorized copying of this application via any medium is strictly prohibited Proprietary and confidential
    Written by MosaicMK Software LLC (contact@mosaicmk.com)
 
    By using this software you agree to the following:
    Agreement Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software and the rights to use and distribute the software so long a no licensing and or documentation files are remove, revised or modified
    the Software is furnished to do so, subject to the following conditions:
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
 
    Contact: Contact@MosaicMK.com
    Version 1.0.0
    .LINK
    https://www.mosaicmk.com/2019/04/shadow-copy-handling-module.html
    #>

    $ShadowCopys = Get-CimInstance -ClassName Win32_ShadowCopy
    Foreach ($item in $ShadowCopys){
        $ID = $item.ID
        $Shadow = Get-ItemProperty -Path HKLM:\SOFTWARE\ShadowCopyHandling\$ID -ErrorAction SilentlyContinue
        $ShadowCopy = New-Object -TypeName psobject
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name DateCreated -Value $Item.InstallDate
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name ClientAccessible -Value $Item.ClientAccessible
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name Location -Value $Item.DeviceObject
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name ID -Value $Item.ID
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name MountPoint -Value $Shadow.MountPoint
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name Status -Value $Shadow.Status
        $ShadowCopy | Add-Member -MemberType NoteProperty -Name Drive -Value $Shadow.Drive
        $ShadowCopy
    }
}

function New-ShadowCopy {
    <#
    .SYNOPSIS
    Create a new shadow copy
    .DESCRIPTION
    Create a shadow copy of a volume
    .PARAMETER Drive
    The Drive letter of the volume to create a shadow copy of
    .EXAMPLE
    New-ShadowCopy -Drive C
    Creates a shadow copy of the c drive
    .NOTES
    Copyright (C) MosaicMK Software LLC - All Rights Reserved
    Unauthorized copying of this application via any medium is strictly prohibited Proprietary and confidential
    Written by MosaicMK Software LLC (contact@mosaicmk.com)
 
    By using this software you agree to the following:
    Agreement Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software and the rights to use and distribute the software so long a no licensing and or documentation files are remove, revised or modified
    the Software is furnished to do so, subject to the following conditions:
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
 
    Contact: Contact@MosaicMK.com
    Version 1.0.0
    .LINK
    https://www.mosaicmk.com/2019/04/shadow-copy-handling-module.html
    #>

    PARAM(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias("DriveLetter","Name")]
        [String]$Drive
    )
    process{
        $Drive = $Drive[0]
        IF (Get-Volume -DriveLetter $Drive -ErrorAction SilentlyContinue){
            $WmiShadowCopyClass = [WMICLASS]"root\cimv2:win32_shadowcopy"
            $WmiShadowCopyResult = $WmiShadowCopyClass.create("${Drive}:\", "ClientAccessible")
            $ReturnValue = $WmiShadowCopyResult.ReturnValue
            $ID = $WmiShadowCopyResult.ShadowID
            if ($ReturnValue -NE 0) {
                if ($ReturnValue -lt $NewErrorMessages.Count) {$Message = $NewErrorMessages[$ReturnValue]} else {$Message = "Unknown error $ReturnValue"}
                Throw "Failed to create a shadow copy of drive ${Drive}: $Message."
            }
            New-Item "HKLM:\SOFTWARE\ShadowCopyHandling\$ID" -Force | Out-Null
            New-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ID -Name Status -Value "Unmounted" | Out-Null
            New-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ID -Name MountPoint -Value $null | Out-Null
            New-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ID -Name Drive -Value $Drive | Out-Null
        } Else {Throw "Cannot find Drive $Drive"}
    }
}

function Mount-ShadowCopy {
    <#
    .SYNOPSIS
    Mount a Shadow copy
    .DESCRIPTION
    Mount a shadow copy to a symbloic link
    .PARAMETER ShadowCopyID
    ID of the shadow copy to mount
    .PARAMETER MountPoint
    Path to where the shadow copy will be mounted
    .EXAMPLE
    Mount-ShadowCopy -ShadowCopyID "{418D332B-AB85-4865-AC07-7AA3DDBEE46D}" -MountPoint C:\Mount
    Mounts the shadow copy to C:\mount
    .NOTES
    Copyright (C) MosaicMK Software LLC - All Rights Reserved
    Unauthorized copying of this application via any medium is strictly prohibited Proprietary and confidential
    Written by MosaicMK Software LLC (contact@mosaicmk.com)
 
    By using this software you agree to the following:
    Agreement Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software and the rights to use and distribute the software so long a no licensing and or documentation files are remove, revised or modified
    the Software is furnished to do so, subject to the following conditions:
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
 
    Contact: Contact@MosaicMK.com
    Version 1.0.0
    .LINK
    https://www.mosaicmk.com/2019/04/shadow-copy-handling-module.html
    #>

    PARAM(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias("ID","ShadowID")]
        [string]$ShadowCopyID,
        [Parameter(Mandatory=$True)]
        [string]$MountPoint
    )
    IF (Test-Path $MountPoint -ErrorAction SilentlyContinue){Throw "$MountPoint Already exisit"} Else {
        IF ((Get-ShadowCopy | Where-Object -Property ID -EQ "$ShadowCopyID").Status -eq "mounted"){Throw "$ShadowCopyID is already mounted"}
        $ShadowCopyPath = "$((Get-ShadowCopy | Where-Object -Property ID -eq "$ShadowCopyID").Location)\"
        Try {$null = [Win32.SymLink]} Catch {
        Add-Type @"
using System;
using System.Runtime.InteropServices;
 
namespace Win32 {
public class SymLink {
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
 
public static uint Create(string lpSymlinkFileName, string lpTargetFileName, int dwFlags) {
bool done = CreateSymbolicLink(lpSymlinkFileName, lpTargetFileName, dwFlags);
if (done) {
return 0;
} else {
return GetLastError();
}
}
}
}
"@

    }
        $Error = [Win32.SymLink]::Create($MountPoint,$ShadowCopyPath,1)
        if ($error) {Throw "Could not create a symbolic link : $_"}
        If (!(Test-Path "HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID" -ErrorAction SilentlyContinue)) {New-Item "HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID" -Force | Out-Null}
        Set-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID -Name Status -Value "Mounted" | Out-Null
        Set-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID -Name MountPoint -Value $MountPoint | Out-Null
    }
}

Function Dismount-ShadowCopy{
    <#
    .SYNOPSIS
    dismount a Shadow copy
    .DESCRIPTION
    Dismount a shadow copy from a symbloic link
    .PARAMETER ShadowCopyID
    ID of the shadow copy to dismount
    .EXAMPLE
    Dismount-ShadowCopy -ShadowCopyID "{418D332B-AB85-4865-AC07-7AA3DDBEE46D}"
    .NOTES
    Copyright (C) MosaicMK Software LLC - All Rights Reserved
    Unauthorized copying of this application via any medium is strictly prohibited Proprietary and confidential
    Written by MosaicMK Software LLC (contact@mosaicmk.com)
 
    By using this software you agree to the following:
    Agreement Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software and the rights to use and distribute the software so long a no licensing and or documentation files are remove, revised or modified
    the Software is furnished to do so, subject to the following conditions:
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
 
    Contact: Contact@MosaicMK.com
    Version 1.0.0
    .LINK
    https://www.mosaicmk.com/2019/04/shadow-copy-handling-module.html
    #>

    PARAM(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias("ID","ShadowID")]
        [string]$ShadowCopyID
    )
    $MountPoint = (Get-ShadowCopy | Where-Object -Property ID -eq "$ShadowCopyID").MountPoint
    IF (!(Test-path $MountPoint)){Throw "Could not find mount point $MountPoint"} else {
        if ((Get-Item -Path $MountPoint).Attributes -band [System.IO.FileAttributes]::ReparsePoint){
            try {
            $MountPoint = Resolve-Path $MountPoint
            [System.IO.Directory]::Delete($MountPoint, $false) | Out-Null
            Set-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID -Name Status -Value "Unmounted"
            Set-ItemProperty HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID -Name MountPoint -Value $null
            } catch {Throw "Failed to dismount $MountPoint : $($_.Exception.Message)"}
        } else {Throw "There is no Shadow Copy mounted at $MountPoint"}
    }
}

Function Remove-ShadowCopy{
    <#
    .SYNOPSIS
    Removes a Shoadow Copy
    .DESCRIPTION
    Removes a shadow copy using the vssadmin
    .NOTES
    A function for each message type is present so addition tasks can be competed when a message of a specific type is written.
 
    Copyright (C) MosaicMK Software LLC - All Rights Reserved
    Unauthorized copying of this application via any medium is strictly prohibited Proprietary and confidential
    Written by MosaicMK Software LLC (contact@mosaicmk.com)
 
    By using this software you agree to the following:
    Agreement Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software and the rights to use and distribute the software so long a no licensing and or documentation files are remove, revised or modified
    the Software is furnished to do so, subject to the following conditions:
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
 
    Contact: Contact@MosaicMK.com
    Version 1.0.0
    .LINK
    https://www.mosaicmk.com/2019/04/shadow-copy-handling-module.html
    #>

    Param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias("ID","ShadowID")]
        [string]$ShadowCopyID,
        [switch]$Force
    )
    process{
        IF (!($Force)){$a = Read-Host "Are you sure you want to remove Shadow copy $ShadowCopyID, This proccess can not be undone (y,n)"}else{$a="y"}
        IF ($a -like "*y*"){
            $ID = (Get-ShadowCopy | Where-Object -Property ID -EQ "$ShadowCopyID").ID
            if ($ID -eq "$null"){Throw "There is no ShadowCopy with ID $ShadowCopyID"}else{
                vssadmin delete shadows /shadow=$ID /quiet | Out-Null
                IF ($LASTEXITCODE -ne 0){Throw "Could not delete shadow copy"}
                Remove-Item HKLM:\SOFTWARE\ShadowCopyHandling\$ShadowCopyID -ErrorAction SilentlyContinue -Recurse -Force | out-null
            }
        }
    }
}