CCIE #7742 Techblog

March 26, 2011

First Post

Filed under: Blog — Tags: — John McManus @ 2:23 am

Hi Everyone,

After the enjoyment I got out of blogging over at Etherealmind.com I decided that I would step out a little bit and give my own web presence.

Networking-Guru is not new, I had Networking Guru up and running in 2004, but never really knew what to do with it, so I just let it go, but kept the domain name registered. Now with the interaction from the networking community it seems a good time to bring it back.

When I started in Networking Guru in 2004 my goal was to share knowledge and that is still my primary goal.

I have included my old articles from the original Networking Guru which are a bit outdated, however for posterities sake I have added these as the first few posts.

 

March 4, 2009

Clone Active Directory User

Filed under: Uncategorized — John McManus @ 12:07 pm

In Active Directory it is possible to copy users using the Active Directory Users and Computers MMC. Based on this process we have the ability to setup template user accounts with the proper group membership, profile setting. There are many additional attributes that do not get copied across with this process.

Many customers maps users home drives during the logon script, and therefore this is not stored with the account information and cannot be copied during the copy user process.

Copying users in Active Directory does not present the administrator with pre-populated options following internal standards, instead the full name, description fields are completed at the administrator discretion, this flaw in the process does not help in anyway to encourage standard.

These limitations have driven many customers to create a process to fill the gaps in this default method, and encourage standard at the same time.

One option which was considered before writing the clone user script was to modified which attributes are copied using ADSI edit as specified in Microsoft KB article:

http://www.microsoft.com/technet/treeview/default.asp?url=/technet/prodtechnol/windowsserver2003/proddocs/entserver/DSAdminCopyUser.asp .

However this would not address the issues of home directory creation or encourage standards.

 

Script Summary
“CloneUser.vbs” is visual basic script developed on a Windows 2003 platform. The script has been tested on Windows 2003 servers, but will run from Windows XP clients and the Windows 2000 platform. The code uses standard LDAP and ADSI calls, the only exception is calls to mailbox properties which are only available if exchange extensions for Active Directory Users and Computer are installed on the computer where the script is being executed. The script makes use of the external program “CACLS.EXE” which is a standard operating system command on Windows 2000, Windows XP and Windows 2003.

 

The script can be run cscript CloneUser.vbs without any parameters.

Domain Controller: The code will then locate a local Domain Controller, otherwise a domain controller at random will be selected for use throughout the code to read and write information from the Active Directory.

TemplateSearch : The code will make a default search based on the Active Directory site the client is a member of. “zz_template*” 

Both these parameters can be specified on the command line if desired.

“cscript CloneUser.vbs /dc:DC001 /template:zz_template*”

The following is a walk through of all the major steps in the code.

Step 1 -              Command Line Parameters are determined, if values have been entered they will be used, otherwise the code calculates values for domain controller and template search string.
Step 2 -              A LDAP search is preformed to find user objects that match the search criteria.
Step 3 -              A list of templates is displayed and the user is prompted to choose a template to create a new user from.
Step 4 -              The new user basic details are requested
Step 5 -              The Active Directory is searched that this user does not already exist, if it does exist then we are prompted to adjust the users properties
Step 6 -              The user is created in the Active Directory, with the values entered in Step 4
Step 7 -              Attribute are copied from the template user to the newly created user:Step 8 -              The User Principal Name is set.
Step 9 -              The home directory is set based on the location of the home path for the template user. The home directory is physically created and the permissions are set so new user has full control of their home directory.

If there is no home path specified in the template user, then we assume the home directory is mapped in the logon script. The home directory is physically created on the same server as the profile and permissions are set so new user has full control of their home directory.

Step 10 -          The profile path is set based on the location of the profile path of the template user. The profile directory will be automatically configured once the users has logged on and off for the first time.
Step 11 -          Group membership is copied.
Step 12 -          If the template account is mailbox-enabled then the code will mailbox-enable the new user account.(Exchange extensions are required)
Step 13 -          The following is set : (Password set to Password1. Enable Account. Force users to change password at next logon.)
Step 14 -          Prompt to confirm
Step 15 -          Displays the created user and has the option to create another user.

 

Setup Template Account
Step 1 -              Logon to computer with permissions to create a user account.
Step 2 -              Start Active Directory User and Computers MMC.
Step 3 -              Navigate to the OU for where you want to create a template account.
Step 4 -              Right Click the mouse pointer on the OU and select New->User.
Step 5 -              Enter the following details: First Name = zz_template Last Name= <template description>
Full Name=<generated by default> !! Remove the space between First and Last Name
User logon name= Copy Full Name
User logon name(pre-Windows 2000) =  <generated by default from User Logon Name>

Tip: to Copy Full Name, select the text in Full Name, use <ctrl>-c to copy the text, put the cursor in the User Logon Name text box and use <ctrl>-v to past the text in.

Click Next

Step 6 -              Enter a password that meets secuirty standard.
Step 7 -              Check Account is disabled.
Step 8 -              Click Next
Step 9 -              If Exchange is installed you will be prompted to “Create an Exchange mailbox”. Un-Check this check box (do not create a mailbox).
Step 10 -          Click Next
Step 11 -          Click Finish

Setup Template Properties
Step 12 -          Right Click on newly create user and select Properties.
Step 13 -          On the General tab complete the following fields : Description = Office = Telephone number =
Step 14 -          Select the Address tab.
Step 15 -          On the Address Tab complete the following fields: Street = The address of the office.City = The city the office is in. State/Province = The state or province the office is in. Zip/Postal Code = The zip or postal code of the office. Country/Region = The country the office is in.

Step 16 -          Select the Profile tab.
Step 17 -          On the Profile tab complete the following fields:
Profile Path = The path to the profiles share on the local site. e.g. for Amsterdam \\FileServer\Profile$\%Username% always use %username%
Logon Script = the logon script name “Logon.Bat”

