2016-07-15

Create Drive D Partition for VDI Pooled VM User Profile Desk

在部署 VDI Pooled VM 時, User 只有 User Profile 可以儲存資料檔案, 或者存放到 UNC Path 的 File Server
在許多情況下 User 會抱怨沒有 Drive D 能存放資料很不習慣, 在使用上也會有 File Server 連線速度較慢的問題
此時我們可以應變的方式為將 User Profile Disk Expand 後提供一個 Partition 給 User 使用
做法是先將 User Profile Disk 利用 Hyper-V 的 Edit Disk 功能 Expand
如果建立 User Profile Disk 時給予的容量限制是 1G, 那麼預設 User Profile Disk: UVHD-template.vhdx 就只有一個 1G 的 Partition
如果要給 User 5G 的 Drive D 空間, Expand 時請填入 1+5=6G 的磁碟大小
如此一來 User Profile Disk 就變成一個 6G 的 Disk, 而磁碟的開頭處有一個 1G 的 Partition 作為 User Profile 使用
後面有一個 5G 的未分割空間

那麼接下來要如何把這 5G 的空間建立 Partition 給 User 使用呢?
我們要利用到 AutoIT 與 VBScript, 請參考以下程式

CreateUserDataDrive.au3

Local $ProgramInstaller = "CreateUserDataDrive.vbs"
RunAsWait("Administrator", ".", "P@$$w0rd", 0, "C:\Windows\System32\wscript.exe " & @ScriptDir & "\" & $ProgramInstaller)

將此程式中的 P@$$w0rd 置換為 Pooled VM 的 Local Administrator 帳號密碼
別忘了用 GPO 將 Local Administrator Enable 起來 (Windows 7 以後 Sysprep 完預設都是 Disable)
然後編譯成 .exe 檔備用 (最好是編譯成 x86 版本)
這個程式會去呼叫下面的 CreateUserDataDrive.vbs

CreateUserDataDrive.vbs

Set dtmConvertedDate = CreateObject("WbemScripting.SWbemDateTime")
strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set oss = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")

For Each os in oss
    OSVersionCaption = os.Caption
VirtualDiskModel = ""
if (Len(Replace(LCase(OSVersionCaption),LCase("Windows 7"),"")) <> Len(OSVersionCaption)) then
OSVersion = "Win7"
VirtualDiskModel = "MSFT VIRTUAL DISK SCSI DISK DEVICE"
elseif (Len(Replace(LCase(OSVersionCaption),LCase("Windows 8.1"),"")) <> Len(OSVersionCaption)) then
OSVersion = "Win81"
VirtualDiskModel = "MICROSOFT VIRTUAL DISK"
elseif (Len(Replace(LCase(OSVersionCaption),LCase("Windows 10"),"")) <> Len(OSVersionCaption)) then
OSVersion = "Win10"
VirtualDiskModel = "MICROSOFT VIRTUAL DISK"
end if
Next

'Option Explicit
Dim objWMIService, objShell, objItem, colItems, DriveHit, ReturnValue

On Error Resume Next

Set objWMIService = GetObject ("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery ("Select * from Win32_LogicalDisk")

DriveHit = 0
DefaultPartitionCount = 1
DiskPartCommandFile = "CreateUserDataDrive.txt"
For Each objItem in colItems
if (UCase(objItem.Name) = "D:") and (UCase(objItem.VolumeName) = "USERDATA") then
DriveHit = 1
WSCript.Quit
exit for
elseif (UCase(objItem.Name) = "E:") and (UCase(objItem.VolumeName) = "USERDATA") then
DriveHit = 2
DefaultPartitionCount = 2
DiskPartCommandFile = "ChangeUserDataLetter.txt"
exit for
end if
Next

if ((DriveHit = 0) or (DriveHit = 2)) then
Set colItems = objWMIService.ExecQuery ("Select * from Win32_DiskDrive")
For Each objItem in colItems
if (UCase(objItem.Name) = "\\.\PHYSICALDRIVE1") and (UCase(objItem.Model) = VirtualDiskModel) and (objItem.Partitions = DefaultPartitionCount) then
set objShell = Wscript.CreateObject ("Wscript.Shell")
set objFSO = CreateObject ("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile(Wscript.ScriptFullName)
ScriptPath = objFSO.GetParentFolderName(objFile)
ReturnValue = objShell.Run("""C:\Windows\System32\diskpart.exe"" /s """ & ScriptPath & "\" & DiskPartCommandFile & """",0,true)
exit for
end if
Next
end if

WSCript.Quit

這個 VBScript 開頭先判斷作業系統版本, 因為 Windows 7 與 Windows 8.1/10 對於掛載到 SCSI Channel 的 VHDX 有不一樣的 Disk Model 名稱
辨別後在下方辨認磁碟時才不會辨認錯誤
後半段先檢查 Drive D 是否存在, 且磁碟名稱是否為 User Data
如果不是的話就利用 DiskPart 來建立分割區並格式化後給予磁碟機代號

CreateUserDataDrive.txt

select disk 1
create partition primary
format fs=ntfs label="UserData" quick OVERRIDE NOERR
assign letter=d
exit

這個是 DiskPart 用到的指令, 在上面 VBScript 中需要呼叫的

ChangeUserDataLetter.txt

select disk 1
select partition 2
assign letter=d
exit

這個是 DiskPart 用到的指令, 在上面 VBScript 中需要呼叫的
有時候很奇怪這個磁碟掛上後代號是 E:
我們要把它修正為 D:

將程式打包

上面四個檔案 (AutoIT 編譯過的 .exe) 準備好之後
用 x86 版本作業系統執行 iexpress (最好是用 Windows 10 x86)
將上述程式打包起來, 執行的程式自然是 AutoIT 編譯過的 .exe
然後放在 GPO 讓 User 登入 Pooled VM 的時候執行
就會自動建立 Drive D 了

沒有留言: