Guy’s Scripting Ezine 59 CONST

Contents for Guy’s Scripting Ezine 59 CONST

 ♣

This Week’s Secret Understanding CONST

When I first started with VBScript, even I just copied and amended other people’s scripts.  However, I could not help but notice that CONST statements always stood out as having a strange aura about them. Naturally, constants by definition do not change, this is what makes CONST fundamentally different from variables.

Since those early days, I have discovered that there are three families of CONSTANTS: system, intrinsic and symbolic constants.  System constants are the easiest to understand, they are constants like, true or false.  Intrinsic constants are built-in constants like vbCr, vbOK and vbCurrency.

Unfortunately, it is the symbolic constants which are widely used in VBScript that are the most difficult to understand.  Here is my view of how how symbolic constants work.  Variable A talks to variable B and variable B talks to variable C.  However A and C cannot talk directly to one another.  So the answer is to change substitute variable B for a symbolic constant.  Let us take an example of a CONST ADS_PROPERTY_APPEND statement which we used to add a member to a group.  The technical explanation of CONST is that because VBScript cannot read from a ‘type library’, we need to employ a symbolic constant instead (Personally I did not find that definition very helpful that is why I evolved my own explanation).

What CONST ADS_PROPERTY_APPEND = 3  is saying to me is this, when VBscript wants to add (APPEND) an Active Directory property (ADS_Property), it has to take the precise form of:  ADS_PROPERTY_APPEND.   Either you just accept that this is how it works, or you delve more deeply and see how the CONST ADS_PROPERTY_APPEND holds the value of 3 throughout the life of the script.  What you cannot do is just substitute 3 for where ever you see ADS_Property.  (Trust me, I tried just substituting 3 for ADS_PROPERTY_APPEND, and the script failed).  What you must do is always script ADS_PROPERTY_APPEND (not 3) when you want to tag on an extra property value.

Here is a roundup what I know about the CONST statement.  VBScript uses symbolic constants, if you do the research, you will discover a whole family of ADS_x_Y constants.  The VBScript procedure is to define these CONST ADS_abc_def at the beginning of your script then call ADS_abc_def when you need to employ the value.  These CONST statements usually refer to an Active Directory property.  Remember that you do not find these CONST statements with network objects such as MapNetworkDrive.

Guy Recommends: The Free IP Address Tracker (IPAT) IP Tracker

Calculating IP Address ranges is a black art, which many network managers solve by creating custom Excel spreadsheets.  IPAT cracks this problem of allocating IP addresses in networks in two ways:

For Mr Organized there is a nifty subnet calculator, you enter the network address and the subnet mask, then IPAT works out the usable addresses and their ranges. 

For Mr Lazy IPAT discovers and then displays the IP addresses of existing computers. Download the Free IP Address Tracker

Example 1 – Delegating Rights to a Computer

VBScript cannot directly modify Active Directory access control lists.  So we have to use the CONST statements to allow the script to make the necessary changes to Active Directory.  It is particularly important to take a minute to work out what this long script will achieve.  The scenario is this: You want to delegate user rights to manage a computer, for example to allow a named user to join this computer to the domain.

Please take the time to investigate the CONST = ADS_ lines in the script

Instructions

  1. Copy and paste the script below into notepad.
  2. Save the file with .vbs extension e.g. DelegateConst.vbs
  3. Double click and then open Active Directory Users and Computers and search the container specified in strContainer.  Did you see a new computer?   Check the security tab, advanced button.  Can you see signs of delegation?
  4. Create a computer referenced by strComputer.  Naturally create the computer in strContainer!
  5. Important edit: strComputerUser = "guyt".   Change the value to a user in your domain

Guy’s Acknowledgement – this script is heavily based on a Microsoft script.

 

‘ DelegateConst.vbs
‘ Problem – Computer account needs to be delegated.
‘ VBScript to create one computer in strContainer
‘ VBScript to delegate lots of User Rights using CONST
‘ Version 1.3.
‘ Guy Thomas January 2005 Based on Microsoft Script

Option Explicit