The home drive is mapped during the logon script, and the “CloneUser.vbs” script will create the home drive based on the profile path. We do not need to modify any setting associated with the home folder.

Step 18 -          Select the Telephones tab.
Step 19 -          On the Telephone tab complete the following fields:Home =Pager =Mobile =Fax = The Office default fax number.
Step 20 -          Select the Member Of tab.
Step 21 -          On the Member Of tab click Add, then add the user to the relevant list of groups.
Step 22 -          Click OK.
Step 23 -          The Template user is now ready for use.

 

 Option Explicit
'    Declare all Variables for main code
'
'
'Template Account should follow the following rules
'Firstname:zz_template_
'  e.g. zz_template_
'Lastname:background
'  e.g. default template'
'UPN(user logon name): Firtname+Lastname
'  e.g zz_template_default template
'samaccount name (pre windows 2000 logon) :firstname+zz_template_default template
'           (20 characters total)
'           
'profilepath:<servername>\sharename\%username% =samaccountname
'homepath:<servername>\sharename\%username% =samaccountname
'
'
Dim argv
Dim sDomainController
Dim sTemplateSearch
Dim NewUser
Dim ChosenUser
Dim answer
Dim strfname
Dim strlastname
Dim strdescription
Dim strdisplayname
Dim strname
Dim strcountry
Dim strinitial
Dim userexists
Dim ContinueMainLoop
Dim GetUserToCopyLoop

GetArgs sDomainController,sTemplateSearch
'Main Program Loop
ContinueMainLoop=True
While ContinueMainLoop
GetUserToCopyLoop=True
 While GetUsertoCopyLoop
 ' Get the user we want to use as a template
  set ChosenUser = GetUserToCopy(sDomainController,sTemplateSearch)
  wscript.echo "User Selected to Copy :" & ChosenUser.Get("distinguishedName")
  answer= DisplayUserDetails(ChosenUser, _
    "This is the template user selected" & vbCr & vblf, _
     vbCr & vblf & "Do you want to use this template?",vbYesNo)
  ' If we don't want to use the user then quit
  If answer=vbYes Then
      GetUserToCopyLoop=false
      'Get information about the new user we want to create
   'We need the country to set a default display name
   On Error Resume next
   Err.Clear
   strcountry=ChosenUser.Get("co")
   If (Err.Number <> 0 And Err.Number <> -2147463155) Then
    wscript.echo "An error has occured retrieving Country " &  Err.Number
    wscript.echo "Err Description: " & Err.Description
    Err.Clear
      End If
      strdescription=ChosenUser.Get("description")
   If (Err.Number <> 0 And Err.Number <> -2147463155) Then
    wscript.echo "An error has occured retrieving description " &  Err.Number
    wscript.echo "Err Description: " & Err.Description
    Err.Clear
      End If
      userexists=1
   While userexists=1
    GetNewUserDetails strfname,strlastname,strdescription,strdisplayname,strname, strcountry, strinitial
    userexists=finduser(sDomainController,strfname & strinitial & strlastname,strdisplayname)
    'Check the User doesnot already exist
    If userexists=1 Then
     If (MsgBox ("User " & vbCr & vbLf & strdisplayname  & vbCr & vbLf _
        & "Already Exists !!!" & vbCr & vbLf & _
         vbCr & vbLf & _
         "Try another username" & vbCr & vbLf _
         ,vbYesNo, "User Already Exists"))  = vbNo Then
       WScript.Quit(0)
      End if
    End if
   Wend
   ' Create a new AD users based on the information and the template
   set NewUser= CreateADUser (ChosenUser, sDomainController, strfname,strlastname,strdescription,strdisplayname,strname,strinitial)
   ' Copy Attributes from the Template
   CopyUserAttrib ChosenUser,NewUser, Array("streetAddress", _
                                    "Company", _
                                    "countryCode", _
                                    "c", _
                                    "department", _
                                    "facsimileTelephoneNumber", _
                                    "l", _
                                    "homePhone", _
                                    "info", _
                                    "mobile", _
                                    "pager", _
                                    "physicalDeliveryOfficeName", _
                                    "postOfficeBox", _
                                    "postalCode", _
                                    "st", _
                                    "telephoneNumber", _
                                    "co", _
                                    "title", _
                                    "scriptPath")
   ' Setup the UPN for the New user
   SetUPN Chosenuser,NewUser
   ' Setup the home directory for the new user
   SetupHomeDir ChosenUser,NewUser
   ' Setup the profile path for the new user
   SetupprofilePath Chosenuser,NewUser
   ' Setup the group membership
   SetupGroupMembership Chosenuser,NewUser ,sDomainController
   'Setup MailBox Enable the Account (only if the template user has an exchange mailbox
   EnableMailBoxRecipient ChosenUser,NewUser
   'Finalise Account
   FinaliseAccount NewUser
   
   ' Check Phone Numbers
   CheckPhoneNumbers NewUser
   
   'Display the user that has been created
   answer= DisplayUserDetails(NewUser,"This is the user that has been created" & vbCr & vblf, _
    "Do you want to create another user ?" &vbCr & vblf ,vbYesNo)
   If answer<>vbYes Then
    ContinueMainLoop=False
   Else
    ContinueMainLoop=True
   End If
  End If
 Wend
 
wend
Sub PrintUsage
   wscript.echo "Usage: cscript CloneUser.wsf /templates:<template search string> /dc:<domain controller>"
   wscript.echo "e.g. cscript CloneUser.wsf /templates:zz_template /dc:dc001"
   wscript.echo Now()
   wscript.quit(0)
End Sub
Function GetArgValue(argName, args())
    Dim a
    Dim v
    Dim iLenArgName
    Dim x
    Dim iArgCount
    Dim fullArgName
    fullArgName = "/" & argName & ":"
    iArgCount = Ubound(args)
    ' Get the length of the argname we are looking for
    iLenArgName = Len(fullArgName)
    GetArgValue = "" ' default to nothing
   
    For x = 0 To iArgCount
        If Len(args(x)) >= iLenArgName Then
            a = Mid(args(x), 1, iLenArgName)
            If UCase(a) = UCase(fullArgName) Then
                ' erase it so we can look for unknown args later
                v = args(x)
                args(x) = ""
                If Len(v) > iLenArgName Then
                    GetArgValue = Mid(v, iLenArgName + 1)
                    Exit Function
                Else
                    GetArgValue = ""
                    Exit Function
                End If
            End If
        End If
    Next
