Monday, January 7, 2013

Vb Script to Join computer to domain based on user DN


This was a complicated script.  We wanted to create an automated process to join a workstation to the domain in the correct destination OU.  In our environment the users exist in a location where the relative OU path to where the workstations should be can easily determined.  I did a good bit of error checking in this script, as I wanted to capture issues well and be able to diagnosis them.

When the computer joins the domain successfully and reboots, the user login will now be a domain account and consequently a new profile will be created.  So I had the script dynamically create another vbs file for profile copy that would run after reboot to copy all their previous profile information to the new profile.

The 4th command line arg is for the password of the user account in AD for the user/comp this is being run on.  In our environment, users had never logged into the domain before (this was a Novell env).  So the password was statically assigned during en-mass user creation operations.  You can prompt the user for a password instead if the user already exists in AD and is actively using his or her account.


'-------------------------------------------------------
'SCRIPT: ADJOIN
'PURPOSE: to find the Proper OU for the Computer to be
'joined to the domain, based on matching the Novell User ID to
'the AD User ID.  Then attempts to Join the Computer to the
'Domain to that OU. Finally, it attempts copying Profile information.
'This Script also alters the DNS search suffixes and order.

'NOTES & ASSUMPTIONS:
'1. This script assumes the user account has been created in AD prior
'    To this script running.
'2. The Username and password supplied by command line arguments, must
'    have rights to create the computer object in the OU being specified.
'3. The Script also requires that the user doesn't have set option to
'   "Force the user to change password on next login".

'Version: 1.6
'Author: Corey Sines
'-------------------------------------------------------
Option Explicit
On Error Resume Next

Dim objArgs, wshShell, VERBOSE
Dim strDomain, strJoinADuser, strJoinADpass, tmpArray, strNTDomain
Dim dnsSuffix1, dnsSuffix2, dnsSuffix3, dnsSuffixArray, objWMIService, objNetworkSettings
Dim strComptr, strUser, strPassword, strNTName, strUserDN
Dim ReturnValue, strErrorDescription, objRegExp, objTrans, strCompOU
Dim objNetwork, strComputer, objComputer
Dim strOpenReg, strExportUserSettings

' Constants for the NameTranslate object.
Const ADS_NAME_INITTYPE_DOMAIN = 1
Const ADS_NAME_INITTYPE_SERVER = 2
Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_NT4 = 3
Const ADS_NAME_TYPE_1779 = 1

' Constants for Domain Join
Const JOIN_DOMAIN = 1
Const ACCT_CREATE = 2
Const ACCT_DELETE = 4
Const WIN9X_UPGRADE = 16
Const DOMAIN_JOIN_IF_JOINED = 32
Const JOIN_UNSECURE = 64
Const MACHINE_PASSWORD_PASSED = 128
Const DEFERRED_SPN_SET = 256
Const INSTALL_INVOCATION = 262144

'Constants for Window Mode
Const MAXIMIZEDWINDOW = 3
Const MINIMIZEDWINDOW = 2


'Debug Script, set to yes (1) if you want VERBOSE feedback, set (0) for none.
VERBOSE = 1

'Section to handle the command line arguments
If WScript.Arguments.count = empty Or WScript.Arguments.Count <> 4 Then
    Call Usage()
End If

Set objArgs = WScript.Arguments
strDomain = LCase(objArgs(0)) ' Domain that will be used for this script
strJoinADuser = LCase(objArgs(1)) ' User Account that has Domain Create Privledges to OUs
strJoinADpass = objArgs(2) ' Password for the Account that has Domain Create Privledges
strPassword = objArgs(3) ' Password For the User Account in AD that matches the Novell ID

tmpArray = Split(strDomain, ".", -1,0)
strNTDomain = tmpArray(0)

If VERBOSE = 1 Then
WScript.Echo "VERBOSE LOG of Active Directory Domain Join Script"
WScript.Echo Date & " " & Time
WScript.Echo "______________________________________________________________"
WScript.echo "You supplied the following command line arguments: " & vbCrLf & vbCrLf &_
"The Domain is set to: " & strDomain & vbCrLf &_
"NT4 Domain Name will be: " & strNTDomain & vbCrLf &_
"UserName to Join Domain (must have create rights!) is: " & strJoinADuser & vbCrLf '&_
'"Password for Join Domain account is: " & strJoinADpass & vbCrLf
End If

