Working on a Provisioning Server Project we've decided to use Device Hard Drive Cache.
However during the initial tests, we've faced an issue : How to automate the creation of the Cache Partition on the physical drives ?
To do so, we've developped a little script, launched at Computer Startup by GPO.
At first server boot on image, the local disk is not present, causing Provisioning Server to fallback on Server Side cache.
The following script will then initialize and format the cache partition which will be available for the PVS Client at next reboot.
All activity is logged in the Applications Event's Log.
To be sure the script will not run on Golden Image or when not necessary, the isSystemVdisk() function is checking if the System Disk is the Provisioning Server HBA Virtual Disk.
To Initialize the Disk (as we're supposed to be on a brand new server), the script will generate a .txt file to use DISKPART programmatically.
Also if the Cache Volume is already existing, the Script will exit logging that the volume is already present.
Constants like the Cache Drive Letter or the Cache Volume Name are initially at the beginning of the script so you can modify them to suit your needs.
'--------------------------------------------------------------------------------------
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
Const DiskLetter = "E"
Const DiskPartScriptPath = "C:\Temp\DISKPART.TXT"
Main()
Sub Main()
DiskType = GetIniString("C:\Personality.ini","ArdenceData","_DiskMode","ERROR")
if isSystemVdisk() then
if DiskType="S"then
if VolumeCacheExist() then
WriteLog "AUTOFORMATPVS: Cache Volume Already Formatted"
Else
DiskIndex = SelectFirstPhysicalDiskIndex()
if DiskIndex >= 0Then
GenerateDiskPartScript DiskPartScriptPath , DiskIndex , DiskLetter
if RunDiskpartScript(DiskPartScriptPath) then
RunFormat DiskLetter
End If
Else
WriteErrorLog "AUTOFORMATPVS: No Physical Disk Found"
End If
End If
Else
WriteLog "AUTOFORMATPVS: Running in a Private VDisk"
End If
Else
WriteLog "AUTOFORMATPVS: System Disk is not a PVS VDisk"
End If
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Ini File Reading
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function GetINIString(Filename,Section, KeyName, Default)
on error resume next
Dim PosSection, PosEndSection, sContents, Value, Found
'Get contents of the INI file As a string
INIContents = GetFile(FileName)
'Find section
PosSection = InStr(1, INIContents, "[" & Section & "]", vbTextCompare)
If PosSection>0 Then
'Section exists. Find end of section
PosEndSection = InStr(PosSection, INIContents, vbCrLf & "[")
'?Is this last section?
If PosEndSection = 0Then PosEndSection = Len(INIContents)+1
'Separate section contents
sContents = Mid(INIContents, PosSection, PosEndSection - PosSection)
If InStr(1, sContents, vbCrLf & KeyName & "=", vbTextCompare)>0Then
Found = True
'Separate value of a key.
Value = SeparateField(sContents, vbCrLf & KeyName & "=", vbCrLf)
End If
End If
If isempty(Found) Then Value = Default
GetINIString = Value
End Function
'Separates one field between sStart And sEnd
Private Function SeparateField(ByVal sFrom, ByVal sStart, ByVal sEnd)
Dim PosB: PosB = InStr(1, sFrom, sStart, 1)
If PosB > 0Then
PosB = PosB + Len(sStart)
Dim PosE: PosE = InStr(PosB, sFrom, sEnd, 1)
If PosE = 0Then PosE = InStr(PosB, sFrom, vbCrLf, 1)
If PosE = 0Then PosE = Len(sFrom) + 1
SeparateField = Mid(sFrom, PosB, PosE - PosB)
End If
End Function
'File functions
Private Function GetFile(ByVal FileName)
on error resume next
Set fso = CreateObject("Scripting.FileSystemObject")
GetFile = fso.OpenTextFile(FileName).ReadAll
End Function
Function iSSystemVdisk()
On Error Resume Next
iSSystemVdisk = False
Set objFso = CreateObject("Scripting.FileSystemObject")
SystemDrive = Left(objFso.GetSpecialFolder(1),2)
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colDiskDrives = objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive WHERE Caption = 'Citrix Virtual HBA SCSI Disk Device' OR Caption='Citrix Virtual Hard Disk'", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objDrive In colDiskDrives
strDeviceID = Replace(objDrive.DeviceID, "\", "\\")
Set colPartitions = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
strDeviceID & """} WHERE AssocClass = " & _
"Win32_DiskDriveToDiskPartition")
For Each objPartition In colPartitions
Set colLogicalDisks = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
objPartition.DeviceID & """} WHERE AssocClass = " & _
"Win32_LogicalDiskToPartition")
For Each objLogicalDisk In colLogicalDisks
if objLogicalDisk.DeviceID = SystemDrive then
iSSystemVdisk = True
End if
Next
Next
Next
End Function
Function VolumeCacheExist()
On Error Resume Next
VolumeCacheExist = False
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDisk WHERE VolumeName = 'Cache'", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem In colItems
VolumeCacheExist = True
Next
End Function
Function SelectFirstPhysicalDiskIndex()
On Error Resume Next
SelectFirstPhysicalDiskIndex = -1
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive WHERE Caption <> 'Citrix Virtual HBA SCSI Disk Device' AND Caption <> 'Citrix Virtual Hard Disk'", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem In colItems
SelectFirstPhysicalDiskIndex = objItem.Index
Exit For
Next
End Function
Sub GenerateDiskPartScript( ScriptPath , DiskIndex , Letter)
on error resume next
err.clear
Set ObjFso = CreateObject("Scripting.FileSystemObject")
Set DPScript = ObjFso.CreateTextFile(ScriptPath, True)
DPScript.WriteLine "SELECT DISK " & DiskIndex
DPScript.WriteLine "CLEAN"
DPScript.WriteLine "CREATE PARTITION PRIMARY"
DPScript.WriteLine "ASSIGN LETTER=" & Letter
DPScript.WriteLine "EXIT"
DPScript.close
if err then WriteErrorLog "AUTOFORMATPVS: Impossible to create the DISKPART script: " & err.description
End Sub
Function RunDiskpartScript( ScriptPath )
on error resume next
Set ObjShell = CreateObject("Wscript.Shell")
if ObjShell.run("DISKPART.EXE /s """ & ScriptPath & """" , 0 , True) = 0 Then
RunDiskpartScript = True
Writelog "AUTOFORMATPVS: Cache partition creation : SUCCESS"
Else
RunDiskpartScript = False
WriteErrorlog "AUTOFORMATPVS: Cache partition creation : ERROR"
End If
End Function
Function RunFormat( Letter )
on error resume next
Set ObjShell = CreateObject("Wscript.Shell")
if ObjShell.run("FORMAT " & Letter & ": /FS:NTFS /V:Cache /Q /Y" , 0 , True) = 0Then
RunFormat = True
Writelog "AUTOFORMATPVS: Cache Partition Format : SUCCESS"
Else
RunFormat = False
WriteErrorlog "AUTOFORMATPVS: Cache Partition Format : ERROR"
End If
End Function
Sub WriteLog( msg )
on error resume next
Set objShell = Wscript.CreateObject("Wscript.Shell")
objShell.LogEvent 0, msg
End Sub
Sub WriteErrorLog( msg )
on error resume next
Set objShell = Wscript.CreateObject("Wscript.Shell")
objShell.LogEvent 1, msg
End Sub
'--------------------------------------------------------------------------------------
]