VBS string wizzardry - vbscript

Ok, so it's not, but...
so this is a quick script I found on the internet which runs on my Exchange server and dumps a list of email addresses that I can use for recipient validation on a spam filter:
' Export all valid recipients (= proxyAddresses) into a
' file virtual.txt
'
' Ferdinand Hoffmann & Patrick Koetter
' 20021100901
' Shamelessly stolen from
' http://www.microsoft.com/windows2000/techinfo/ \
' planning/activedirectory/bulksteps.asp
'Global variables
Dim Container
Dim OutPutFile
Dim FileSystem
'Initialize global variables
Set FileSystem = WScript.CreateObject("Scripting.FileSystemObject")
Set OutPutFile = FileSystem.CreateTextFile("virtual.txt", True)
Set Container=GetObject("LDAP://CN=Users,DC=office,DC=example,DC=com")
'Enumerate Container
EnumerateUsers Container
'Clean up
OutPutFile.Close
Set FileSystem = Nothing
Set Container = Nothing
'Say Finished when your done
WScript.Echo "Finished"
WScript.Quit(0)
'List all Users
Sub EnumerateUsers(Cont)
Dim User
'Go through all Users and select them
For Each User In Cont
Select Case LCase(User.Class)
'If you find Users
Case "user"
'Select all proxyAddresses
Dim Alias
If Not IsEmpty(User.proxyAddresses) Then
For Each Alias in User.proxyAddresses
OutPutFile.WriteLine "alias: " & Alias
'WScript.Echo Alias
Next
End If
Case "organizationalunit" , "container"
EnumerateUsers User
End Select
Next
End Sub
The catch is that the list of recipients comes back like this:
smtp:user#local.lan
SMTP:user#publicdomain.com
x400:c=US;a= ;p=local;o=Exchange;s=lastname;g=firstname;
smtp:postmaster#publicdomain.com
smtp:webmaster#publicdomain.com
The spam filter has an import scrip that only imports lines with "smtp" or "SMTP" prefixed so the x400 isn't an issue. What is an issue is that I don't want the VBscript exporting the "user#local.lan" address. I've tried this:
'List all Users
Sub EnumerateUsers(Cont)
Dim User
'Go through all Users and select them
For Each User In Cont
Select Case LCase(User.Class)
'If you find Users
Case "user"
'Select all proxyAddresses
Dim Alias
If Not IsEmpty(User.proxyAddresses) Then
For Each Alias in User.proxyAddresses
If Not Alias = "*.lan" Then
OutPutFile.WriteLine "alias: " & Alias
WScript.Echo Alias
End If
Next
End If
Case "organizationalunit" , "container"
EnumerateUsers User
End Select
Next
End Sub
But, that doesn't do anything. I've tried matching for the public domain (If Alias = "publicdomain" Then) but that didn't produce any results.
So, how do I filter the output so I only get addresses ont he public domain?

Replace
If Not Alias = "*.lan"
with
If Right(Alias, 4) <> ".lan"
(It can be done with regular expressions but it's Friday and I'm tired!)

You could use a regular expression to filter out lines that don't match your criteria. Something like the following.
smtp:.*#publicdomain\.com
Alternatively you could also tweak your LDAP query to only return users of a certain OU. Is there an AD group that only users with exchange accounts belong in?
Here's the VBS for RegEx matching...
Dim s : s = "smtp:user#local.lan" & VBCRLF & _
"SMTP:user#publicdomain.com" & VBCRLF & _
"x400:c=US;a= ;p=local;o=Exchange;s=lastname;g=firstname;" & VBCRLF & _
"smtp:postmaster#publicdomain.com" & VBCRLF & _
"smtp:webmaster#publicdomain.com"
Dim ex : ex = "smtp:.*#publicdomain\.com"
Dim oRE: Set oRE = New RegExp
oRE.IgnoreCase = True
oRE.Global = True
oRE.Pattern = ex
Dim matches : Set matches = oRE.Execute(s)
For Each match In matches
WScript.Echo match.Value
Next