'-------------------------------------------------------
'Start of Section to set DNS Suffix Order
'where the Computer Account is going to reside.
'-------------------------------------------------------
'Production
'dnsSuffix1 = "Sandbox.testlab.local"
'dnsSuffix2 = "test.sandbox.testlab.local"
'dnsSuffix3 = "testlab.local"

'Adding Suffixes to an array
dnsSuffixArray = Array(dnsSuffix1 & ", " & dnsSuffix2 & ", " & dnsSuffix3)

If VERBOSE = 1 Then
WScript.Echo "Changing DNS Suffixes to the following: "
Dim suffix
For Each suffix In dnsSuffixArray
WScript.Echo suffix
Next
WScript.Echo ""
End If

strComptr = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComptr & "\root\cimv2")
Set objNetworkSettings = objWMIService.Get("Win32_NetworkAdapterConfiguration")
objNetworkSettings.SetDNSSuffixSearchOrder(dnsSuffixArray)

If Err.Number <> 0 Then ' Error occured in the above code
    DisplayError "Error adding DNS Suffixes: " & dnsSuffixArray & vbCrLf & " Script Exiting!"
    Wscript.Quit(0) ' Script exits
End If

'-------------------------------------------------------
'Start of Section to Retrive the OU for
'where the Computer Account is going to reside.
'-------------------------------------------------------
Set wshShell = Wscript.CreateObject("Wscript.Shell")
'Specifies Username and Password for the matching user of this machine in  AD

If Ucase(WshShell.ExpandEnvironmentStrings("%NWUSERNAME%")) <> "" then
strUser = Ucase(WshShell.ExpandEnvironmentStrings("%NWUSERNAME%")) 'Novell ID
else
strUser = Ucase(WshShell.ExpandEnvironmentStrings("%USERNAME%")) 'Novell ID
End if

strNTName = strNTDomain & "\" & strUser ' Specify the NT4 name user. ex: DOMAIN\USER

If VERBOSE = 1 Then
WScript.echo "The Novell UserName to match on search in AD is:" & strUser & vbCrLf &_
"The Password to use for this AD account is:" & strPassword & vbCrLf &_
"The Matching AD NT4 Domain Name is: " & strNTName & vbCrLf
End If

' Use the NameTranslate object to convert the NT user name to the
' Distinguished Name required for the LDAP provider.
Set objTrans = CreateObject("NameTranslate")
' Initialize NameTranslate by locating the DC for the Domain.
' Because this computer isn't part of the domain, you must supply credentials
objTrans.InitEx ADS_NAME_INITTYPE_DOMAIN, strDomain, strUser, strNTDomain, strPassword
' Use the Set method to specify the NT format of the object name.
objTrans.Set ADS_NAME_TYPE_NT4, strNTName
' Use the Get method to retrieve the RFC 1779 Distinguished Name.
strUserDN = objTrans.Get(ADS_NAME_TYPE_1779)

If Err.Number <> 0 Then ' Error occured in the above code
    DisplayError "User: " & strNTName & " not found in Domain: " & strDomain & vbLf &_
    "or Password: " & strPassword & " is incorrect for this User." & vbCrLf & "Script Exiting!"
    Wscript.Quit(0) ' Script exits
End If

' Escape any "/" characters with backslash escape character.
' All other characters that need to be escaped will be escaped.
strUserDN = Replace(strUserDN, "/", "\/")

If VERBOSE = 1 Then WScript.echo "User DN Found:" & strUserDN End If

' Using regex to remove the CN, and then concat the Computers OU to string

If InStr(strUserDN, "OU=Users_and_Groups") Then
Set objRegExp = New RegExp
With objRegExp
.Pattern = "^cn=[^,]+,OU=Users_and_Groups,"
.IgnoreCase = True
.Global = True
End With