End Function
Function CheckForBadArgs(args())
 Dim I
    For i = 0 to UBound(args)
        If Len(args(i)) > 0 Then
            CheckForBadArgs = 1
            Exit Function
        End If
    Next
    CheckForBadArgs = 0
End Function
 
 
Function GetUserToCopy (DC,SearchFor)
 
 Dim oConn  'Connection object for ldap queries
 Dim oCmd  'Command object for ldap queries
 Dim sQuery  'Query string for ldap
 Dim oRecordset  'AD objects recordset
 Dim oRecipient  'Recipient object
 Dim strsAMAccountName   'sam account name
 Dim strExchAlias        'exchange alias name
 Dim i
 Dim choices
 Dim ChosenUser
 GetUserToCopy=""
 
 ' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdaexamples_vbscript01_6.asp 
 ' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/searching_with_activex_data_objects_ado.asp
 ' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/vbsProcedures.asp
 'Build an array of AD Users.
 'Use LDAP to pull the information.
 '
 'Set up ADSI for AD.
 '
 Set oConn = wScript.CreateObject("ADODB.Connection")
 oConn.Provider = "ADSDSOObject"
 oConn.Open "Active Directory Provider"
 Set oCmd = wScript.CreateObject("ADODB.Command")
 '
 ' Search for all matching recipients as per constants defined above.
 '
 sQuery = "<LDAP://" & DC  &  _
          ">;(&(objectClass=User)(cn="& SearchFor & "))"& _
   ";sAMAccountName,UserPrincipalName,givenName,sn,cn,distinguishedName,description;subtree"
'          ">;(& (objectClass=User) | (cn="& SearchFor & ")(UserPrincipalName=" & SearchFor & ")(samaccountname=" & SearchFor & ")(Name=" & SearchFor & "))"& _
'   ";sAMAccountName,UserPrincipalName,givenName,sn,cn,distinguishedName,description;subtree"
 
 wscript.echo
 wscript.echo "LDAP Query being Run:" & sQuery
 wscript.echo
 
 Set oCmd.ActiveConnection = oConn
 oCmd.CommandText = sQuery
 oCmd.Properties("Page Size") = 1000
 Set oRecordset = CreateObject("ADODB.RecordSet")
 on error resume next
 Set oRecordset = oCmd.Execute()
 If Err.Number <> 0 Then
    wscript.echo "The could not find the template begining With (" & sTemplateSearch & ")"
    wscript.echo "                         On Domain Controller (" & DC & ")"
    wscript.echo "Error #: " & Err.Number
    wscript.echo "Error  : " & Err.Description
    Err.Clear
    WScript.Quit(0)
 End If
 
 On Error GoTo 0 
 '
 ' Loop through recipients matched.
 '
 if oRecordSet.RecordCount=0 then
     wscript.echo "The could not find the template begining With (" & sTemplateSearch & ")"
     wscript.quit(0)
 end if
 wscript.echo "The Query has returned  : (" & oRecordSet.RecordCount & ") records"
 i=0
 ChosenUser=""
 choices=""
 On Error Resume next
 While Not oRecordset.EOF
  'Loop through all user accounts
  i=i+1
  choices=choices & vbCr & vbLf
  choices=choices & i & ". "
  choices=choices & oRecordset("givenName").Value
  choices=choices & " " & oRecordset("sn").Value
  choices=choices & " " & oRecordset("description").Value
  oRecordset.MoveNext
 Wend
 On Error goto 0
 choices=choices & vbCr & vbLF
 
 While ChosenUser=""
 ChosenUser = InputBox(choices,"Select a template to use?","1")
 If ChosenUser<>"" then
  If (cint(ChosenUser)<1 Or cint(ChosenUser) >i)   Then
   ChosenUser=""
   wscript.echo "Invalid Choice"
  End If
 Else
  wscript.echo "Quitting Program"
  WScript.Quit(0)
 End If
 wend
 oRecordset.MoveFirst
 oRecordset.Move(cint(ChosenUser)-1)
 ' Get the user template we will use top copy the details of
 set GetUserToCopy = GetObject("LDAP://" & DC & "/" & oRecordset("distinguishedName").Value)