Related

add multiple multi string values to registry using array

Code is cleaned and changed from previous post since old logics had various errors that have been corrected and narrowed down to one error in one condition that I cant find an answer to. Currently getting error when my url is being read as only value and throwing Subscript Out of range error even though array is initialized. Other conditions when user has preset items or no key at all works perfectly. Thanks.
option explicit
'on error resume next
Dim ObjName,oADSysInfo,strComputer
Dim objReg,IE_Main,mstrValName,strFunctionIntranet,strNYHomepage,multiStringValues(),allURLs(),itemname,a,return
Set oADSysInfo = CreateObject("ADSystemInfo")
Set ObjName = GetObject("LDAP://" & oADSysInfo.UserName)
strComputer = "."
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
Const HKCU = &H80000001
IE_Main = "Software\Microsoft\Internet Explorer\Main"
mstrValName = "Secondary Start Pages"
strNYHomepage = "http://www.google.com"
strFunctionIntranet = "www.mycompany.com"
SetHomePage
Sub SetHomepage
objReg.setStringValue HKCU,IE_Main,"Start Page",strNYHomepage
'Reading MultiStringValue of "Secondary Start Pages" for HKCU and continuing if it has something preset.
return = objReg.getMultiStringValue (HKCU,IE_Main,mstrValName,multiStringValues)
If return=0 Then
a=0
'Reading all items currently set to make sure users retain their existing URLs.
For Each itemname In multiStringValues
'Only continue if any of the existing URLs DO NOT MATCH what we are enforcing as the URL.
If itemname <> strFunctionIntranet Then
WScript.Echo itemname
WScript.Echo "itemname is NOT equal intranet"
a = a + 1
ReDim Preserve allURLs(a)
allURLs(a) = itemname
'a = a + 1
End If
Next
objReg.DeleteValue HKCU,IE_Main,mstrValName
'Enforce our URL to always be the first item.
allURLs(0)=strFunctionIntranet
'Set the new MultiStringValue registry key back.
objReg.setMultiStringValue HKCU,IE_Main,mstrValName,allURLs
WScript.echo "finished setting all secondary tabs... "
Else
strFunctionIntranet = Array(strFunctionIntranet)
objReg.setMultiStringValue HKCU,IE_Main,mstrValName,strFunctionIntranet
End If
End Sub
Wscript.Quit
Your array contains an empty element, because you create it one field too big.
Change this line:
ReDim Preserve allURLs(a+1)
into this:
ReDim Preserve allURLs(a)

How to provide hostname and credentials to "LDAP://"?

