View all posts filed under 'VBScript'

Scriptbox – the Windows Script Library

Wednesday, 28. April 2010 16:51

By chance (meaning by googling something) I stumbled over a script library called Scriptbox, and I found a really useful script there. It’s a huge resource! With about 6.500 vbs, js, and ps1 scripts I consider it one of biggest libraries ever.

Category:Scripting, VBScript, Windows PowerShell | Comments (1) | Author: Frank-Peter

How To Re-Use VBScript In PowerShell?

Tuesday, 17. February 2009 0:39

There’s a lot of useful, proven VBScript functions and libraries out there and it is virtually impossible and maybe foolish to rewrite all that good stuff in Windows PowerShell.

They key to use VBS code in PowerShell is the COM object MSScriptControl that is designed to act as a script host. Within a PowerShell script, you can use this object to embed VBScript, e.g. load VBS code, call a function from it, pass arguments to it, and get its return values. Sounds cool? Yes, it is!

The function below – Load-VbsCode – passes VBS code to MSScriptControl and returns a code object with methods that represent the functions defined within the VBS code:

function Load-VbsCode
{
	param($vbsCode = $(throw "No VBS code specified."))

	$vbs = New-Object -ComObject MSScriptControl.ScriptControl
	$vbs.Language = "VBScript"
	$vbs.AddCode([string]::Join("`n", $vbsCode))
	$vbs.CodeObject
}

The AddCode() method expects a string. In order to prevent that an array of multiple text lines will be passed to the method, the data in $vbsCode will be converted to a string using Join.)

Let’s say that you have a VBS file called ConvertFunctions.vbs that, among others, contains this function:

Function Celsius(GradF)
	Celsius = (GradF - 32) * 5 / 9
End Function

The following example shows how to use the Load-VbsCode function in order to embed the above vbs code:

# get contents of the vbs file
$vbsCode = Get-Content .\ConvertFunctions.vbs

# pass the vbs code to Load-VbsCode
$vbs = Load-VbsCode($vbsCode)

# Ready to use the Celsius function...
$f = 70
$c = $vbs.Celsius($f)
Write-Host "$f Fahrenheit are $c Celsius."

Category:Scripting, VBScript, Windows PowerShell | Comments (1) | Author: Frank-Peter

New Citrix MFCOM Scripting Guide

Wednesday, 28. May 2008 14:03

If you need to automate Citrix XenApp (formerly known as Presentation Server) download now the updated Ultimate Guide to MFCOM SDK by “Dr. SDK”

According Citrix Blogger Vishal Ganeriwala this is the only guide you will ever need to understand and learn about MFCOM SDK. It covers everything up to SDK version 4.5. It covers all the advance MFCOM topics such as multifarm management, publishing different type of Applications, policies, load evaluators and more.

All sample code in the new MFCOM guide is still written in VBScript.

According Dr. SDK Citrix is considering to develop a PowerShell-based interface to replace MFCOM entirely. Part of the reason for such a consideration is that most of the farm and server properties will be moved Active Directory. That will result in a large portion of MFCOM properties being invalid.

If you’re interested in scripting MFCOM with PowerShell see also: PowerShell and Citrix MFCOM recorded Webinar and Powerpoint slide deck.

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

ICA Client Detection

Friday, 2. May 2008 15:50

With a few lines of VBScript you can check if an ICA Client is installed and, if yes, determine its version.

If you only want to display the version information you can use the ICA Client Object’s AboutBox method:

On Error Resume Next
Set objICA = WScript.CreateObject("Citrix.ICAClient")
If IsObject(objICA) Then
	objICA.AboutBox
Else
	MsgBox "No ICA Client installed."
End If

This works for ICA Client Version 8 or newer.

Another approach uses the ICA Client Object’s ClientVersion property. The function below, GetICAClientVersion, returns the ICA Client’s version as a string:

Dim strICAClientVersion

strICAClientVersion = GetICAClientVersion()

