CitrixTools.Net Articles

Current Articles | Categories | Search | Syndication

Automatically Initialize a Provisioning Server Client Cache Disk

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 >= 0 Then
    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 = 0 Then PosEndSection = Len(INIContents)+1
    
    'Separate section contents
    sContents = Mid(INIContents, PosSection, PosEndSection - PosSection)

    If InStr(1, sContents, vbCrLf & KeyName & "=", vbTextCompare)>0 Then
      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 > 0 Then
    PosB = PosB + Len(sStart)
    Dim PosE: PosE = InStr(PosB, sFrom, sEnd, 1)
    If PosE = 0 Then PosE = InStr(PosB, sFrom, vbCrLf, 1)
    If PosE = 0 Then 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) = 0 Then
  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
 

'--------------------------------------------------------------------------------------

]

posted on Sunday, May 24, 2009 8:20 PM by Pierre Marmignon    

Previous Page | Next Page

COMMENTS

Using this with PVS 5.1 on a desktop I keep getting the error, no physical disk found?

posted @ Wednesday, July 08, 2009 1:57 PM by Trevor


Dear Trevor, as seen together this is now fixed ;) I've updated this article.

posted @ Friday, August 14, 2009 9:13 AM by Pierre Marmignon


Hello

When using this script I keep getting a message, in the Event Viewer, saying: "AUTOFORMATPVS: Running in a Private VDisk" eventhough the vDisk has been configured as a Standard Image with caching on device HD.

The contents of personality.ini:

[StringData]
$DiskName=WinXP
$WriteCacheType=4
[ArdenceData]
_EnablePrinterSettings=0
_DiskMode=S

From the looks of it, the disk is NOT configured as a Private vDisk. Do You have any suggestions as to why the script "thinks" the disk is a Private vDisk?

posted @ Sunday, February 14, 2010 12:01 AM by Kasper Johansen


Only registered users may post comments.