I need to have an Active Directory Shadow Groups (aka Active Directory Dynamic Group), based on several DN's.
I've searched high and low for a simple tool that would allow me to do this, and finally found Dan Holme's excellent script (quoted below) at http://kb.caresys.com.cn/4052785/need-script-add-all-accounts-active-directory-security-group (and a few other places)
I also found several PowerShell scripts, but they all appear to have much harder dependencies and I need a tool that's as stand-alone as possible. They also all have the same problem as I'm faced with here.
The Group_Shadow.vbs script performs exactly what I need with one exception:
I need to be able to specify the AD's Host, port number and credentials (login and password).
The script assumes that "LDAP://" is pointing to the correct AD, and I guess the AD Credentials are derived from the user running the script?
I did find a hint about how to set the host name and password, by changing the "LDAP://" string into "LDAP://LDAP_HOST:LDAP_PORT/".
That seems pretty easy to implement - but there were a few comments stating it didn't work...
I also found a hint about setting the credentials:
Dim LDAP ' As IADsOpenDSObject
Set LDAP = GetObject("LDAP:")
Set obj = LDAP.OpenDSObject("LDAP://", "domain\name", "password", ADS_USE_ENCRYPTION OR ADS_SECURE_AUTHENTICATION)
This appear to be the hard part (being totally novice in both the VBScript and Active Directory world), and I simply can't figure out how to combine to two.
I hope the community can help me out, either by assisting fixing this script or by pointing to a different solution.
Thanks in advance!
The Script:
'==========================================================================
'
' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2007
'
' NAME: Group_Shadow.vbs
'
' AUTHOR: Dan Holme , Intelliem
' DATE : 12/12/2007
'
' USAGE:
' cscript.exe Group_Shadow.vbs
'
' Dynamically updates the membership of a group
' to match the objects returned from an Active Directory query
'
' See the Windows Administration Resource Kit for documentation
'
' Neither Microsoft nor Intelliem guarantee the performance
' of scripts, scripting examples or tools.
'
' See www.intelliem.com/resourcekit for updates to this script
'
' (c) 2007 Intelliem, Inc
'==========================================================================
Option Explicit
Dim sDomainDN
Dim sGroupSAMAccountName
Dim aSearchOUs
Dim sQuery
'==========================================================================
' CONFIGURATION BLOCK
' Domain's DN
sDomainDN = "dc=domain,dc=local"
' sAMAccountName of shadow group
sGroupSAMAccountName = "Security Group"
' An array of one or more OUs to search
aSearchOUs = Array("ou=Something,dc=domain,dc=local")
' LDAP query that will be run in each OU
sQuery = " (&(objectCategory=computer)(name=GA*));distinguishedName;subtree"
'==========================================================================
' Create dictionaries
Dim dResults
Set dResults = CreateObject("Scripting.Dictionary")
dResults.CompareMode = vbTextCompare ' Case INsensitive
Dim dTargetMembership
Set dTargetMembership = CreateObject("Scripting.Dictionary")
dTargetMembership.CompareMode = vbTextCompare ' Case INsensitive
Dim dCurrentMembership
Set dCurrentMembership = CreateObject("Scripting.Dictionary")
dCurrentMembership.CompareMode = vbTextCompare ' Case INsensitive
Dim dMembershipChanges
Set dMembershipChanges = CreateObject("Scripting.Dictionary")
dMembershipChanges.CompareMode = vbTextCompare ' Case INsensitive
' Perform LDAP searches, adding to final list stored in dTargetMembership
Dim sSearchOU
Dim sLDAPQuery
For Each sSearchOU In aSearchOUs
sLDAPQuery = "<LDAP://" & sSearchOU & ">;" & sQuery
Set dResults = AD_Search_Dictionary(sLDAPQuery)
Call DictionaryAppend(dResults, dTargetMembership)
Next
' Locate group
Dim sGroupADsPath
Dim oGroup
sGroupADsPath = ADObject_Find_Generic(sGroupSAMAccountName, sDomainDN)
If sGroupADsPath = "" Then
' Error handling: group not found
WScript.Quit
End If
Set oGroup = GetObject(sGroupADsPath)
' Get members and store in dictionary
Dim aMembers
aMembers = oGroup.GetEx("member")
Set dCurrentMembership = ArrayToDictionary(aMembers)
' Calculate the "delta" between the current and desired state
Set dMembershipChanges = Dictionary_Transform(dCurrentMembership, dTargetMembership)
' Make the membership changes based on the transform dictionary's instructions
Dim sMember
For Each sMember In dMembershipChanges
If UCase(dMembershipChanges.Item(sMember)) = "ADD" Then
oGroup.Add "LDAP://" & sMember
End If
If UCase(dMembershipChanges.Item(sMember)) = "DELETE" Then
oGroup.Remove "LDAP://" & sMember
End If
Next
WScript.Quit
' ======================
' FUNCTIONS FROM LIBRARY
' ======================
' #region Dictionary routines
Function ArrayToDictionary(ByRef aArray)
' Converts a one-dimensional array into a dictionary.
' Assumes elements in array are unique
Dim dDic
Dim aElement
Set dDic = CreateObject("Scripting.Dictionary")
dDic.CompareMode = vbTextCompare ' Case INsensitive
On Error Resume Next ' trap duplicate array elements
For Each aElement In aArray
dDic.Add aElement, 0
Next
On Error GoTo 0
Set ArrayToDictionary = dDic
End Function
Sub DictionaryAppend(ByRef dNewElements, ByRef dDictionary)
' Appends the elements of dNewElements to dDictionary
Dim sKey
On Error Resume Next ' trap duplicate array elements
For Each sKey In dNewElements.keys
dDictionary.Add sKey, dNewElements.Item(sKey)
Next
On Error GoTo 0
End Sub
Function Dictionary_Transform(ByVal dOriginal, ByVal dFinal)
' Retunrs a dictionary with a list of update operations required
' so that dOriginal is transformed to dFinal
Dim dTransform, sKey
Set dTransform = CreateObject("Scripting.Dictionary")
dTransform.CompareMode = vbTextCompare ' Case INsensitive
For Each sKey In dFinal.Keys
If Not dOriginal.Exists(sKey) Then
dTransform.Add sKey, "ADD"
End If
Next
For Each sKey In dOriginal.Keys
If Not dFinal.Exists(sKey) Then
dTransform.Add sKey, "DELETE"
End If
Next
Set Dictionary_Transform = dTransform
End Function
' #endregion
' #region Active Directory object find routines
Function ADObject_Find_Generic(ByVal sObject, ByVal sSearchDN)
' Version 071130
' Takes any input (name, DN, or ADsPath) of a user, computer, or group, and
' returns the ADsPath of the object as a way of validating that the object exists
'
' INPUTS: sObject DN or ADsPath to an object
' sAMAccountName (pre-Windows 2000 logon name) of a user or group
' computer name of a computer
' sSearchDN the DN within which to search (often, the DN of the domain, e.g. dc=contoso, dc=com)
'
' RETURNS: ADObject_Find_Generic ADsPath (LDAP://...) of the object
' blank if object was not found
'
' NOTES: ASSUMPTION: computers, users & groups have unique names. See note inline.
'
' REQUIRES AD_Search_Array routine
' AD_Search_RS routine
' ADObject_Validate routine
Dim aResults, sLDAPQuery
Select Case ADObject_NameType(sObject)
Case ""
ADObject_Find_Generic = ""
Case "adspath"
ADObject_Find_Generic = ADObject_Validate(sObject)
Case "distinguishedname"
ADObject_Find_Generic = ADObject_Validate("LDAP://" & sObject)
Case "name"
' Assumption: No computer has the same name as a user's or group's sAMAccountName
' otherwise, this query will return more than one result
sLDAPQuery = "<LDAP://" & sSearchDN & ">;" & _
"(|(samAccountName=" & sObject & ")(samAccountName=" & sObject & "$));" & _
"aDSPath;subtree"
aResults = AD_Search_Array (sLDAPQuery)
If Ubound(aResults) = -1 Then
ADObject_Find_Generic = ""
Else
ADObject_Find_Generic = aResults(0)
End If
End Select
End Function
Function ADObject_NameType(ByVal sObjectName)
' Version 071204
' Evaluates sObjectName to determine what type of name it is
' Returns ADObject_NameType adspath
' distinguishedname
' name
' blank if sObjectName = ""
Dim sNameType
If Len(sObjectName) = 0 Then
sNameType = ""
ElseIf Len(sObjectName) < 3 Then
' can't be a DN or an ADsPath - must be a name
sNameType = "name"
ElseIf Ucase(Left(sObjectName,3)) = "CN=" Then
' is a DN
sNameType = "distinguishedname"
ElseIf Len(sObjectName) < 8 Then
' too short to be an ADsPath and isn't a DN, so it must be a name
sNameType = "name"
ElseIf UCase(Left(sObjectName, 7)) = "LDAP://" Then
' is already an ADsPath
sNameType = "adspath"
Else
' must be a name
sNameType = "name"
End If
ADObject_NameType = sNameType
End Function
Function ADObject_Validate(ByVal sObjectADsPath)
' Version 071122
' Returns ADsPath of object as a way of validating that the object exists
'
' INPUTS: sObjectADsPath ADsPath of object to test
' RETURNS: ADObject_Validate Path of object (if it exists) or blank
Dim oObject
On Error Resume Next
Set oObject = GetObject(sObjectADsPath)
If Err.Number <> 0 Then
ADObject_Validate = ""
Err
Turns out there are two answers to take note of in regard to "LDAP://" credentials.
First, specifically to the script I posted, I simply had to open my eyes!
Almost the last line of the script there were already options to add the credentials:
oConnection.Open "", vbNullString, vbNullString
Simply had to be correctly populated:
oConnection.Open "", "username", "password"
Second, a more general description was already provided by #Harvey Kwok in this SO answer: Secure LDAP object manipulation with VBscript using alternate credentials