End Function
Function DisplayUserDetails(OUser,PreText,PostText,vbButtons)
'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/vbsProcedures.asp
'Dim OUser
Dim DisplayText
'Set oUser = GetObject("LDAP://" & DC & "/" & UserDN)
On Error Resume next
With oUser
.GetInfo
DisplayText=PreText  & vbCr & vbLf
DisplayText=DisplayText & vbCr & vbLf & "First Name  : "
DisplayText=DisplayText & .Get("givenName") 
DisplayText=DisplayText &  vbCr & vbLf & "Last Name  : "
DisplayText=DisplayText & .Get("sn")
DisplayText=DisplayText &  vbCr & vbLf & "Initial   : "
DisplayText=DisplayText & .Get("initials")
DisplayText=DisplayText &  vbCr & vbLf & "Display Name  : "
DisplayText=DisplayText & .Get("Name")
DisplayText=DisplayText &  vbCr & vbLf & "Description  : "
DisplayText=DisplayText & .Get("description")
DisplayText=DisplayText &  vbCr & vbLf & "SAM Account Name  : "
DisplayText=DisplayText & .Get("sAMAccountName")
DisplayText=DisplayText &  vbCr & vbLf & "UPN   : "
DisplayText=DisplayText & .Get("userPrincipalName")
DisplayText=DisplayText &  vbCr & vbLf
DisplayText=DisplayText & "Address : " & vbCr & vbLf
DisplayText=DisplayText &  .Get("streetAddress")
DisplayText=DisplayText &  vbCr & vbLf
DisplayText=DisplayText &  vbCr & vbLf & "ZIP/PostCode  : "
DisplayText=DisplayText & .Get("postalCode")
DisplayText=DisplayText &  vbCr & vbLf & "State/Provence  : "
DisplayText=DisplayText & .Get("st")
DisplayText=DisplayText &  vbCr & vbLf & "Country   : "
DisplayText=DisplayText & .Get("co")
DisplayText=DisplayText &  vbCr & vbLf & "Telephone  : "
DisplayText=DisplayText & .Get("telephoneNumber")
DisplayText=DisplayText &  vbCr & vbLf & "Fax   : "
DisplayText=DisplayText & .Get("facsimileTelephoneNumber")
DisplayText=DisplayText &  vbCr & vbLf & "Pager   : "
DisplayText=DisplayText & .Get("pager")
DisplayText=DisplayText &  vbCr & vbLf & "Title   : "
DisplayText=DisplayText & .Get("Title")
DisplayText=DisplayText &  vbCr & vbLf
DisplayText=DisplayText &  vbCr & vbLf
DisplayText=DisplayText &  vbCr & vbLf & "Home Directory : "
DisplayText=DisplayText & .Get("homeDirectory")
DisplayText=DisplayText &  vbCr & vbLf & "Home Drive : "
DisplayText=DisplayText & .Get("homeDrive")
DisplayText=DisplayText &  vbCr & vbLf & "Logon Script : "
DisplayText=DisplayText & .Get("scriptPath")
DisplayText=DisplayText &  vbCr & vbLf & "Profile Path : "
DisplayText=DisplayText & .Get("profilePath")
DisplayText=DisplayText &  vbCr & vbLf & "Exch Home Srv : "
DisplayText=DisplayText & .Get("msExchHomeServerName")
DisplayText=DisplayText &  vbCr & vbLf &  vbCr & vbLf & PostText

End With
On Error goto 0
DisplayUserDetails=MsgBox(DisplayText,vbYesNo,"Display User Details")

End Function
Sub GetNewUserDetails(strfname,strlname,strdescription,strdisplayname,strname, _
   strcountry,strinitial)
'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/vbsProcedures.asp
strfname = InputBox("Enter First Name","Get Info",strfname)
strlastname = InputBox("Enter Last Name","Get Info",strlname)
strinitial =InputBox("Enter Initials","Get Info",strinitial)
strdisplayname= strlname & ", " & strfname & " ("& strcountry &")"
strdisplayname = InputBox("Enter Display Name","Get Info",strdisplayname)
strname = strfname & strinitial & strlname
strname = InputBox("Logon Name","Get Info",strname)
strdescription = InputBox("Enter Description","Get Info",strdescription)

End sub
        
'CheckPhoneNumbers NewUser
Sub CheckPhoneNumbers(NewUser)
'"Company", _
'"c","department","facsimileTelephoneNumber", "l", _
'"homePhone", "info", "mobile", "pager", "physicalDeliveryOfficeName", _
'telephoneNumber","title", _
'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp
 On Error Resume Next
 Dim Temp
 temp=""
 temp= NewUser.Get("telephoneNumber")
 temp = InputBox("Enter Phone number","Get Info",temp)
 NewUser.Put "telephoneNumber",temp
 NewUser.SetInfo
'
 temp=""
 temp= NewUser.Get("facsimileTelephoneNumber")
 temp = InputBox("Enter Fax number","Get Info",temp)
 NewUser.Put "facsimileTelephoneNumber",temp
 NewUser.SetInfo
'
 temp=""
 temp= NewUser.Get("pager")
 temp = InputBox("Enter pager number","Get Info",temp)
 NewUser.Put "pager",temp
 NewUser.SetInfo
'
 temp=""
 temp= NewUser.Get("title")
 temp = InputBox("Enter Title","Get Info",temp)
 NewUser.Put "title",temp
 NewUser.SetInfo

On Error Goto 0
End sub

Function finduser(dc,strname,strdisplayname)
 on error resume Next
 Err.Clear
 finduser=0
 Dim oConn
 Dim oCmd
 Dim sQuery
 Dim orecordSet
 Set oConn = wScript.CreateObject("ADODB.Connection")
 oConn.Provider = "ADSDSOObject"
 oConn.Open "Active Directory Provider"
 Set oCmd = wScript.CreateObject("ADODB.Command")
 '
 ' Search for all matching recipients as per constants defined above.
 '
 sQuery = "<LDAP://" & DC  &  _
          ">;(&(objectClass=User)(|(UserPrincipalName="& strname & "@*)(displayName="& strdisplayname &")))"& _
   ";givenName,sn,cn,distinguishedName;subtree"
 wscript.echo
 wscript.echo "LDAP Query being Run:" & sQuery
 wscript.echo
 
 Set oCmd.ActiveConnection = oConn
 oCmd.CommandText = sQuery
 oCmd.Properties("Page Size") = 1000
 Set oRecordset = CreateObject("ADODB.RecordSet")
 Set oRecordset = oCmd.Execute()
 If Err.Number <> 0 Then
    wscript.echo "Error searching for user (" & strname & ")"
    wscript.echo "                         On Domain Controller (" & DC & ")"
    wscript.echo "Error #: " & Err.Number
    wscript.echo "Error  : " & Err.Description
    Err.Clear
    WScript.Quit(0) 
 End If
 
 On Error GoTo 0 
 '
 ' Loop through recipients matched.
 '
 if oRecordSet.RecordCount>0 then
     finduser=1  
     wscript.echo "User Alredy exists (" & strname & ")"
 end if
End Function