Dim strComputer, strComputerUser, strContainer, strDNSDomain
Dim objRootDSE, objContainer, objComputer
Dim objSecurityDescriptor, objDACL
Dim objACE1, objACE2, objACE3, objACE4, objACE5
Dim objACE6, objACE7, objACE8, objACE9

‘ Here is where the computer will be created
strContainer = "CN=Computers,"
strComputer = "Ezine58"
‘ Note this is the user that will be delegated rights
‘ Edit this domain user for your script
strComputerUser = "guyt"

‘ ADS_USER_FLAG_ENUM
Const ADS_UF_PASSWD_NOTREQD = &h0020
Const ADS_UF_WORKSTATION_TRUST_ACCOUNT = &h1000

‘ ADS_ACETYPE_ENUM
Const ADS_ACETYPE_ACCESS_ALLOWED = &h0
Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &h5

‘ ADS_FLAGTYPE_ENUM
Const ADS_FLAG_OBJECT_TYPE_PRESENT = &h1

‘ ADS_RIGHTS_ENUM
Const ADS_RIGHT_GENERIC_READ = &h80000000
Const ADS_RIGHT_DS_SELF = &h8
Const ADS_RIGHT_DS_WRITE_PROP = &h20
Const ADS_RIGHT_DS_CONTROL_ACCESS = &h100

‘controlAccessRight rightsGuid values
Const ALLOWED_TO_AUTHENTICATE = "{68B1D179-0D15-4d4f-AB71-46152E79A7BC}"
Const RECEIVE_AS = "{AB721A56-1E2f-11D0-9819-00AA0040529B}"
Const SEND_AS = "{AB721A54-1E2f-11D0-9819-00AA0040529B}"
Const USER_CHANGE_PASSWORD = "{AB721A53-1E2f-11D0-9819-00AA0040529b}"
Const USER_FORCE_CHANGE_PASSWORD = "{00299570-246D-11D0-A768-00AA006E0529}"
Const USER_ACCOUNT_RESTRICTIONS = "{4C164200-20C0-11D0-A768-00AA006E0529}"
Const VALIDATED_DNS_HOST_NAME = "{72E39547-7B18-11D1-ADEF-00C04FD8D5CD}"
Const VALIDATED_SPN = "{F3A64788-5306-11D1-A9C5-0000F80367C1}"

