This article provides the script AttachLoadEvaluatorToServer.vbs that attaches a Load Evaluator to a Citrix terminal server. The script is proven in CPS 4.0 and 4.5 environments, and thanks to the hint of one of my fellows at Login Consultants it supports now the built-in Load Evaluators “Default” and “Advanced”.

Given that you have a Load Evaluator to put a terminal server in offline mode – that is a Load Evaluator with an according Scheduling rule to disable ICA logons – this script is useful for automated installation or maintenance tasks.

Since AttachLoadEvaluatorToServer.vbs automates a Citrix server configuration it’s no surprise that it requires MFCOM. Therefore you should it execute on a Citrix terminal server. You need to specify the computer name of a terminal server in the farm and the exact name of the Load Evaluator as arguments. Listed below some examples to clarify the usage of the script…

This one attaches the Load Evaluator “DisableIca” to the Citrix server “ctx01”:

Example Call AttachLoadEvaluatorToServer #1

Visual Basic

1

cscript.exe AttachLoadEvaluatorToServer ctx01 DisableIca

To attach the Load Evaluator “Advanced” to the Citrix server that executes AttachLoadEvaluatorToServer.vbs type:

The login script template provided in this article maps network drives and printers based on the user’s membership in so-called “map groups”. Since a map group delivers the information which resource should be mapped for its members, you hardly ever need to modify this script due to changes in the drive or printer mappings.

For each drive and printer mapping you need to create an according AD group that follows an naming convention. By default, a map group for a network drive begins with “MAP-DRV-“, and the prefix for a network printer map group is “MAP-PRN-“. (Both prefixes can be customized by changing the constants MAP_DRIVE_GROUP_PREFIX and MAP_PRINTER_GROUP_PREFIX in this script.)

In addition to follow the naming convention you have to specify the network resources that should be mapped in the description field of a map group. In case of the map group for a network drive you must specify the drive letter followed by the unc path (seperated by a space character). In case of the printer map group you must specify the network printer’s unc path.