If (strICAClientVersion <> "") Then
	MsgBox "ICA Client " & strICAClientVersion
Else
	MsgBox "No ICA Client installed."
End If

Function GetICAClientVersion()
	Dim strV
	On Error Resume Next
	Set objICA = WScript.CreateObject("Citrix.ICAClient")
	If IsObject(objICA) Then
		strV = objICA.ClientVersion
	Else
		Err.Clear
		strV = ""
	End If
	On Error GoTo 0
	GetICAClientVersion = strV
End Function

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

How To Attach A Citrix Load Evaluator?

Friday, 11. April 2008 15:50

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":

cscript.exe AttachLoadEvaluatorToServer ctx01 DisableIca

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

cscript.exe AttachLoadEvaluatorToServer %COMPUTERNAME% Advanced

Below you find the listing of the script:

'
' Script name:	AttachLoadEvaluatorToServer.vbs
'
' Purpose:	Attaches a load evaluator to a Citrix terminal server.
'
' Syntax:	AttachLoadEvaluatorToServer servername lename
'
'		  servername     The Citrix terminal server's computer name.
'		  lename         The load evaluator's name (case sensitive)
'
' Author:	Frank-Peter Schultze
'
' Last Update:	2008-04-11
'

Option Explicit

Const CTX_LE_DEFAULT  = "MFDefaultLE"
Const CTX_LE_ADVANCED = "LMSDefaultLE"

Dim strCitrixServer : strCitrixServer = ""
Dim strLEName       : strLEName       = ""

Call GetArgs(strCitrixServer, strLEName)

Call AttachLEToServer(strCitrixServer, strLEName)

Sub AttachLEToServer(strCitrixServer, strLEName)

    Dim objFarm

    On Error Resume Next
    Set objFarm = WScript.CreateObject("MetaFrameCOM.MetaFrameLoadEvaluator")
    On Error GoTo 0
    If IsObject(objFarm) Then
        objFarm.LEName = strLEName
        objFarm.LoadData(True)
        objFarm.AttachToServerByName False, strCitrixServer
        objFarm.SaveData()
        Set objFarm = Nothing
    Else
        WScript.Echo "Can not create MFCOM object."
    End If

End Sub

Sub GetArgs(ByRef strServer, ByRef strLEName)

    Dim objArgs, strTmp

    Set objArgs = WScript.Arguments
    If (objArgs.Count = 2) Then
        strServer = UCase(objArgs.Item(0))
        strTmp = objArgs.Item(1)
        Select Case LCase(strTmp)
            Case "default"
                strLEName = CTX_LE_DEFAULT
            Case "advanced"
                strLEName = CTX_LE_ADVANCED
            Case Else
                strLEName = strTmp
        End Select
    Else
        Call Usage(True)
	Exit Sub
    End If

End Sub

Sub Usage(blnQuit)

    WScript.Echo "Attaches a load evaluator to a Citrix farm server."
    WScript.Echo
    WScript.Echo WScript.ScriptName & " servername lename"
    WScript.Echo
    WScript.Echo "  servername     The Citrix terminal server's computer name."
    WScript.Echo "  lename         The load evaluator's name (case sensitive)."

    If blnQuit Then WScript.Quit

End Sub

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

Active Directory Login Script Template

Thursday, 16. August 2007 18:30

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.