Populate GPO from Text File using VBScript or other

Ok, so we need to create a GPO that allows our users to only use specific programs.
GPO Location:
User Configuration
Policies
Administrative Templates [...]
System
Run only specified Windows applications
Then setting the GPO to enabled and clicking on List of allowed applications --> Show...
I have created an excel spreadsheet containing the names of all the programs and their associated executable files with other pertinent information so that we can easily organize, add, delete, etc. the executable files that we need to allow our users access to.
This spreadsheet then dumps all the executable files into a text file.
Here is an example of what the text file looks like:
Acrobat.exe
chrome.exe
calc.exe
.
.
.
There are a lot of entries and these are likely subject to change. What I am trying to do is create a script that will take that text file and populate the GPO automatically. I don't care if we have to open the window and then run it, it does not need to run from the task scheduler (although that would be amazing if someone has that code ready). We just need it to populate this ridiculous amount of executable filenames into the fields.
Here is code I found (VBScript) that when run, should populate the fields automatically, however I cannot get it to run in the Group Policy Management Editor (it runs in the windows explorer window instead and ends up searching for some of the files)
' Open the text file, located in the same path as the script
Set objFSO = CreateObject("Scripting.FileSystemObject")
strPath = Mid(Wscript.ScriptFullName, 1, InStrRev(Wscript.ScriptFullName, wscript.ScriptName) -1)
Set objFile = objFSO.OpenTextFile(strPath & "appList.txt")
' Activate the "Show Contents" window with the "List of allowed applications".
' Note the window must be opened already and we should have selected where in
' the list we want to enter the data before running the script
set WshShell = WScript.CreateObject("WScript.Shell")
WScript.Sleep 1000
WshShell.AppActivate "Show Contents"
' Read the file line by line
Do While objFile.AtEndOfStream <> True
' Each line contains one EXE name
exeName = objFile.ReadLine
' Escape forbidden chars { } [ ] ( ) + ^ % ~
exeName = Replace(exeName, "[", "{[}")
exeName = Replace(exeName, "]", "{]}")
exeName = Replace(exeName, "(", "{(}")
exeName = Replace(exeName, ")", "{)}")
exeName = Replace(exeName, "+", "{+}")
exeName = Replace(exeName, "^", "{^}")
exeName = Replace(exeName, "%", "{%}")
exeName = Replace(exeName, "~", "{~}")
' Send the EXE name to the window
WScript.Sleep 100
WshShell.SendKeys exeName
' Move to the next one
WshShell.SendKeys "{TAB}"
Loop
objFile.Close
from: http://blogs.msdn.com/b/alejacma/archive/2011/03/24/how-to-update-quot-run-only-specified-windows-applications-quot-gpo-programmatically-vbscript.aspx
"C:\Windows\System32\GroupPolicy\User\Registry.pol"
Is where my policies are stored. It's a semi text file. Try writing to that file.
Ok, so I tried it many different ways. If anyone is looking for an answer to do this, this is the way I've figured it out and the way I've decided to proceed. I will post all relevant code below.
In Excel, the format of my table is as follows:
(With obviously WAY more entries)
Here is the VBA code I used to turn the data from this file into the proper format for the registry key:
VBA - In Excel
Public Sub ExportToTextFile(FName As String, _
Sep As String, SelectionOnly As Boolean, _
AppendData As Boolean)
Dim WholeLine As String
Dim FNum As Integer
Dim RowNdx As Long
Dim ColNdx As Integer
Dim StartRow As Long
Dim EndRow As Long
Dim StartCol As Integer
Dim EndCol As Integer
Dim CellValue As String
Application.ScreenUpdating = False
On Error GoTo EndMacro:
FNum = FreeFile
StartRow = 2
If SelectionOnly = True Then
With Selection
StartCol = .Cells(2).Column
EndRow = .Cells(.Cells.Count).Row
EndCol = .Cells(2).Column
End With
Else
With ActiveSheet.UsedRange
StartCol = .Cells(2).Column
EndRow = .Cells(.Cells.Count).Row
EndCol = .Cells(2).Column
End With
End If
If AppendData = True Then
Open FName For Append Access Write As #FNum
Else
Open FName For Output Access Write As #FNum
End If
For RowNdx = StartRow To EndRow
WholeLine = ""
For ColNdx = StartCol To EndCol
If Cells(RowNdx, ColNdx).Value = "" Then
CellValue = ""
Else
CellValue = Cells(RowNdx, ColNdx).Value
End If
WholeLine = WholeLine & Chr(34) & CellValue & ".exe" & Chr(34) & "=" & Chr(34) & CellValue & ".exe" & Chr(34) & Sep
Next ColNdx
WholeLine = Left(WholeLine, Len(WholeLine) - Len(Sep))
Print #FNum, WholeLine; ""
Next RowNdx
EndMacro:
On Error GoTo 0
Application.ScreenUpdating = True
Close #FNum
End Sub
Sub PipeExport()
Dim FileName As Variant
Dim Sep As String
FileName = Application.GetSaveAsFilename(InitialFileName:="appList", filefilter:="Text (*.txt),*.txt")
If FileName = False Then
''''''''''''''''''''''''''
' user cancelled, get out
''''''''''''''''''''''''''
Exit Sub
End If
Sep = "|"
If Sep = vbNullString Then
''''''''''''''''''''''''''
' user cancelled, get out
''''''''''''''''''''''''''
Exit Sub
End If
Debug.Print "FileName: " & FileName, "Extension: " & Sep
ExportToTextFile FName:=CStr(FileName), Sep:=CStr(Sep), _
SelectionOnly:=False, AppendData:=False
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
PipeExport
End Sub
The file that is created is appList.txt and its format is the same format as the registry key:
"Acrobat.exe"="Acrobat.exe"
"AcroRd32.exe"="AcroRd32.exe"
Now in your GPO, add a unique program name to the allowed applications list (say test1234.exe) and in your registry editor, go to Edit > Find test1234.exe.
Export that registry key under File > Export. Remove the test1234.exe line and paste in your text file. Then reimport that file and you're done!