Since the script recognized indirect or nested group memberships you are able to add users as well as groups to the map groups. The LoadGroups function contains slightly modified code that I found on Richard L. Mueller’s website (http://www.rlmueller.net), Thanks.

Active Directory Login Script (VBScript)

Visual Basic

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

'

' =================================================================

'

' Script Information

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

'

' Filename: login.vbs

' Description: Active Directory Login Script

' Created: 9 Aug 2006

' Author: Frank-Peter Schultze

'

' =================================================================

'

'

'-- Need to declare variables

'

OptionExplicit

'

'-- Define MAP group prefixes

'

ConstMAP_DRIVE_GROUP_PREFIX="MAP-DRV-"

ConstMAP_PRINTER_GROUP_PREFIX="MAP-PRN-"

'

'-- Global variables

'

DimblnSilent

DimstrLastErrSource,strLastErrNumber,strLastErrDescription

DimobjNet,objUser

DimstrLoginName,strUserDomain,strUserDN

DimobjMemberOf,arrMemberOf,intGroupCount

DimstrGroup,strGroupDN,objGroup

DimstrNetUse,arrNetUse

DimstrDrv,strUnc

DimstrPrinterPath

Dimi,j,l,u

'

'-- Silent operation/do not show errors?

'

blnSilent=True

'

'-- Bind the user object . . .

'

SetobjNet=WScript.CreateObject("Wscript.Network")

strLoginName=UCase(objNet.UserName)

strUserDomain=objNet.UserDomain

strUserDN=GetDN(strUserDomain&"\" & strLoginName)

Set objUser = GetObject("LDAP://" & strUserDN)

'

'-- Load the user's direct and indirect group memberships . . .

'

Set objMemberOf = WScript.CreateObject("Scripting.Dictionary")

LoadGroups strLoginName, objUser

arrMemberOf = objMemberOf.Keys

intGroupCount = objMemberOf.Count

'

'-- Map the user's network drives . . .

'

For i = 0 To intGroupCount - 1

strGroup = Replace(arrMemberOf(i), strLoginName & "\","")

j=Len(MAP_DRIVE_GROUP_PREFIX)

If(Left(strGroup,j)=MAP_DRIVE_GROUP_PREFIX)Then

strGroupDN=GetDN(strUserDomain&"\" & strGroup)

Set objGroup = GetObject("LDAP://" & strGroupDN)

On Error Resume Next

strNetUse = Trim(CStr(objGroup.Description))

If (strNetUse <> "") Then

arrNetUse = Split(strNetUse, "")

l = LBound(arrNetUse)

u = UBound(arrNetUse)

If (l <> u) Then

strDrv = arrNetUse(l)

strUnc = arrNetUse(u)

If Not MapDrive(strDrv, strUnc) Then

TimeBombedErrorBox "MapDrive(" & Chr(34) & strDrv & Chr(34) & "," _

& Chr(34) & strUnc & Chr(34) & ")returned an error!"

End If

End If

End If

On Error GoTo 0

Set objGroup = Nothing

End If

Next

'

'-- Map the user's network printers . . .

'

For i = 0 To intGroupCount - 1

strGroup = Replace(arrMemberOf(i), strLoginName & "\","")

j=Len(MAP_PRINTER_GROUP_PREFIX)

If(Left(strGroup,j)=MAP_PRINTER_GROUP_PREFIX)Then

strGroupDN=GetDN(strUserDomain&"\" & strGroup)

Set objGroup = GetObject("LDAP://" & strGroupDN)

On Error Resume Next

strPrinterPath = CStr(objGroup.Description)

If (strPrinterPath <> "") Then

objNet.AddWindowsPrinterConnection strPrinterPath

If (Err.Number <> 0) Then

strLastErrSource = CStr(Err.Source)

strLastErrNumber = CStr(Err.Number)

strLastErrDescription = CStr(Err.Description)

Err.Clear

TimeBombedErrorBox "AddWindowsPrinterConnection" & Chr(34) _

& strPrinterPath & Chr(34) & "returned an error!"

End If

End If

On Error GoTo 0

Set objGroup = Nothing

End If

Next

Set objMemberOf = Nothing

Set objUser = Nothing

Set objNet = Nothing

'//

'// Procedures

'//

Sub LoadGroups(strLoginName, objADObject)

'

' Load the user's direct and indirect group memberships

'

Dim colstrGroups

Dim objGroup

Dim j

objMemberOf.CompareMode = vbTextCompare

colstrGroups = objADObject.memberOf

If IsEmpty(colstrGroups) Then

Exit Sub

End If

If TypeName(colstrGroups) = "String" Then

Set objGroup = GetObject("LDAP://" & colstrGroups)

If Not objMemberOf.Exists(strLoginName & "\"&objGroup.sAMAccountName)Then

objMemberOf(strLoginName&"\" & objGroup.sAMAccountName) = True

LoadGroups strLoginName, objGroup

End If

Set objGroup = Nothing

Exit Sub

End If

For j = 0 To UBound(colstrGroups)

Set objGroup = GetObject("LDAP://" & colstrGroups(j))

If Not objMemberOf.Exists(strLoginName & "\"&objGroup.sAMAccountName)Then

The Run method uses always the current working directory. Therefore, you have to change the directory if the command that will be executed with the Run method requires to be run from a specific directory.

Set CurrentDirectory (VBScript)

Visual Basic

1

2

3

4

5

theDir="C:\WINDOWS"

theCmd="%ComSpec% /K Echo Type EXIT to close this window."

SetobjSh=WScript.CreateObject("WScript.Shell")

objSh.CurrentDirectory=theDir

objSh.Run theCmd

The Sub below, RunHere, executes a command in the specified working directory and then changes back to the original directory.

In order to detect if a script was started in a terminal server session the script can check the SESSIONNAME environment variable which is only defined if the Terminal Services are installed on Windows 2000 Server, Windows Server 2003, and Windows XP clients (or newer). When a client connects via a RDP or ICA (Citrix) session, this variable is a combination of the connection name, i.e. “RDP-Tcp” or “ICA-Tcp”, followed by a pound symbol “#” and then the session number in three figures “nnn“. When logging on directly to the machine, this variable returns “Console”.

The VScript function below returns True if the SESSIONNAME variable resolve to a value beginning with “RDP” or “ICA”

The VBScript file below, Tail.vbs, shows the end (the last lines) of a text file.

During the read of the text file, instead of counting the lines, each line is pushed into a small, rotating stack held in a dynamic array (size = number of tail lines). At the end of file, the stack array is popped to echo the tail.