strCompOU = "OU=Computers," & CStr(objRegExp.Replace(strUserDN, ""))

Else

Set objRegExp = New RegExp
With objRegExp
.Pattern = "^cn=[^,]+,"
.IgnoreCase = True
.Global = True
End With

strCompOU = "OU=Workstations," & CStr(objRegExp.Replace(strUserDN, ""))
End If


If VERBOSE = 1 Then WScript.echo "Computer OU set to:" & strCompOU End If

'-------------------------------------------------------
'Start of Section to Join the Computer to the Domain.
'-------------------------------------------------------

' Geting the Computer Name from WMI
Set objNetwork = CreateObject("WScript.Network")
strComputer = objNetwork.ComputerName

If VERBOSE = 1 Then WScript.Echo "Computer Name is:" & strComputer End If

'Getting the Computer Object from WMI so it can be use to Join Domain
Set objComputer = _
    GetObject("winmgmts:{impersonationLevel=Impersonate}!\\" & _
    strComputer & "\root\cimv2:Win32_ComputerSystem.Name='" _
    & strComputer & "'")

If VERBOSE = 1 Then WScript.Echo "Attempting to Join Computer to the Domain.." End if
'Attempting to Join Domain - Using the credentials supplied by command line arguements.
'NOTE: This account must have priviledges to Create Computer in the specified OU
ReturnValue = objComputer.JoinDomainOrWorkGroup(strDomain, _
    strJoinADpass, _
    strJoinADuser, _
    strCompOU, _
    JOIN_DOMAIN + ACCT_CREATE)

If VERBOSE = 1 Then WScript.Echo "RETURNVALUE from Joining Domain was: " & ReturnValue End If

If Err.Number <> 0  Or ReturnValue <> 0 Then ' Error occured in the above code
    On Error Resume Next
    Err.Raise CInt(ReturnValue)
    Err.Source  = "objComputer.JoinDomainOrWorkGroup"
    Select Case ReturnValue
Case 5 strErrorDescription = "Access is denied"
Case 87 strErrorDescription = "The parameter is incorrect"
Case 110 strErrorDescription = "The system cannot open the specified object"
Case 1323 strErrorDescription = "Unable to update the password"
Case 1326 strErrorDescription = "Logon failure: unknown username or bad password"
Case 1355 strErrorDescription = "The specified domain either does not exist or could not be contacted"
Case 2224 strErrorDescription = "The account already exists"
Case 2691 strErrorDescription = "The machine is already joined to the domain"
Case 2692 strErrorDescription = "The machine is not currently joined to a domain"
End Select
    Err.Description = strErrorDescription
    DisplayError "Joining Computer: " & strComputer & " to Domain: " & strDomain &_
    " Failed. " & vbCrLf & "Script Exiting!"  
    Wscript.Quit(0) ' Script exits
End If

Wait(20)

'-------------------------------------------------------
'Start of Section to Handle Profile Copy
'-------------------------------------------------------

If VERBOSE = 1 Then WScript.Echo "Backing up Previous Registry Info..." End If

'Backing up Registry into .Reg file.
strOpenReg = "REG add HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System /v DisableRegistryTools /t REG_DWORD /d 0 /f"
strExportUserSettings = "regedit /e C:\DESKTOP.REG " & Chr(34) & "HKEY_CURRENT_USER\Control Panel" & Chr(34)

If VERBOSE = 1 Then 'Executes the program in the desired window mode base on VERBOSE setting
RunProgram strOpenReg, MAXIMIZEDWINDOW, True
RunProgram strExportUserSettings, MAXIMIZEDWINDOW, True
Else
RunProgram strOpenReg, MINIMIZEDWINDOW, True
RunProgram strExportUserSettings, MINIMIZEDWINDOW, True
End If

If Err.Number <> 0 Then ' Error occured in the above code
 DisplayError "An Error occurred backing up your previous profile information, your profile may not" &_
     "have been transferred over... Script Continuing.. Contact Customer Service!"
    Err.Clear ' Script continues, Error is cleared...  