Function CreateADUser (objTemplateUser, dc, strfname,strlname,strdescription,strdisplayname,strname,strintial)
'The following code example creates a user account with the default attributes.
'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp
 Dim ou
 Dim strou
 Dim dname
 strou=objTemplateUser.Get("distinguishedname")
 strou=Right(strou,len(strou)-InStr(strou,","))
 wscript.echo strou
 'Do our own error checking here.
 On Error Resume Next
 Err.Clear
 
' dname="cn=" & strlname & "\" & Hex(Asc(",")) &  " " & strfname
 ' need to use dislpay name
 dname="cn=" & strdisplayname
 dname=Replace(dname, "," ,"\" & Hex(Asc(",")))
 'need to use \ escape sequence to use , in directory name
 Set ou = GetObject("LDAP://" & strou)
 
 wscript.echo "dname:" & dname
 Set CreateADUser = ou.Create("user", dname)
 CreateADUser.SetInfo
 If (Err.Number <> 0) Then
  wscript.echo "An error has occurred creating the user: " &  Err.Number
  wscript.echo "Err Description: " & Err.Description
  wscript.echo "Try Again Adding (Initial) to the Display Name"
  WScript.Quit(0)
    End If
 

 With CreateADUser
  wscript.echo "adding samAccountName: "
  wscript.echo  left(strname,20)
  .Put "samAccountName", left(strname,20)
  .SetInfo
  If (Err.Number <> 0 and Err.Number <> -2147463160) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
  wscript.echo "adding fullname: "
  wscript.echo strdisplayname
  .put "displayName", strdisplayname
  .SetInfo
  If (Err.Number <> 0 and Err.Number <> -2147463160) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
  wscript.echo "adding firstname: "
  wscript.echo  strfname
  .put "givenName", strfname
  .SetInfo
  If (Err.Number <> 0 and Err.Number <> -2147463160) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
  wscript.echo "adding initials: "
  wscript.echo  strinitial
  .put "initials" ,strinitial
  .SetInfo
  If (Err.Number <> 0 and Err.Number <> -2147463160) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
  wscript.echo "adding lastnamename: "
  wscript.echo  strlname
  .put "sn", strlname
  .SetInfo
  If (Err.Number <> 0 and Err.Number <> -2147463160) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
  wscript.echo "adding description: "
  wscript.echo  strdescription
  .put "description", strdescription
  .setinfo
  '-2147463160 = trying to set to a null value
  If (Err.Number <> 0 and Err.Number <> -2147463160) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
 End With
 Set ou = Nothing
    Set usr = Nothing
 On Error Goto 0
End Function
Sub CopyUserAttrib(FromUser,ToUser,Attribs)
 'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp
 On Error Resume Next
 Err.Clear
 Dim strAttribute
 For Each strAttribute In Attribs
  If Not IsNull(FromUser.Get(strAttribute)) Then
   wscript.echo "Copying Attrib: " & strAttribute
   ToUser.Put strAttribute, FromUser.Get(strAttribute)
   Touser.Setinfo
   If (Err.Number <> 0 And Err.Number <> -2147463155) Then
    wscript.echo "An error has occured copying the attribute " &  Err.Number
    wscript.echo "Err Description: " & Err.Description
    Err.Clear
      End If
     End if
 Next

End Sub
sub SetupHomeDir (ChosenUser,NewUser)
 'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp
 'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/wscondrivingapplications.asp
 On Error Resume Next
 Err.Clear
 Dim NewHomeDir
 Dim fso,wshshell,fldUserHomedir, cmdline
 NewHomeDir=""
 NewHomeDir= Replace(ucase(ChosenUser.Get("homeDirectory")),ucase(ChosenUser.Get("sAMAccountName")),NewUser.Get("sAMAccountName"),vbTextCompare)
 If NewHomeDir<>"" then
  wscript.echo "NewHomeDir: " & NewHomeDir
  NewUser.Put "homeDirectory", NewHomeDir
  NewUser.Put "homeDrive", ChosenUser.Get("homeDrive")
  NewUser.Setinfo
  If (Err.Number <> 0) Then
   wscript.echo "Error Setting Home Drive Paramaters " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
    End If
   Else
    ' Home drive has not been set so assume that it is being mapped in the logon script
    ' Create directory for logon script to mapto based on profile path.
    NewHomeDir= Replace(ucase(ChosenUser.Get("profilePath")),ucase(ChosenUser.Get("sAMAccountName")),NewUser.Get("sAMAccountName"),vbTextCompare)
    NewHomeDir= Replace(NewHomeDir,"PROFILE","HOME",vbTextCompare)
 End If
 If NewHomeDir<>"" Then
  Err.Clear
  'Physically create home drive
  'Create the home directory.
  Set fso = CreateObject("Scripting.FileSystemObject")
  If Not fso.FolderExists(NewHomeDir) Then
   Set fldUserHomedir = fso.CreateFolder(NewHomeDir)
  End If
  Set wshShell = WScript.CreateObject("Wscript.Shell")
  cmdline="cacls " & NewHomeDir & " /e /g " & NewUser.Get("userPrincipalName") & ":F"
  wscript.echo "CMD=" & cmdline
  wshShell.Run cmdline, 1, True
  If (Err.Number <> 0) Then
   wscript.echo "Error Creating Home Drive  " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
    End If
   
  
 End If
 On Error goto 0
End Sub
sub SetupprofilePath (ChosenUser,NewUser)
 'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp 
 On Error Resume Next
 Err.Clear
 Dim NewprofilePath
 NewprofilePath= Replace(ucase(ChosenUser.Get("profilePath")),ucase(ChosenUser.Get("sAMAccountName")),NewUser.Get("sAMAccountName"),vbTextCompare)
 wscript.echo "profilePath: " & NewprofilePath
 NewUser.Put "profilePath", NewprofilePath
 NewUser.Setinfo
 If (Err.Number <> 0) Then
   wscript.echo "An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
    End If
    On Error Goto 0
End Sub
Sub SetUPN (ChosenUser,NewUser)
 'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp
 'Setup the UsersPrincipalName base on First&LastName
 Dim OldName
 Dim NewName
 On Error Resume Next
 Err.Clear
 Dim NewUPN
 OldName=ucase(ChosenUser.Get("givenName")& ChosenUser.Get("sn"))
 ' if no initials exist then the following line will fail so oldname = firstname+lastname
 OldName=ucase(ChosenUser.Get("givenName")& ChosenUser.Get("Initials") & ChosenUser.Get("sn"))
 wscript.echo "Old: " & OldName
 NewName=NewUser.Get("givenName")& NewUser.Get("sn")
 ' if no initials exist then the following line will fail so newname = firstname+lastname
 NewName=NewUser.Get("givenName")& NewUser.Get("Initials") & NewUser.Get("sn")
 wscript.echo "New: " & NewName
 wscript.echo "TemplateUPN: " & Replace(ucase(ChosenUser.Get("userPrincipalName")))
 Err.Clear
 'Clear any errors from above
 NewUPN= Replace(ucase(ChosenUser.Get("userPrincipalName")),OldName,NewName)
 wscript.echo "NewUPN: " & NewUPN
 NewUser.Put "userPrincipalName", NewUPN
 NewUser.Setinfo
 If (Err.Number <> 0) Then
   wscript.echo "SetUPN:An error has occured setting the property " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
    End If
    On Error Goto 0
End sub

Sub SetupGroupMembership (Chosenuser,NewUser,dc)
 'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/iads.asp
 Dim arrMembers
 Dim member
 Dim CurrentGroup
 On Error Resume Next
 Err.Clear

 arrMembers = Chosenuser.GetEx("memberOf")
 For Each member In arrMembers
  wscript.echo member
  Set CurrentGroup=GetObject("LDAP://" & dc & "/" & member)
  CurrentGroup.Add("LDAP://" & NewUser.Get("distinguishedname"))
  CurrentGroup.SetInfo
  If (Err.Number <> 0) Then
   wscript.echo "An error has occured adding user to the group " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
  Set CurrentGroup= Nothing
 Next
 
On Error Goto 0
End Sub
Sub EnableMailBoxRecipient(ChosenUser,NewUser)
' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_cdo_creating_a_mailbox_enabled_recipient.asp
 On Error Resume Next
 Dim HomeMDB
 Err.Clear
 HomeMDB=""
 HomeMDB=ChosenUser.HomeMDB
 If HomeMDB <>  "" Then
   wscript.echo "Template Has a Mailbox: " & HomeMDB
   wscript.echo "MailBox Enabling New User"
  NewUser.CreateMailbox "LDAP://" & HomeMDB
   NewUser.SetInfo
  If (Err.Number <> 0) Then
   wscript.echo "An error has occured MailBox Enabling user" &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
     End If
    Else
   wscript.echo "Template Does not have a Mailbox."
   wscript.echo "****** No Mailbox Created ******"
     
  End if
 On Error Goto 0
End Sub
Sub FinaliseAccount(NewUser)
 On Error Resume Next
 Err.Clear
 NewUser.SetPassword "Password1"
 NewUser.AccountDisabled = False
 ' Set the pwdLastSet property to zero, which forces the
 ' user to change the password at next log on.
 NewUser.Put "pwdLastSet", 0
 NewUser.SetInfo
 If (Err.Number <> 0) Then
   wscript.echo "An error has occured finalising the account " &  Err.Number
   wscript.echo "Err Description: " & Err.Description
   Err.Clear
    End If
End Sub
Sub GetArgs(sDomainController,sTemplateSearch)
 Dim sys
 Set sys = CreateObject("ADSystemInfo")
 Dim args()
 ReDim args(0)
 args(0) = ""
 Dim i
 For i = 0 to wscript.arguments.count - 1
     ReDim Preserve args(i)
     args(i) = wscript.arguments.item(i)
 Next
 sTemplateSearch   = GetArgValue("templates",   args)
 If sTemplateSearch ="" Then
     sTemplateSearch="zz_template*"
     wscript.echo "No template entered will search based on :" & sTemplateSearch
 End If
 sDomainController = GetArgValue("dc",   args)
 If sDomainController="" Then
  sDomainController=sys.GetAnyDCName()
     wscript.echo "No dc entered will use:" & sDomainController
 End if
 If CheckForBadArgs(args) Then
     wscript.echo "Unknown command-line arguments specified"
     PrintUsage
 End If
End sub

Connect to the nearest printer

Filed under: Uncategorized — John McManus @ 11:22 am

again some old code I have written that need airing.

Have you ever wanted to have users automatically connect to the printer nearest the workstation they are logging into. We here is how it is done.

  • Create a printer queue(daqueue) on printserver (pserver)
  • Create a global group prt_daqueue_pserver
  • Add the workstation accounts which are closest to the printer (daqueue).
  • Now use the following sub in a users start-up script and hey presto the printer is mapped.
 
'*******************************************************************************************
'*
'*
'* Purpose: Connect user to a networked printer depending on the machines Global Group membership
'*
'* if the machine is a member of a group beginning with prt the subroutine
'* extract the servername and printername from the group name and attempt to
'* connect to the printer.
'*
'* Therefore to add a printer to a machine, simply add the machine to the printers group
'* If the user set a default printer, this will remain the default.
'* this has not been tested on roaming profiles/
'* group format = prt_printername_servername
'* NB: the printer and server name cannot include _
'*
'*******************************************************************************************
'on error resume Next 'Ignore any error and continue ( when debugging comment this line out)
'* Declare variables
Dim objWSHNetwork 'Network object for connecting to printers
Dim objComputer 'local computer object which has group membership
Dim objMember 'group membership
Dim strComputerName 'The local computername
Dim strObjPath 'The object path of the computer in the directory
Dim strPrinter 'Printer name
Dim strPrintServer 'Printserver name
Dim strConnectString 'Connection String
Dim strEventLogText 'Eventlog text
Set objSysInfo = CreateObject("ADSystemInfo")
Set objWSHShell = WScript.CreateObject("WScript.Shell")
strComputerName = objSysInfo.ComputerName 'Get the DN of this computer
strObjPath = "LDAP://" & strComputerName 'Get the Object Path of this computer in the directory
Set objComputer = GetObject(strObjPath) 'Setup the computer object from the directory
Set objWSHNetwork = CreateObject("WScript.Network") 'Setup the network object ready to add printers
For Each objMember In objComputer.Groups 'Enumerate all the group this computer is a member of
 if left(lcase(objMember.Name),6)="cn=prt" Then ' test group to see if it is a printer setting
  strPrinter=""
  'The next three lines extract the printername and printservername from the global group name
  strPrinter=right(objMember.Name,len(objMember.Name)-7)
  strPrinter=left(strPrinter,InStr(1,strPrinter,"_")-1)
  strPrintServer=right(objMember.Name,(len(objMember.Name)-len(strPrinter))-8)
  strConnectString="\\"& strPrintServer & "\" & strPrinter 'build the connection string
  objWSHNetwork.AddWindowsPrinterConnection strConnectString 'connect the network printer
  strEventLogText="ConnectNetworkPrinter: Connecting " & strConnectString 'Create eventlog text
  objWSHShell.LogEvent 4, strEventLogText 'log and event showing which printer has been added
 End If
Next
Set objComputer = Nothing 'deallocate the computer object
Set objWSHNetwork = Nothing 'deallocate the network object
 
 
 
 

Create a printer queue(daqueue) on printserver (pserver)
Create a global group prt_daqueue_pserver
Add the workstation accounts which are closest to the printer (daqueue).
Now use the following sub in a users start-up script and hey presto the printer is mapped.

Set Nearest ISA Server

Filed under: Uncategorized — Tags: — John McManus @ 11:00 am

I wrote this years ago but I removed my old web site so it was no longer available. although is it based on ISA 2004 I am sure it can be easily update to the more recent versions.

 

I use a cmd file to call the vbscript and put all files in the “c:\Program Files\Microsoft Firewall Client 2004\” Directory

Last update  27thOct05

 

SetISAServer.cmd

cscript //NoLogo “C:\Program Files\Microsoft Firewall Client 2004\SetISAServer.vbs” server1.networking-guru.net server2.networking-guru.net

 

 

The following code does

  • standard ping test to see if the ISA servers (passed as arguments) is alive and evaluate two response times
  • Set the quickest response as the preferred ISA server in the firewall client using the firewall client tool. Available from Microsoft (MS Download)
  • Verifies ISA server is operational using firewall client tool.

I haven’t been able to full test the pingserver functionality of the FWCTOOL.

I would think it is only compatible with windows xp and above due to the use of Win32_PingStatus

 

 

SetISAServer.vbs

'==========================================================================
'
'
' NAME: SetISAServer
'
' AUTHOR: Guru , Networking-Guru.net
' DATE : 26/10/2005
'
' beta 1 release - initial release
'beta 2 release 27/10:2005 12:01 BST - updated fwctool pingserver should now work
'==========================================================================
Dim FWServer1
Dim FWServer2
Dim FWServer1ResponseTime
Dim FWServer2ResponseTime
Dim PreferedFWServer
Dim objShell
Dim returncode
FWServer1=Wscript.Arguments(0)
FWServer2=Wscript.Arguments(1)
wscript.echo "Info: Server1=" & FWServer1
wscript.echo "Info: Server2=" & FWServer2
FWServer1ResponseTime = 0
FWServer2ResponseTime = 0
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPings = objWMIService.ExecQuery _
("Select * From Win32_PingStatus where Address = " & "'" & FWServer1 & "'")
' Ping Server 1 and get response time
For Each objStatus in colPings
If IsNull(objStatus.StatusCode) or objStatus.StatusCode<>0 Then
FWServer1ResponseTime = 99999999
Else
FWServer1ResponseTime = objStatus.ResponseTime
End If
Next
' Ping Server 1 again and get response time
Set colPings = objWMIService.ExecQuery _
("Select * From Win32_PingStatus where Address = " & "'" & FWServer1 & "'")
For Each objStatus in colPings
If IsNull(objStatus.StatusCode) or objStatus.StatusCode<>0 Then
FWServer1ResponseTime=FWServer1ResponseTime + 99999999
Else
FWServer1ResponseTime= FWServer1ResponseTime + objStatus.ResponseTime
End If
Next
' Calculate average Response Time
FWServer1ResponseTime= FWServer1ResponseTime /2
' Ping Server 2 and get response time
Set colPings = objWMIService.ExecQuery _
("Select * From Win32_PingStatus where Address = " & "'" & FWServer2 & "'")
For Each objStatus in colPings
If IsNull(objStatus.StatusCode) or objStatus.StatusCode<>0 Then
FWServer2ResponseTime = 99999999
Else
FWServer2ResponseTime = objStatus.ResponseTime
End If
Next
' Ping Server 2 again and get response time
Set colPings = objWMIService.ExecQuery _
("Select * From Win32_PingStatus where Address = " & "'" & FWServer2 & "'")
For Each objStatus in colPings
If IsNull(objStatus.StatusCode) or objStatus.StatusCode<>0 Then
FWServer2ResponseTime = FWServer2ResponseTime + 99999999
Else
FWServer2ResponseTime = FWServer2ResponseTime + objStatus.ResponseTime
End If
Next
' Calculate average Response Time
FWServer2ResponseTime = FWServer2ResponseTime/2
If FWServer1ResponseTime = 99999999 AND FWServer2ResponseTime = 99999999 then
' both ISA servers are unreachable do nothing
Wscript.Echo "Failure: ISA Servers unreachable"
wscript.quit(0)
elseif FWServer1ResponseTime=FWServer2ResponseTime then
' both ISA servers have the same response time, choose one at random
PreferedFWServer=FWServer1
elseif FWServer1ResponseTime<FWServer2ResponseTime then
PreferedFWServer=FWServer1
AlternateFWServer=FWServer2
else
' by elimination FWServer2 must be quicker
PreferedFWServer=FWServer2
AlternateFWServer=FWServer1
end if
wscript.echo "Info:" & FWServer1 & " AvgResponse=" & FWServer1ResponseTime
wscript.echo "Info:" & FWServer2 & " AvgResponse=" & FWServer2ResponseTime
wscript.echo "Info: PreferedServer =" & PreferedFWServer
Set objShell = WScript.CreateObject("WScript.Shell")
returncode=0
' Set the Prefered Server
cmdline = """C:\Program Files\Microsoft Firewall Client 2004\FwcTool.exe""" & " SetManualServer /Server:" & PreferedFWServer
wscript.echo "Info:" & cmdline
returncode = objShell.Run (cmdline,0,true)
wscript.echo "Info: ReturnCode=" & returncode
'Check that ISA Firewall Accessable is running on the desired server
cmdline = """C:\Program Files\Microsoft Firewall Client 2004\FwcTool.exe""" & " PingServer"
wscript.echo "Info:" & cmdline
returncode = objShell.Run (cmdline,0 ,true)
wscript.echo "Info: ReturnCode=" & returncode
if returncode <> 0 then
wscript.echo "Failure:" & PreferedFWServer & " ISA Server is unavailable"
' The Prefered Server has failed so let try the alternate
returncode=0
cmdline = """C:\Program Files\Microsoft Firewall Client 2004\FwcTool.exe""" & " SetManualServer /Server:" & AlternateFWServer
wscript.echo "Info:" & cmdline
returncode = objShell.Run (cmdline,0,true)
wscript.echo "Info: ReturnCode=" & returncode
if returncode <> 0 then
wscript.echo "Failure:" & AlternateFWServer & " ISA Server is unavailable"
wscript.echo "Failure: Both Server are unavailable"
else
wscript.echo "Success:" & AlternateFWServer & " ISA Server is operational"
End if
Else
wscript.echo "Success:" & PreferedFWServer & " ISA Server is operational"
End if

January 22, 2009

Calculate Full Mesh

Filed under: Uncategorized — John McManus @ 11:15 am

To workout how many point to point connections are required to create a full mesh network e.g. in Frame Relay. Then use the following formula

n=nodes.
Point to Point connections = n x (n-1)/2

so for a 5 node network
5×4=20 divided by 2 = 10

December 15, 2008

Duplexing Still Causing Issues?

Filed under: Uncategorized — Tags: — John McManus @ 9:10 am

Recently I came across an issue on a customer location where the connection between the router and the switch had a duplexing mismatch. One side was configured as 100 Full and the other end was Auto/Auto. As a result the Auto/Auto auto configured for 100/Half. Now this location had been running for months without issue, so why all of a sudden did it start having problems? There is no doubt that the configurations had not been changed in a long time.

Firstly the site had multiple routers running GLBP, therefore it is possible that the router in question was not being used, and for what ever reason now some PC were deciding to use this router. Certainly one thing I noticed on this router with the duplex problem is that ‘show glbp brief” was in ‘init’ state for some groups and had ‘unkown’ in some ‘active’ and ‘standby’ columns. There was nothing glaringly obvious with the GLBP config, it was just in an inconsistent state (I didn’t have access to the running config). The logs did not show any significant events which would point to a duplexing error.

What I should also mention the data problem being reported was files copied across the network were being corrupted for a few users.

After more investigation the provider found that their router’s fast Ethernet interface was clocking up errors then, it became obvious that the duplexing was mismatched.

It may be worth doing a standard check on all devices for interfaces with running at 100/half, I do not ever recall having 100mb connection which would run half duplex only ever 100 full. Maybe during the initial progression from 10/half to 100/full there were switches/repeaters which ran 100/half.

So this raises the question; When should I manually set port speed and duplex setting and when should I use Automatic negotiation?

First let’s understand briefly AUTO negotiation of Speed and Duplex.

The negotiation is an OPTIONAL part of IEEE 802.3u Fast Ethernet Standard, although it is fair to say most devices these days would support it, possibly older 100mb devices could be affected.

This standard exchanges link capabilities between devices on the end of the link and determine a common speed and duplex setting, even with this configured on both device, there can still be mismatches due to glitches. (This is the same on Gigabit too – gigabit does not do half duplex)

The best place to use Auto negotiate is where devices come and go, e.g. for desktop or laptop connection which have the potential to be moved etc, and potentially have different capabilities.

With this said it makes perfect sense for fixed/permanent and critical components connection we should set the duplex and speed manually on BOTH devices.

So Router to Switch/ Switch to Switch we should have fixed settings, also remember to add description on ports.

What else is in the mix.

What about IP phone, these are effectively small network switches. It depends on the criticality of your phones, but in general I have seen them as AUTO. And really just treat them like moveable devices e.g. PC

Summary

Use AUTO negotiation (both ends) for movable devices

Use Fixed configuration for (both ends) for critical network components and critical server components.

Key Indicators of Problems

If you see a switch port running at full duplex but see lost of FCS and Alignment errors clocking up there is a good chance the other side is on half duplex.

If you have port running a-100, a-half then it is likey that the a-half is wrong and maybe worth investigating.

References

http://www.cisco.com/en/US/tech/tk389/tk214/technologies_tech_note09186a0080094781.shtml

Required CCO Access:

http://www.cisco.com/en/US/partner/products/hw/switches/ps700/products_tech_note09186a00800a7af0.shtml

March 30, 2006

Connecting to the nearest printer.

Filed under: Old — John McManus @ 12:28 am

Have you ever wanted to have users automatically connect to the printer nearest the workstation they are logging into. We here is how it is done.

  • Create a printer queue(daqueue) on printserver (pserver)
  • Create a global group prt_daqueue_pserver
  • Add the workstation accounts which are closest to the printer (daqueue).
  • Now use the following sub in a users start-up script and hey presto the printer is mapped.

 

The Code

connprinters

Theme: Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.