'
' =================================================================
'
'   Script Information
'   ------------------
'
'   Filename:       login.vbs
'   Description:    Active Directory Login Script
'   Created:        9 Aug 2006
'   Author:         Frank-Peter Schultze
'
' =================================================================
'
'
'-- Need to declare variables
'
Option Explicit
'
'-- Define MAP group prefixes
'
Const MAP_DRIVE_GROUP_PREFIX = "MAP-DRV-"
Const MAP_PRINTER_GROUP_PREFIX = "MAP-PRN-"
'
'-- Global variables
'
Dim blnSilent
Dim strLastErrSource, strLastErrNumber, strLastErrDescription
Dim objNet, objUser
Dim strLoginName, strUserDomain, strUserDN
Dim objMemberOf, arrMemberOf, intGroupCount
Dim strGroup, strGroupDN, objGroup
Dim strNetUse, arrNetUse
Dim strDrv, strUnc
Dim strPrinterPath
Dim i, j, l, u
'
'-- Silent operation/do not show errors?
'
blnSilent = True
'
'-- Bind the user object . . .
'
Set objNet = 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
			objMemberOf(strLoginName & "\" & objGroup.sAMAccountName) = True
			LoadGroups strLoginName, objGroup
		End If
	Next
	Set objGroup = Nothing

End Sub

Function MapDrive(strDrive, strShare)

	'
	' Map a network drive
	'

	Const DRIVE_TYPE_NETWORK = 3

	Dim objDrive
	Dim objFSO
	Dim objNet

	MapDrive = False
	strDrive = Left(strDrive, 2)
	Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
	Set objNet = WScript.CreateObject("WScript.Network")
	On Error Resume Next
	If objFSO.DriveExists(strDrive) Then
		Set objDrive = objFSO.GetDrive(strDrive)
		If (objDrive.DriveType <> DRIVE_TYPE_NETWORK) Then
			strLastErrSource = "MapDrive"
			strLastErrNumber = ""
			strLastErrDescription = "Drive letter already in use"
			On Error GoTo 0
			Exit Function
		End If
		objNet.RemoveNetworkDrive strDrive, True, True
		If (Err.Number <> 0) Then
			strLastErrSource = CStr(Err.Source)
			strLastErrNumber = CStr(Err.Number)
			strLastErrDescription = CStr(Err.Description)
			Err.Clear
			On Error GoTo 0
			Exit Function
		End If
	End If
	objNet.MapNetworkDrive strDrive, strShare
	If (Err.Number <> 0) Then
		strLastErrSource = CStr(Err.Source)
		strLastErrNumber = CStr(Err.Number)
		strLastErrDescription = CStr(Err.Description)
		Err.Clear
	Else
		MapDrive = True
	End If
	On Error GoTo 0
	Set objFSO = Nothing

End Function

Sub TimeBombedErrorBox(strMsg)

	Dim objWsh
	Dim intTimeout
	Dim strTitle
	Dim intButton

	If (blnSilent <> True ) Then
		Set objWsh = WScript.CreateObject("WScript.Shell")
		intTimeout = 30
		strTitle = "Error"
		strMsg = strMsg & vbNewLine & vbNewLine
		strMsg = strMsg & "Error source: " & strLastErrSource & vbNewLine
		strMsg = strMsg & "Error number: " & strLastErrNumber & vbNewLine
		strMsg = strMsg & "Error description: " & strLastErrDescription
		intButton = objWsh.Popup(strMsg, intTimeout, strTitle, vbExclamation)
		Set objWsh = Nothing
	End If

End Sub

Function GetDN(strNTName)

	'
	' Translate NT4 name to its DN
	'

	Const ADS_NAME_INITTYPE_GC = 3
	Const ADS_NAME_TYPE_NT4 = 3
	Const ADS_NAME_TYPE_1779 = 1

	Dim objTrans

	Set objTrans = WScript.CreateObject("NameTranslate")
	objTrans.Init ADS_NAME_INITTYPE_GC, ""
	objTrans.Set ADS_NAME_TYPE_NT4, strNTName
	GetDN = objTrans.Get(ADS_NAME_TYPE_1779)
	Set objTrans = Nothing

End Function

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

How To Retrieve The UUID/GUID From A Computer?

Monday, 28. August 2006 11:40

The VBScript function below, GetUUID, shows how to retrieve the UUID/GUID from a computer.

' Test it
WScript.Echo GetUUID(".")

Function GetUUID(strComputer)

	Dim objWmi, colItems, objItem, strUUID, blnValidUUID

	Set objWmi = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
	Set colItems = objWmi.ExecQuery("Select * from Win32_ComputerSystemProduct")
	strUUID = ""
	blnValidUUID = False
	For Each objItem in colItems
		strUUID = objItem.UUID
		If Not IsEmpty(strUUID) OR Not IsNull(strUUID) Then
			If (strUUID <> "00000000-0000-0000-0000-000000000000") AND _
				(strUUID <> "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") Then
				blnValidUUID = True
				Exit For
			End If
		End If
	Next
	Set objWmi = Nothing
	If Not blnValidUUID Then
		Set colItems = GetObject("winmgmts:" & strComputer & "\root\cimv2").InstancesOf("Win32_NetworkAdapter")
		For Each objItem In colItems
			If (objItem.AdapterType = "Ethernet 802.3") Then
				If (objItem.Description <> "Packet Scheduler Miniport") Then
					strUUID = "00000000-0000-0000-0000-" & Replace(objItem.MACAddress, ":", "")
					Exit For
				End If
			End If
		Next
		Set NicSet = Nothing
	End If
	GetUUID = strUUID

End Function

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

How To Enable DHCP Completely?

Wednesday, 19. July 2006 16:12

The Sub procedure below uses WMI in order to set the network adapter’s IP configuration to DHCP, not only for IP address, IP gateway, and subnet mask, but also for both DNS server search order and WINS servers:

Sub AutoIpConfig

	Const LOCAL_MACHINE = "."

	Dim objWmi, colItems, objItem, intError

	Set objWmi =WshGetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
		& LOCAL_MACHINE & "\root\cimv2")
	Set colItems = objWmi.ExecQuery( _
		"Select * from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")
	For Each objItem In colItems
		intError = objItem.EnableDHCP()
		If (intError <> 0) Then
			CriticalErrorBox "Could not enable DHCP."
		End If
		objItem.SetDNSServerSearchOrder Null
		objItem.SetWINSServer Null, Null
		Exit For
	Next