End If

'Sub routine that creates the PCOPY.VBS file to be used on reboot.
CreatePCOPYVBS "c:\pcopy.vbs"

If VERBOSE = 1 Then WScript.Echo strComputer & " has been joined to the " & strDomain & " Domain." &_
"This Computer will now Reboot." End If

MsgBox strComputer & " has been joined to the " & strDomain & " Domain."
       MsgBox "This computer will now reboot."
RunProgram "Shutdown -r -t 10", 2, False 'Restarts PC in 10 seconds


'Cleaning up resources.
Set objArgs = Nothing
Set wshShell = Nothing
Set objWMIService = Nothing
Set objNetworkSettings = Nothing
Set objRegExp = Nothing
Set objTrans = Nothing
Set objNetwork = Nothing
Set objComputer = Nothing
WScript.Quit(0) ' Exiting Script

'--------------------------SUBS & FUNCTIONS------------------------------
Sub Wait(someSeconds)
    Dim tmpTime, i
    tmpTime = 1000000 * someSeconds
    for i = 0 to tmpTime
    next
End Sub
'-----
Sub Usage() ' Displays a Popup window detailing how to use the Script with Commandline Arguments
    Dim wshShell, responce, FSO, objFile
Set WshShell = Wscript.CreateObject("Wscript.Shell")

    WshShell.Popup("Usage:" & vbNewLine &_
                "cscript ADJOIN.vbs {AD Domain} {AD Join Account} {AD Join Account Password} " &_
                " {New User Account Password for the Matching Novell to AD User}" & vbNewLine &_
                VbCrLF & "Example:" & vbtab & "cscript ADJOIN.vbs  SANDBOX.TESTLAB.LOCAL  " &_
                 "SANDBOX\JOINDOM  adminP@55 p@ssw0rd" & vbNewLine &_
                VbCrLF & "Note:" & vbtab & "AD Join Account must be DOMAIN\USER format!")
             
    responce =  MsgBox ("Do you want this script to create an example Batch file?", VBYesNo, "AD DOMAIN JOIN SCRIPT")
        If responce = VBYes Then
       WScript.Echo "Creating file: EXAMPLE.BAT"
       Set FSO = CreateObject("Scripting.FileSystemObject")
       Set objFile = fso.CreateTextFile(WshShell.CurrentDirectory & "\EXAMPLE.BAT", True)
    objFile.WriteLine "@ECHO OFF"
    objFile.WriteLine "cscript  //nologo ADJOIN.VBS SANDBOX.TESTLAB.LOCAL SANDBOX\JOINDOM adminP@55 p@ssw0rd > ADJOIN.LOG"  
    objFile.Close
   End If
   WScript.Quit(0)
End Sub
'-----
Sub RunProgram(progName, windowMode, waitForReturn) ' Runs a Program with desired options
wshShell.Run progName, windowMode, waitForReturn
End Sub
'-----
Sub DisplayError(customErrText) ' Displays Error information
WScript.Echo customErrText
    WScript.Echo "Error: " & Err.Number
    WScript.Echo "Error (Hex): " & Hex(Err.Number)
    WScript.Echo "Source: " &  Err.Source
    WScript.Echo "Description: " &  Err.Description
End Sub
'-----
Sub CreatePCOPYVBS(locationOfFile) 'creates PCOPY.VBS file.
Dim FSO, objFile

If VERBOSE = 1 Then WScript.Echo "Attempting to create PCOPY.VBS..." End If

