web-dev-qa-db-ja.com

PowerShellからボリュームシャドウコピー(VSS)スナップショットにアクセスする

Windows 7のWindows Power Shellを使用してボリュームシャドウコピースナップショットを作成してアクセスしようとしています。以前の スーパーユーザーの質問 を使用して、以下を使用してスナップショットを作成できることがわかりました。

(Get-WmiObject -list win32_shadowcopy).create("C:\","ClientAccessible")

シャドウコピーを "露出"に設定して、WMIを使用してドライブ文字にマッピングできることを示すドキュメントが見つかりません。同じ質問でリンクされている article は、ジャンクションを使用してスナップショットにアクセスするハックを示しています。

シンボリックリンクにアクセスしようとすると、次のメッセージが表示されます。

PS C:\Windows\system32> ls C:\shadowcopy
Get-ChildItem : The parameter is incorrect.

At line:1 char:3
+ ls <<<<  C:\shadowcopy
    + CategoryInfo          : ReadError: (C:\shadowcopy:String) [Get-ChildItem], IOException
    + FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand

スナップショットに直接アクセスしようとすると、次のようになります。

PS C:\Windows\system32> ls '\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy14'
Get-ChildItem : Paths that begin with \\?\GlobalRoot are internal to the kernel and should not be opened by managed applications.
At line:1 char:3
+ ls <<<<  '\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy14'
    + CategoryInfo          : NotSpecified: (:) [Get-ChildItem], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.GetChildItemCommand

PowerShellスクリプトからVSSスナップショットにアクセスするにはどうすればよいですか?

17
jordanm

どのようにしてシンボリックリンクを作成しましたか?その記事で説明されているように、末尾にバックスラッシュを付けてデバイスパスを指定する必要があります。

_$s1 = (Get-WmiObject -List Win32_ShadowCopy).Create("C:\", "ClientAccessible")
$s2 = Get-WmiObject Win32_ShadowCopy | Where-Object { $_.ID -eq $s1.ShadowID }

$d  = $s2.DeviceObject + "\"   # <-- this here

cmd /c mklink /d C:\shadowcopy "$d"
_

この後、_C:\shadowcopy_にマウントされたシャドウコピーに問題なくアクセスできました。

@KeyszerSがコメントで指摘したように、シャドウコピーをマウント解除するには$s2.Delete()を呼び出します。

27
Ansgar Wiechers

ここに提供されている情報と公式のMicrosoftドキュメントはこちら https://docs.Microsoft.com/en-us/previous-versions/windows/desktop/vsswmi​​/create-method-in-class-win32- shadowcopy この問題を解決するいくつかのPowerShell関数/コマンドレットを作成しました。ランダムなメモ、powershell 5以降のnew-itemのitemTypeはsymbolicLinkですが、ターゲットをシャドウスナップショットとして作成しようとすると、パスが存在しないというメッセージが表示されるため、mklinkツールを使用できます。

function New-ShadowLink {
[CmdletBinding()]
param (
    $linkPath="$($ENV:SystemDrive)\ShadowCopy"
)

begin {
    Write-Verbose "Creating a snapshot of $($ENV:SystemDrive)\"
    $class=[WMICLASS]"root\cimv2:win32_shadowcopy";
    $result = $class.create("$ENV:SystemDrive\", "ClientAccessible");
    Write-Verbose "Getting the full target path for a symlink to the shadow snapshot"
    $shadow = Get-CimInstance -ClassName Win32_ShadowCopy | Where-Object ID -eq $result.ShadowID
    $target = "$($shadow.DeviceObject)\";
}

process {
    Write-Verbose "Creating SymLink to shadowcopy at $linkPath"
    Invoke-Expression -Command "cmd /c mklink /d '$linkPath' '$target'";
}

end {
    Write-Verbose "Created link to shadowcopy snapshot of $($ENV:SystemDrive)\ at $linkPath";
    Write-Verbose "Returning shadowcopy snapshot object"
    return $shadow;
}

}

function Remove-ShadowLink {
[CmdletBinding()]
param (
    $shadow,
    $linkPath="$($ENV:SystemDrive)\ShadowCopy"
)

begin {
    Write-verbose "Removing shadow copy link at $linkPath"
}

process {
    Write-Verbose "Deleting the shadowcopy snapshot"
    $shadow.Delete();
    Write-Verbose "Deleting the now empty folder"
    Try {
        Remove-Item -Force -Recurse $linkPath -ErrorAction Stop;
    }
    catch {
        Invoke-Expression -Command "cmd /c rmdir /S /Q '$linkPath'";
    }
}

end {
    Write-Verbose "Shadow link and snapshot have been removed";
    return;
}

}

これらは、両方の関数をコピーして貼り付け、次のように実行することで利用できます

$shadow = New-ShadowLink -Verbose;
ls C:\ShadowCopy # would show snapshot version of c drive
Remove-ShadowLink -shadow $shadow -Verbose;
ls C:\ShadowCopy # will give error as it doesn't exist

$s = New-ShadowLink -verbose
VERBOSE: Creating a snapshot of C:\
VERBOSE: Getting the full target path for a symlink to the shadow snapshot
VERBOSE: Creating SymLink to shadowcopy at C:\ShadowCopy
VERBOSE: Created link to shadowcopy snapshot of C:\ at C:\ShadowCopy
VERBOSE: Returning shadowcopy snapshot object
PS C:\> ls C:\ShadowCopy
    Directory: C:\ShadowCopy
#ommitted my C drive listing, but it would be here
PS C:\> Remove-ShadowLink -shadow $s -Verbose
VERBOSE: Removing shadow copy link at C:\ShadowCopy
VERBOSE: Deleting the shadowcopy snapshot
VERBOSE: Deleting the now empty folder
VERBOSE: Shadow link and snapshot have been removed
PS C:\> ls C:\ShadowCopy
ls : Cannot find path 'C:\ShadowCopy' because it does not exist.
3
JJ Fullmer

これは、Invoke-Expression の中に New-ShadowLinkは文字列を返します。行を次のように変更した場合:

Invoke-Expression -Command "cmd /c mklink /d '$linkPath' '$target'" | Out-Null

それは問題を修正します。

0
Andrew Butler