なお、このスクリプトは一般向きではありません。DISKPART と DISM によるオフラインパッチを手作業で (マニュアルで) できるという人が、それを自動化したい場合に限り参考にしてください。スクリプトを眺めるだけでも、いろいろと勉強になるところがあるかもしれません (サブフォルダーのための再帰とか)。
[patch2vhd.vbs]
Option Explicit
Const HKEY_LOCAL_MACHINE = &H80000002
Dim arg, InputKey, targetVHD
Dim objShell, objExec, strCmd
Dim objFSO, objTextFile, strText, outMsgs, outMsg, invalidVHD, VHDDiskID, VHDDriveLetter
Dim objRegistry, strKeyPath, strValueName, strValue, winVer
Dim objFolder, objFile, objSubFolder, strExt
' VHD ファイルの指定
If Right((LCase(WScript.FullName)),11) <> "cscript.exe" then
WScript.Echo "このスクリプトはCSCRIPT.EXEを使用して実行して下さい。"
WScript.Quit
End if
Set arg = WScript.Arguments
if arg.Count = 0 then
WScript.StdOut.Write "VHD のパスを入力して下さい: "
InputKey = Trim(WScript.StdIn.ReadLine)
If InputKey <> "" then
targetVHD = InputKey
Else
WScript.Echo "VHD のパスが入力されませんでした。中止します。"
WScript.Quit
End If
else
targetVHD = arg(0)
end if
' DISKPART 用スクリプトの生成
WScript.Echo "VHD 接続の準備をしています..."
Set objShell = CreateObject("WScript.Shell")
strCmd = "echo select vdisk file = """ & targetVHD & """ > AttachVHDScript.txt & echo attach vdisk >> AttachVHDScript.txt & echo detail vdisk >> AttachVHDScript.txt"
Set objExec = objShell.Exec("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
strCmd = "echo select vdisk file = """ & targetVHD & """ > DetachVHDScript.txt & echo detach vdisk >> DetachVHDScript.txt"
Set objExec = objShell.Exec("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' VHD の接続
WScript.Echo "VHD を接続しています..."
strCmd = "DISKPART /s AttachVHDScript.txt > VHDDiskID.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' ディスク番号の取得
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile ("VHDDiskID.txt", 1)
strText = objTextFile.ReadAll
objTextFile.Close
invalidVHD = true
outMsgs = Split(strText, vbCrLf)
For each outMsg in outMsgs
If Instr(outMsg,"DiskPart により、仮想ディスク ファイルがアタッチされました。") > 0 then
invalidVHD = false
WScript.StdOut.Write "VHD を接続しました。ファイル名: " & targetVHD
Exit For
End If
Next
If invalidVHD then
WScript.Echo "VHD を接続できませんでした。中止します。"
WScript.Quit
End if
invalidVHD = true
For each outMsg in outMsgs
If Instr(outMsg,"関連付けられたディスク番号:") > 0 then
invalidVHD = false
VHDDiskID = Replace(outMsg,"関連付けられたディスク番号: ","")
WScript.Echo " ディスク番号: " & VHDDiskID
Exit For
End If
Next
If invalidVHD then
WScript.Echo " ディスク番号: 不明"
WScript.Echo "ディスク番号を取得できなかったので中止します。VHD は切断されていません。「ディスクの管理」を使用して切断してください。"
WScript.Quit
End if
' ボリューム情報の取得
WScript.Echo "VHD のボリューム情報を取得しています..."
strCmd = "echo select disk " & VHDDiskID & " > DetailDiskScript.txt & echo detail disk >> DetailDiskScript.txt"
Set objExec = objShell.Exec("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' ローカルドライブにマウントされるまでしばらく待つ
WScript.Sleep 10000
strCmd = "DISKPART /s DetailDiskScript.txt > DiskDetails.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
Set objTextFile = objFSO.OpenTextFile ("DiskDetails.txt", 1)
strText = objTextFile.ReadAll
objTextFile.Close
invalidVHD = true
outMsgs = Split(strText, vbCrLf)
For each outMsg in outMsgs
If (Left(outMsg,8) = " Volume") and (Mid(outMsg,15,3) <> "Ltr") then
VHDDriveLetter = Mid(outMsg,15,1)
WScript.StdOut.Write VHDDriveLetter & " ドライブを調べています。"
If objFSO.FolderExists(VHDDriveLetter & ":\Windows") then
WScript.Echo VHDDriveLetter & ":\Windows を確認しました。"
invalidVHD = false
Exit for
Else
WScript.Echo VHDDriveLetter & ":\Windows は存在しません。"
End If
End If
Next
If invalidVHD then
WScript.Echo "Windows のインストールが見つかりません。中止します。VHD は切断されていません。「ディスクの管理」を使用して切断してください。"
WScript.Quit
End if
' OS 情報を取得しています。
' Windows 7 or Windows Server 2008 R2
WScript.Echo "VHD イメージの Windows バージョンを取得しています..."
' ハイブのロード
strCmd = "REG LOAD HKLM\myvhd " & VHDDriveLetter & ":\Windows\System32\config\SOFTWARE"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' レジストリの読み取り
Set objRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
strKeyPath = "myvhd\Microsoft\Windows NT\CurrentVersion"
strValueName = "CurrentVersion"
objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
invalidVHD = true
If Not isNull(strValue) then
If CSng(strValue) > 6 then ' 6.1 以降
invalidVHD = false
End If
winVer = strValue
WScript.Echo "Windows のバージョン: " & winVer
Else
WScript.Echo "Windows のバージョン: 不明"
End If
strValueName = "ProductName"
objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
If Not isNull(strValue) then
WScript.Echo "Windows の製品名: " & strValue
Else
WScript.Echo "Windows の製品名: 不明"
End If
' ハイブのアンロード
strCmd = "REG UNLOAD HKLM\myvhd"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
If invalidVHD then
WScript.Echo "このバージョンの Windows は、オフライン パッチに対応していません。中止します。VHD は切断されていません。「ディスクの管理」を使用して切断してください。"
WScript.Quit
End if
' DISM によるオフライン パッチ
WScript.Echo "更新プログラムをインストールします..."
Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(".\Updates")
InjectUpdates(objFolder)
Sub InjectUpdates(objFolder)
For Each objFile In objFolder.Files
strExt = objFSO.GetExtensionName(objFile.Path)
If (strExt = "msu") or (strExt = "cab") then
WScript.Echo "更新プログラム: " & objFile.Name
strCmd = "DISM /Image:" & VHDDriveLetter & ":\ /Add-Package /PackagePath:""" & objFile.Path & """ >> InjectUpdatesOutput.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0 ' DISM コマンドの終了を待つ
WScript.Sleep 1000
Loop
End If
Next
For Each objSubFolder In objFolder.SubFolders
InjectUpdates(objSubFolder)
Next
End Sub
' VHD の切断
WScript.Echo "VHD を切断します。"
WScript.Sleep 5000
strCmd = "DISKPART /s DetachVHDScript.txt > DetachVHDOutput.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
WScript.Echo "終了しました。"
Const HKEY_LOCAL_MACHINE = &H80000002
Dim arg, InputKey, targetVHD
Dim objShell, objExec, strCmd
Dim objFSO, objTextFile, strText, outMsgs, outMsg, invalidVHD, VHDDiskID, VHDDriveLetter
Dim objRegistry, strKeyPath, strValueName, strValue, winVer
Dim objFolder, objFile, objSubFolder, strExt
' VHD ファイルの指定
If Right((LCase(WScript.FullName)),11) <> "cscript.exe" then
WScript.Echo "このスクリプトはCSCRIPT.EXEを使用して実行して下さい。"
WScript.Quit
End if
Set arg = WScript.Arguments
if arg.Count = 0 then
WScript.StdOut.Write "VHD のパスを入力して下さい: "
InputKey = Trim(WScript.StdIn.ReadLine)
If InputKey <> "" then
targetVHD = InputKey
Else
WScript.Echo "VHD のパスが入力されませんでした。中止します。"
WScript.Quit
End If
else
targetVHD = arg(0)
end if
' DISKPART 用スクリプトの生成
WScript.Echo "VHD 接続の準備をしています..."
Set objShell = CreateObject("WScript.Shell")
strCmd = "echo select vdisk file = """ & targetVHD & """ > AttachVHDScript.txt & echo attach vdisk >> AttachVHDScript.txt & echo detail vdisk >> AttachVHDScript.txt"
Set objExec = objShell.Exec("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
strCmd = "echo select vdisk file = """ & targetVHD & """ > DetachVHDScript.txt & echo detach vdisk >> DetachVHDScript.txt"
Set objExec = objShell.Exec("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' VHD の接続
WScript.Echo "VHD を接続しています..."
strCmd = "DISKPART /s AttachVHDScript.txt > VHDDiskID.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' ディスク番号の取得
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile ("VHDDiskID.txt", 1)
strText = objTextFile.ReadAll
objTextFile.Close
invalidVHD = true
outMsgs = Split(strText, vbCrLf)
For each outMsg in outMsgs
If Instr(outMsg,"DiskPart により、仮想ディスク ファイルがアタッチされました。") > 0 then
invalidVHD = false
WScript.StdOut.Write "VHD を接続しました。ファイル名: " & targetVHD
Exit For
End If
Next
If invalidVHD then
WScript.Echo "VHD を接続できませんでした。中止します。"
WScript.Quit
End if
invalidVHD = true
For each outMsg in outMsgs
If Instr(outMsg,"関連付けられたディスク番号:") > 0 then
invalidVHD = false
VHDDiskID = Replace(outMsg,"関連付けられたディスク番号: ","")
WScript.Echo " ディスク番号: " & VHDDiskID
Exit For
End If
Next
If invalidVHD then
WScript.Echo " ディスク番号: 不明"
WScript.Echo "ディスク番号を取得できなかったので中止します。VHD は切断されていません。「ディスクの管理」を使用して切断してください。"
WScript.Quit
End if
' ボリューム情報の取得
WScript.Echo "VHD のボリューム情報を取得しています..."
strCmd = "echo select disk " & VHDDiskID & " > DetailDiskScript.txt & echo detail disk >> DetailDiskScript.txt"
Set objExec = objShell.Exec("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' ローカルドライブにマウントされるまでしばらく待つ
WScript.Sleep 10000
strCmd = "DISKPART /s DetailDiskScript.txt > DiskDetails.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
Set objTextFile = objFSO.OpenTextFile ("DiskDetails.txt", 1)
strText = objTextFile.ReadAll
objTextFile.Close
invalidVHD = true
outMsgs = Split(strText, vbCrLf)
For each outMsg in outMsgs
If (Left(outMsg,8) = " Volume") and (Mid(outMsg,15,3) <> "Ltr") then
VHDDriveLetter = Mid(outMsg,15,1)
WScript.StdOut.Write VHDDriveLetter & " ドライブを調べています。"
If objFSO.FolderExists(VHDDriveLetter & ":\Windows") then
WScript.Echo VHDDriveLetter & ":\Windows を確認しました。"
invalidVHD = false
Exit for
Else
WScript.Echo VHDDriveLetter & ":\Windows は存在しません。"
End If
End If
Next
If invalidVHD then
WScript.Echo "Windows のインストールが見つかりません。中止します。VHD は切断されていません。「ディスクの管理」を使用して切断してください。"
WScript.Quit
End if
' OS 情報を取得しています。
' Windows 7 or Windows Server 2008 R2
WScript.Echo "VHD イメージの Windows バージョンを取得しています..."
' ハイブのロード
strCmd = "REG LOAD HKLM\myvhd " & VHDDriveLetter & ":\Windows\System32\config\SOFTWARE"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
' レジストリの読み取り
Set objRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
strKeyPath = "myvhd\Microsoft\Windows NT\CurrentVersion"
strValueName = "CurrentVersion"
objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
invalidVHD = true
If Not isNull(strValue) then
If CSng(strValue) > 6 then ' 6.1 以降
invalidVHD = false
End If
winVer = strValue
WScript.Echo "Windows のバージョン: " & winVer
Else
WScript.Echo "Windows のバージョン: 不明"
End If
strValueName = "ProductName"
objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
If Not isNull(strValue) then
WScript.Echo "Windows の製品名: " & strValue
Else
WScript.Echo "Windows の製品名: 不明"
End If
' ハイブのアンロード
strCmd = "REG UNLOAD HKLM\myvhd"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
If invalidVHD then
WScript.Echo "このバージョンの Windows は、オフライン パッチに対応していません。中止します。VHD は切断されていません。「ディスクの管理」を使用して切断してください。"
WScript.Quit
End if
' DISM によるオフライン パッチ
WScript.Echo "更新プログラムをインストールします..."
Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(".\Updates")
InjectUpdates(objFolder)
Sub InjectUpdates(objFolder)
For Each objFile In objFolder.Files
strExt = objFSO.GetExtensionName(objFile.Path)
If (strExt = "msu") or (strExt = "cab") then
WScript.Echo "更新プログラム: " & objFile.Name
strCmd = "DISM /Image:" & VHDDriveLetter & ":\ /Add-Package /PackagePath:""" & objFile.Path & """ >> InjectUpdatesOutput.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0 ' DISM コマンドの終了を待つ
WScript.Sleep 1000
Loop
End If
Next
For Each objSubFolder In objFolder.SubFolders
InjectUpdates(objSubFolder)
Next
End Sub
' VHD の切断
WScript.Echo "VHD を切断します。"
WScript.Sleep 5000
strCmd = "DISKPART /s DetachVHDScript.txt > DetachVHDOutput.txt"
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While objExec.Status = 0
WScript.Sleep 1000
Loop
WScript.Echo "終了しました。"
注意: スクリプトの実行が途中で中止またはエラーで終了した場合、VHD のマウントは解除されません。「ディスクの管理」スナップインを使用して、VHD を手動で切断してください。また、ローカルのレジストリの「HKEY_LOCAL_MACHINE\myvhd」にオフラインのレジストリ ハイブがロードされたままになる場合があります。これもレジストリ エディター (Regedit.exe) を使用して、手動でアンロードしてください。
注目: 「DISKPART 用スクリプトの生成」~「 OS 情報の取得」の直前までの処理は、VMST 3.0 の VHDMountDetails.bat を参考にしています。VHDMountDetails.batでは、VHD 内のボリューム (パーティション) のうち、後ろの方のボリュームが Windows のドライブ文字として選択されるようになっています。そのため、VMST 3.0 の場合、Windows のインストール ボリュームより後ろの位置に、別のボリュームが存在する場合にパッチできないという問題が出るかもしれません。そこで、patch2vhd.vbs では、最初に Windows パスが見つかったボリュームを、Windows のドライブ文字として選択するようにしています。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。