Set FSO = CreateObject("Scripting.FileSystemObject") ' Sets the FSO Object for accessing Files
Set objFile = fso.CreateTextFile(locationOfFile, True)
objFile.Write("On Error Resume Next" & vbCrLf &_
"Wscript.Echo " & Chr(34) & "------AD PROFILE COPY--------" & Chr(34) & vbCrLf &_
"Wscript.Echo " & Chr(34) & "Checking if Logged in User is and Administrator.." & Chr(34) & vbCrLf &_
"Set FSO = CreateObject(" & Chr(34) & "Scripting.FileSystemObject" & Chr(34) & ")" & vbCrLf &_
"Set WshShell = WScript.CreateObject(" & Chr(34) & "WScript.Shell" & Chr(34) & ")" & vbCrLf &_
"Set WshSysEnv = WshShell.Environment(" & Chr(34) & "PROCESS" & Chr(34) & ")" & vbCrLf &_
"If isAdmin = True Then" & vbCrLf &_
"Wscript.Echo " & Chr(34) & "User is Administrator, Starting Profile Copy..." & Chr(34) & vbCrLf &_
"  oldProfile = " & Chr(34) & wshShell.ExpandEnvironmentStrings("%USERPROFILE%") & Chr(34) & vbCrLf &_
"  oldUserName = " & Chr(34) & WshShell.ExpandEnvironmentStrings("%USERNAME%") & Chr(34) & vbCrLf &_
"  newProfile = WshShell.ExpandEnvironmentStrings(" & Chr(34) & "%USERPROFILE%" & Chr(34) & ")" & vbCrLf &_
"  newUserName = WshShell.ExpandEnvironmentStrings(" & Chr(34) & "%USERNAME%" & Chr(34) & ")" & vbCrLf &_
"  Wscript.Echo " & Chr(34) & "old username was:" & Chr(34) & " & oldUserName" & vbCrLf &_
"  Wscript.Echo " & Chr(34) & "new username was:" & Chr(34) & " & newUserName" & vbCrLf &_
"   If oldProfile <> newProfile Then" & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Old and New Profile's don't match, beginning Copy process.." & Chr(34) & vbCrLf &_      
"     MsgBox " & Chr(34) & "Copying your Previous Novell Profile to your new AD profile, "  &_
"your system may seem slow or unresponsive for a few minutes depending on the size of your old profile..." & Chr(34) &_
"      , 0, " & Chr(34) & "AD Profile Copy" & Chr(34) & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Copying Desktop" & Chr(34) & vbCrLf &_
"     CopyProfileFolder oldProfile & "& Chr(34) & "\desktop" & Chr(34) & ", newProfile " & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Copying Favorites"  & Chr(34) & vbCrLf &_
"     CopyProfileFolder oldProfile & "& Chr(34) & "\favorites" & Chr(34) & ", newProfile" & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Copying My Documents" & Chr(34) & vbCrLf &_
"     CopyProfileFolder oldProfile & "& Chr(34) & "\my documents" & Chr(34) & ", newProfile " & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Copying Start Menu" & Chr(34) & vbCrLf &_
"     CopyProfileFolder oldProfile & "& Chr(34) & "\Start Menu" & Chr(34) & ", newProfile  " & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Copying Application Data" & Chr(34) & vbCrLf &_
"     CopyProfileFolder oldProfile & "& Chr(34) & "\Application data" & Chr(34) & ", newProfile " & vbCrLf &_
"        If FSO.FileExists(" & Chr(34) & "C:\desktop.reg" & Chr(34) & ") Then" & vbCrLf &_
"          Wscript.Echo " & Chr(34) & "Importing old Registry Settings..." & Chr(34) & vbCrLf &_
"   strOpenReg = " & Chr(34) & "REG add HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System /v DisableRegistryTools /t REG_DWORD /d 0 /f" & Chr(34) & vbCrLf &_
"          strImportUserSettings = " & Chr(34) & "regedit /s C:\DESKTOP.REG" & Chr(34) & vbCrLf &_
"          RunProgram strOpenReg, 2, True" & vbCrLf &_
"          RunProgram strImportUserSettings, 2, True" & vbCrLf &_
"        Else" & vbCrLf &_
"          ElevateToError()" & vbCrLf &_
"        End If" & vbCrLf &_
"   Else" & vbCrLf &_
"     ElevateToError()" & vbCrLf &_
"   End If" & vbCrLf &_
"  If Err.Number <> 0 Then ElevateToError() End If" & vbCrLf &_
"     Wscript.Echo " & Chr(34) & "Cleaning up Script..." & Chr(34) & vbCrLf &_
"  strCloseReg = " & Chr(34) & "reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System " &_
"  /v DisableRegistryTools /t REG_DWORD /d 1 /f" & Chr(34) & vbCrLf &_
"      RunProgram strCloseReg, 2, True" & vbCrLf &_
"  MsgBox " & Chr(34) & "Your Previous Profile information was copied to your new AD Profile, your system will now reboot." &_
   Chr(34) & ", 0, " & Chr(34) & "AD Profile Copy" & Chr(34) & vbCrLf &_
"  Fso.DeleteFile" & chr(34) & "C:\Documents and Settings\All Users\Start Menu\Programs\Startup\PCOPY.lnk" & Chr(34) & ", True" & vbCrlf &_
"  RunProgram " & Chr(34) & "Shutdown -r -t 60" & Chr(34) & ", 2, True" & vbCrLf &_
"Else" & vbCrLf &_
"     MsgBox " & Chr(34) & "Your current User doesn't appear to have administrator rights, "  &_
"      sometimes this happens on the first login to Active Directory, The script will go ahead and reboot your PC," &_
"      On the subsequent reboot your profile should copy over properly." & Chr(34) &_
"      , 0, " & Chr(34) & "AD Profile Copy" & Chr(34) & vbCrLf &_
"      RunProgram " & Chr(34) & "Shutdown -r -t 60" & Chr(34) & ", 2, True" & vbCrLf &_
"End If" & vbCrLf &_
"Wscript.Quit(0)" & vbCrLf &_
"'--------------------------------------" & vbCrLf &_
"Function isAdmin()" & vbCrLf &_
"On Error Resume Next" & vbCrLf &_
" Err.Clear" & vbCrLf &_
" FSO.CreateTextFile " & Chr(34) & "C:\test.txt" & Chr(34) & ", True" & vbCrLf &_
"  If Err.Number = 0 Then"  & vbCrLf &_
"    isAdmin = True"  & vbCrLf &_
" Else"  & vbCrLf &_
"    isAdmin = False"  & vbCrLf &_
" End If"  & vbCrLf &_
"End Function"  & vbCrLf &_
"Sub CopyProfileFolder(sourceFolder, destinationFolder)" & vbCrLf &_
" Set oSHApp = CreateObject(" & Chr(34) & "Shell.Application" & Chr(34) & ")" & vbCrLf &_
" oSHApp.Namespace(destinationFolder).CopyHere sourceFolder, 16" & vbCrLf &_
" Set oSHApp = nothing " & vbCrLf &_
"End Sub" & vbCrLf &_
"Sub ElevateToError()" & vbCrLf &_
"   MsgBox " & Chr(34) & "A Problem Occured in tranferring your old Novell profile to your new AD Profile." &_
" Please Contact Customer Support!" & Chr(34) & ", 0, " & Chr(34) & "AD Profile Copy" & Chr(34) & vbCrLf &_
"   Wscript.Quit(0)" & vbCrLf &_
"End Sub" & vbCrLf &_
"Sub RunProgram(progName, windowMode, waitForReturn)" & vbCrLf &_
"    wshShell.Run progName, windowMode, waitForReturn" & vbCrLf &_
"End Sub")
objFile.Close

'Adds to the startup folder to run after reboot.  Requres 2 reboots to complete entire process...

Dim MyShortcut
 Set MyShortcut = wshShell.CreateShortcut("C:\Documents and Settings\All Users\Start Menu\Programs\Startup\PCOPY.lnk")
  MyShortcut.TargetPath = WSHShell.ExpandEnvironmentStrings("%windir%\system32\cscript.exe")
  MyShortcut.Arguments = "C:\pcopy.vbs"
  MyShortcut.WorkingDirectory = "C:\"
  MyShortcut.WindowStyle = 1
  MyShortcut.Save

If Err.Number <> 0 Then ' Error occured in the above code
  DisplayError "An Error occurred creating the Profile Copy File, your profile may not" &_
      "Transfer over. Contact Customer Service. Script Continuing.."
    Err.Clear ' Script continues, Error is cleared...  
End If

End Sub

No comments:

Post a Comment