Setting VBA to read personal inbox

trying to get some VBA code together to basically be able to run my rules from a button on my toolbar within outlook 2007. The following code runs the rules on my exchange server inbox, which is empty as everything moves to my "Personal Inbox". I just want to change the code below to read my personal inbox and not my exchange mailbox inbox. Have searched on the web and cant find my answer and hence my post -
Sub RunAllInboxRules()
Dim st As Outlook.Store
Dim myRules As Outlook.Rules
Dim rl As Outlook.Rule
Dim count As Integer
Dim ruleList As String
'On Error Resume Next
' get default store (where rules live)
Set st = Application.Session.DefaultStore
' get rules
Set myRules = st.GetRules
' iterate all the rules
For Each rl In myRules
' determine if it's an Inbox rule
If rl.RuleType = olRuleReceive Then
' if so, run it
rl.Execute ShowProgress:=True
count = count + 1
ruleList = ruleList & vbCrLf & rl.Name
End If
Next
' tell the user what you did
ruleList = "These rules were executed against the Inbox: " & vbCrLf & ruleList
MsgBox ruleList, vbInformation, "Macro: RunAllInboxRules"
Set rl = Nothing
Set st = Nothing
Set myRules = Nothing
End Sub
Try this. I have tested on my machine. This logs into the mailbox you are logged onto and runs the rules accordingly
Sub RunAllInboxRules()
Dim objOL As Outlook.Application
Dim st As Outlook.Store
Dim myRules As Outlook.Rules
Dim rl As Outlook.Rule
Dim count As Integer
Dim ruleList As String
Dim fldInbox As Object
Dim gnspNameSpace As Outlook.NameSpace
'On Error Resume Next
' get default store (where rules live)
'Logs into Outlook session
Set objOL = Outlook.Application
Set gnspNameSpace = objOL.GetNamespace("MAPI") 'Outlook Object
'Logs into the default Mailbox Inbox
'set the store to the mailbox
Set st = gnspNameSpace.GetDefaultFolder(olFolderInbox).Store
' get rules
Set myRules = st.GetRules
' iterate all the rules
For Each rl In myRules
' determine if it's an Inbox rule
If rl.RuleType = olRuleReceive Then
' if so, run it
rl.Execute ShowProgress:=True
count = count + 1
ruleList = ruleList & vbCrLf & rl.Name
End If
Next
' tell the user what you did
ruleList = "These rules were executed against the Inbox: " & vbCrLf & ruleList
MsgBox ruleList, vbInformation, "Macro: RunAllInboxRules"
Set rl = Nothing
Set st = Nothing
Set myRules = Nothing
End Sub