End Sub

If you omit the SetDNSServerSearchOrder and SetWINSServer statements the previously configured DNS and WINS servers will remain in the network adapter’s IP configuration.

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

How To Set The Working Directory For WScript.Shell’s Run Method?

Tuesday, 14. February 2006 16:48

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.

theDir = "C:\WINDOWS"
theCmd = "%ComSpec% /K Echo Type EXIT to close this window."
Set objSh = 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.

' -----------------------------------------------------
' ---- Sub RunHere(theCommandLine, theWorkingDirectory)
' -----------------------------------------------------

Sub RunHere(theCommandLine, theWorkingDirectory)

	Const WAIT = True

	Dim objSh, strPopd

	On Error Resume Next
	Set objSh = WScript.CreateObject("WScript.Shell")
	strPopd = objSh.CurrentDirectory
	objSh.CurrentDirectory = theWorkingDirectory
	objSh.Run theCommandLine, , WAIT
	objSh.CurrentDirectory = strPopd
	Set objSh = Nothing
	On Error GoTo 0

End Sub

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter

How To Import a Regfile?

Tuesday, 24. January 2006 13:17

Batch programmers know that reg files can be imported silently with Regedit.exe /S.

This example shows how to implement this in VBScript:

Dim wsh
Set wsh = WScript.CreateObject("WScript.Shell")
wsh.Run "%SystemRoot%\regedit.exe /S regfile.reg", , True

It is advisable to use a Sub-procedure, especially if you have to import more than one regfile.

ImportRegFile "regfile1.reg"
ImportRegFile "regfile2.reg"
ImportRegFile "regfile3.reg"

Sub ImportRegFile(theFile)
	Dim fso, wsh
	Set fso = WScript.CreateObject("Scripting.FileSystemObject")
	If fso.FileExists(theFile) Then
		Set wsh = WScript.CreateObject("WScript.Shell")
		wsh.Run "%SystemRoot%\regedit.exe /S " & theFile, , True
		Set wsh = Nothing
	End If
	Set fso = Nothing
End Sub

Category:Scripting, VBScript | Comment (0) | Author: Frank-Peter