‘ Binding to container where computer is created
Set objRootDSE = GetObject("LDAP://rootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
Set objContainer = GetObject("LDAP://" & strContainer & strDNSDomain)

Set objComputer = objContainer.Create("Computer", "cn=" & strComputer)
objComputer.Put "sAMAccountName", strComputer & "$"
‘ Note you could set this to 4096 instead of using ADS_UF_PASSWD_NOTREQD
objComputer.Put "userAccountControl", _
ADS_UF_PASSWD_NOTREQD Or ADS_UF_WORKSTATION_TRUST_ACCOUNT
objComputer.SetInfo

Set objSecurityDescriptor = objComputer.Get("ntSecurityDescriptor")
Set objDACL = objSecurityDescriptor.DiscretionaryAcl

On Error Resume next
Set objACE1 = CreateObject("AccessControlEntry")
objACE1.Trustee = strComputerUser
objACE1.AccessMask = ADS_RIGHT_GENERIC_READ
objACE1.AceFlags = 0
objACE1.AceType = ADS_ACETYPE_ACCESS_ALLOWED

‘ objACE2 to objACE6: Give extended Rights
Set objACE2 = CreateObject("AccessControlEntry")
objACE2.Trustee = strComputerUser
objACE2.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
objACE2.AceFlags = 0
objACE2.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE2.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE2.ObjectType = ALLOWED_TO_AUTHENTICATE

Set objACE3 = CreateObject("AccessControlEntry")
objACE3.Trustee = strComputerUser
objACE3.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
objACE3.AceFlags = 0
objACE3.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE3.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE3.ObjectType = RECEIVE_AS

Set objACE4 = CreateObject("AccessControlEntry")
objACE4.Trustee = strComputerUser
objACE4.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
objACE4.AceFlags = 0
objACE4.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE4.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE4.ObjectType = SEND_AS

Set objACE5 = CreateObject("AccessControlEntry")
objACE5.Trustee = strComputerUser
objACE5.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
objACE5.AceFlags = 0
objACE5.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE5.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE5.ObjectType = USER_CHANGE_PASSWORD

Set objACE6 = CreateObject("AccessControlEntry")
objACE6.Trustee = strComputerUser
objACE6.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS
objACE6.AceFlags = 0
objACE6.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE6.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE6.ObjectType = USER_FORCE_CHANGE_PASSWORD

‘ objACE7: Property Sets
Set objACE7 = CreateObject("AccessControlEntry")
objACE7.Trustee = strComputerUser
objACE7.AccessMask = ADS_RIGHT_DS_WRITE_PROP
objACE7.AceFlags = 0
objACE7.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE7.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE7.ObjectType = USER_ACCOUNT_RESTRICTIONS

‘ objACE8 and objACE9: Validated Rights
Set objACE8 = CreateObject("AccessControlEntry")
objACE8.Trustee = strComputerUser
objACE8.AccessMask = ADS_RIGHT_DS_SELF
objACE8.AceFlags = 0
objACE8.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE8.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE8.ObjectType = VALIDATED_DNS_HOST_NAME

Set objACE9 = CreateObject("AccessControlEntry")
objACE9.Trustee = strComputerUser
objACE9.AccessMask = ADS_RIGHT_DS_SELF
objACE9.AceFlags = 0
objACE9.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objACE9.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
objACE9.ObjectType = VALIDATED_SPN

objDACL.AddAce objACE1
objDACL.AddAce objACE2
objDACL.AddAce objACE3
objDACL.AddAce objACE4
objDACL.AddAce objACE5
objDACL.AddAce objACE6
objDACL.AddAce objACE7
objDACL.AddAce objACE8
objDACL.AddAce objACE9

objSecurityDescriptor.DiscretionaryAcl = objDACL
objComputer.Put "ntSecurityDescriptor", objSecurityDescriptor
objComputer.SetInfo
Wscript.Echo "Check " & strContainer & _
vbCR & "Security tab, Advanced button on " & strComputer
wscript.quit

‘End of Script
 

Learning Points

Note 0:  When troubleshooting make sure that the strComputer, strContainer and strComputerUser are correct.

Note 1: A plain user, strComputerUser = "guyt"  worked for me.  However strComputerUser = "guyt\domain" failed.  I will let you into a secret, something is not quite correct with format of strComputerUser.  The problem is that strComputerUser = "guyt"  keeps generating an Unknown User in the access control list of the security tab.

Note 2: Once the script runs go to Active Directory Users and Computers.  Make sure the security tab is visible by checking the View (Menu), Advanced Features is ticked. right-click the strComputer object, Properties Security (tab), Advanced (Button).  What you see next depends on whether you are using Windows 2000 or 2003, however what you are looking for is evidence of delegation of the rights set by our script.  Tip, scroll down to see the user referenced in the script.

Note 3: Take the time to admire and study all the CONST statements.

Challenges

  • Try a different user
  • Try to reduce the CONST statements so that they just delegate a few essential user rights.

Summary of CONST

ADS_xyx constants are essential for scripting tasks where you cannot access values directly.  So the technique is to assign the value to a CONST, for example ADS_abc_def = X.  Then call the ADS_abc_def constant at the part of your script where you need to manipulate X.  CONST is just that constant, unchanging, the opposite of a variable.  Technically, VBScript employs symbolic constants when it could not access the type library directly.

See more about VBScript syntax

VBScripts   • WMI  • Logon Scripts  • Ezine 18 Carriage returns  • Ezine 28 InStr  •Free IP Tracker  • Ezines

Ezine 47 .put  •Ezine 59 CONST  • Ezine 41 VBS Select case  •Ezine 56 VBS Select case  • Ezine 80 Comspec

Ezine 89 Sendkeys  • Ezine 97 Net Time  • Ezine 98 W32 Time  • Ezine 99 Time services  • Ezine 120 Sendkeys