VBS Script for modifying multi-value Active Directory display specifier

Following the howto Extending the Active Directory Schema To Track Custom Info I'm able to setup a single-value schema attribute that is easily changeable via a context menu in ADUC. Multi-value schema attributes get considerably more complicated. Say (for the sake of argument) my value is "Projects" and each user may be a list as many projects as necessary.
Following is a sad little script that will set Project to a single value:
Dim oproject
Dim oUser1
Dim temp1
Set oproject = Wscript.Arguments
Set oUser1 = GetObject(oproject(0))
temp1 = InputBox("Project: " & oUser1.project & vbCRLF & vbCRLF & "Project")
if temp1 <> "" then oUser1.Put "project",temp1
oUser1.SetInfo
Set oUser1 = Nothing
Set oproject = Nothing
Set temp1 = Nothing
WScript.Quit
How can I modify this to allow, assign, and modify multiple values?
I gave up on an elegant UI and just went with the semicolon delimited list. Here's the code if anyone cares:
Dim objProject
Dim objUser
Dim temp1, title, message, default
Dim projects
title = "Projects"
Set objProject = Wscript.Arguments
Set objUser = GetObject(objProject(0))
'Find our current projects
projects = objUser.projects
If Not isArray(projects) Then
projects = Array(projects)
End If
'Setup our message box
message = "Semicolon-delimited list of Projects"
default = arrayToStr(projects)
temp1 = InputBox(message, title, default)
'catch cancels
if IsEmpty(temp1) Then
WScript.Quit
End If
' update our data
projects = strToArray(temp1)
objUser.Put "projects",projects
objUser.SetInfo
'Clean up and quit
Set projects = Nothing
Set objUser = Nothing
Set objProject = Nothing
Set temp1 = Nothing
Set title = Nothing
Set message = Nothing
Set default = Nothing
WScript.Quit
'Functions
Function strToArray(s)
Dim a
Dim token
' discard blank entries
For Each token in split(s, ";")
token = trim(token)
If token <> "" Then
If isEmpty(a) Then
a = token
Else
a = a & ";" & token
End If
End If
Next
' return array
strToArray = split(a, ";")
End Function
Function arrayToStr(a)
Dim s
Dim token
For Each token in a
If isEmpty(s) Then
s = token
Else
s = s & ";" & token
End If
Next
' return string
arrayToStr = s
End Function

Resources