Guest Rey Posted December 19, 2007 Posted December 19, 2007 Howdy all. New to this group. Have several questions related to login scripts: Does the NetLogon directory need to have the user's name added to it for read & execute permissions or would be be better to grant the Every One object read and execute permission - might be better to include the domain users group? Latter seems better as one may forget to add new user to Netlogon directory. In addition to the NetLogon directory, the login script (GroupMaps.vbs) is also listed/included in a group policy for domain users. It is listed under User configuration, Window Settings, Scripts(logon/logoff), Logon. But it did not fire until I also listed the file under the User Profile Tab of the user account...and here I had to use the format \\ServerName\Netlogon\GroupMaps.vbs instead of C: \Windows\sysvol\domain\sysvol\scripts\GroupMaps.vbs which did not work. Seems like the way it worked for me was to use the Netlogon directory in conjunction w/User Profile path as testing w/just the group policy did not work...Which is the correct way? Finally, in the script my initial test account, test user (login tuser), does not display the groups in which the account belongs, e.g. BoeingGroup, thus it does not map the drive and printers. So I created another user, John T. Doe (login jdoe) who does display being in the same groups as test user and for whom the script runs correctly... Any possible reasons for this? Thanks in advance for your suggestions. Will have to do some more reading... Rey Below is the login script being tested. ' purpose: map drive based on grp membership ' Example from http://www.computerperformance.co.uk/Logon/logon_group_membership.htm ' Modified for use on OEM domain ' Rey Collazo 8/30/2007, 12/18/2007 ' GroupMap.vbs ' Author Guy Thomas http://computerperformance.co.uk/ ' Version 3.3 - May 2006 ' -----------------------------------------------------------------' Option Explicit Dim objNetwork, objUser, CurrentUser Dim strGroup Dim objFSO Dim strUserDIR ' printers Dim prnBoeingDefault Dim prnBoeingGeneral Dim prnBoeingLS Dim prnKittingCopier Dim prnAdminCopier ' printer names prnBoeingDefault = "\\oemphxdc00\HP LJ2420DN" prnBoeingLS = "\\oemphxdc00\HP LJ2300N" prnAdminCopier = "\\oemphxdc00\Admin_copier" prnKittingCopier = "\\oemphxdc00\Kitting_copier" ' simple way of bypassing already connected drives... On Error Resume Next ' Initialise Groups with Const Const BoeingGroup = "cn=oem boeing seattle users" Const ExecutivesGroup = "cn=OEM Executive - Sales" 'Const ManagersGroup = "cn=OEM Managers" 'Const Users_Group = "cn=users" 'Const Administrators_Group = "cn=administrators" ' Create objects and extract strGroup values Set objNetwork = CreateObject("WScript.Network") Set objUser = CreateObject("ADSystemInfo") Set CurrentUser = GetObject("LDAP://" & objUser.UserName) wscript.echo "Sleeping a bit..." wscript.sleep 200 strGroup = LCase(Join(CurrentUser.MemberOf)) Wscript.echo "User name: " & objNetwork.username wscript.echo "Current user: " & objUser.username WScript.Echo "Member of " & strGroup ' add shared drive (S) for all users 'WScript.Echo "Shared Drive - all users" & vbcrlf & "User: " & objNetwork.UserName objNetwork.MapNetworkDrive "S:", "\\oemphxdc00\shared" ' set home directory for user if exists - not being created via script 'objNetwork.MapNetworkDrive "H:", "\\oemphxdc00\Users\" & objNetwork.UserName If InStr(strGroup, lcase(BoeingGroup)) Then WScript.Echo "Boeing Seattle User " ' map drive persistent objNetwork.MapNetworkDrive "M:", "\\oemphxdc00\Boeing Seattle\" ' setting default grp printer objNetwork.AddWindowsPrinterConnection prnBoeingDefault objNetwork.SetDefaultPrinter prnBoeingDefault ' adding other printers objNetwork.AddWindowsPrinterConnection prnBoeingLS objNetwork.AddWindowsPrinterConnection prnAdminCopier ElseIf InStr(strGroup, lcase(ExecutivesGroup)) Then 'WScript.Echo " Executives " objNetwork.MapNetworkDrive "N:", "\\oemphxdc00\Executive_Sales\" End If ' setting default grp printer ' objNetwork.AddWindowsPrinterConnection prnBoeingDefault ' objNetwork.SetDefaultPrinter prnBoeingDefault ' ' adding other printers ' objNetwork.AddWindowsPrinterConnection prnBoeingLS ' objNetwork.AddWindowsPrinterConnection prnAdminCopier ' objNetwork.AddWindowsPrinterConnection prnKittingCopier 'Wscript.Echo "Finished Testing for Groups " WScript.Quit ' End of GroupMaps
Guest Richard Mueller [MVP] Posted December 20, 2007 Posted December 20, 2007 Re: Several Questions on Login Scripts See comments inline below: "Rey" <reycollazo@cox.net> wrote in message news:5492b1f9-3250-4130-874e-e2d66a604c9b@s12g2000prg.googlegroups.com... > Howdy all. > New to this group. Have several questions related to login scripts: > > Does the NetLogon directory need to have the user's name added to it > for read & execute permissions or would be be better to grant the > Every One object read and execute permission - might be better to > include the domain users group? Latter seems better as one may forget > to add new user to Netlogon directory. By default the group "Everyone" has read permissions in the NetLogon share. On the Security tab (in ADUC) the group "Authenticated Users" has Read and Execute permissions. I've never altered this. > > In addition to the NetLogon directory, the login script > (GroupMaps.vbs) is also listed/included in a group policy for domain > users. It is listed under User configuration, Window Settings, > Scripts(logon/logoff), Logon. But it did not fire until I also listed > the file under the User Profile Tab of the user account...and here I > had to use the format \\ServerName\Netlogon\GroupMaps.vbs instead of C: > \Windows\sysvol\domain\sysvol\scripts\GroupMaps.vbs which did not > work. > Seems like the way it worked for me was to use the Netlogon directory > in conjunction w/User Profile path as testing w/just the group policy > did not work...Which is the correct way? If you configure a logon script on the Profile tab and also in a Group Policy it will run twice (or each will run). On the Profile tab for the user in ADUC if you enter "GroupMaps.vbs" in the field labeled "Logon script", the logon script becomes \\ServerName\NetLogon\GroupMaps.vbs where \\ServerName is the DC that authenticated the user. This is better than being tied down to one DC. The way to configure logon scripts in a group policy is to copy the logon script so it is on the Windows clipboard, edit the Group Policy and navigate to the Logon script setting (User Configuration, Windows Settings, Scripts), double click Logon, click the "Show Files..." button, and past the logon script in the dialog. Otherwise it's too difficult to figure out where the *.vbs file should go. Then close the dialog and click the Add button and Browse to select the logon script. For more on configuring logon scripts, see this link: http://www.rlmueller.net/LogonScriptFAQ.htm In testing the script you post below, the first step is to remove "On Error Resume Next". This makes troubleshooting nearly impossible. Logon scripts are too important; if there is a problem, you want an error message to alert you and give you a clue where to start (like a line number). Most logon scripts can be initially tested as normal scripts run after logon is complete, but you test with a normal user account. The most likely cause of your problem below is the statement: strGroup = LCase(Join(CurrentUser.MemberOf)) I know this is freqently suggested (and I think Microsoft might even use this), but it is flawed. The memberOf attribute is multi-valued. It can have no values, one value, or more than one. Your code must work in all three situations. In this case, the Join function will raise a type mismatch error unless the user is a member of at least two groups, so that memberOf is a variant array. In you case one of your test users was a member of two or more groups (other than the "primary" group, usually "Domain Users", which is never included) while the other was not. If you want to use a similar method, I would suggest: =============== Set objSysInfo = CreateObject("ADSystemInfo") strUserDN = objSysInfo.UserName Set objUser = GetObject("LDAP://" & strUserDN) On Error Resume Next arrGroups = objUser.GetEx("memberOf") If (Err.Number <> 0) Then On Error GoTo 0 strGroup = "" Else On Error GoTo 0 strGroup = LCase(Join(arrGroups)) End If =========== Note that I use "On Error Resume Next", but only for the one statement I expect might raise an error. Then I handle the error and restore normal error handling with "On Error GoTo 0". I use the GetEx method because it only raises an error if memberOf is empty (no group memberships other than the "primary"). If the user is a member of only one group, GetEx returns a variant array with one element. For more details, and other methods to check direct membership in groups, see this link: http://www.rlmueller.net/MemberOf.htm > > Finally, in the script my initial test account, test user (login > tuser), does not display the groups in which the account belongs, e.g. > BoeingGroup, thus it does not map the drive and printers. So I created > another user, John T. Doe (login jdoe) who does display being in the > same groups as test user and for whom the script runs correctly... > Any possible reasons for this? > > Thanks in advance for your suggestions. Will have to do some more > reading... > > Rey > > Below is the login script being tested. > ' purpose: map drive based on grp membership > ' Example from > http://www.computerperformance.co.uk/Logon/logon_group_membership.htm > ' Modified for use on OEM domain > ' Rey Collazo 8/30/2007, 12/18/2007 > > ' GroupMap.vbs > ' Author Guy Thomas http://computerperformance.co.uk/ > ' Version 3.3 - May 2006 > ' -----------------------------------------------------------------' > Option Explicit > > Dim objNetwork, objUser, CurrentUser > Dim strGroup > Dim objFSO > Dim strUserDIR > > ' printers > Dim prnBoeingDefault > Dim prnBoeingGeneral > Dim prnBoeingLS > Dim prnKittingCopier > Dim prnAdminCopier > > ' printer names > prnBoeingDefault = "\\oemphxdc00\HP LJ2420DN" > prnBoeingLS = "\\oemphxdc00\HP LJ2300N" > prnAdminCopier = "\\oemphxdc00\Admin_copier" > prnKittingCopier = "\\oemphxdc00\Kitting_copier" > > > ' simple way of bypassing already connected drives... > On Error Resume Next > > ' Initialise Groups with Const > Const BoeingGroup = "cn=oem boeing seattle users" > Const ExecutivesGroup = "cn=OEM Executive - Sales" > 'Const ManagersGroup = "cn=OEM Managers" > 'Const Users_Group = "cn=users" > 'Const Administrators_Group = "cn=administrators" > > ' Create objects and extract strGroup values > Set objNetwork = CreateObject("WScript.Network") > Set objUser = CreateObject("ADSystemInfo") > Set CurrentUser = GetObject("LDAP://" & objUser.UserName) > > wscript.echo "Sleeping a bit..." > wscript.sleep 200 > > strGroup = LCase(Join(CurrentUser.MemberOf)) > > Wscript.echo "User name: " & objNetwork.username > wscript.echo "Current user: " & objUser.username > WScript.Echo "Member of " & strGroup > > ' add shared drive (S) for all users > 'WScript.Echo "Shared Drive - all users" & vbcrlf & "User: " & > objNetwork.UserName > objNetwork.MapNetworkDrive "S:", "\\oemphxdc00\shared" > > ' set home directory for user if exists - not being created via script > 'objNetwork.MapNetworkDrive "H:", "\\oemphxdc00\Users\" & > objNetwork.UserName > > If InStr(strGroup, lcase(BoeingGroup)) Then > WScript.Echo "Boeing Seattle User " > ' map drive persistent > objNetwork.MapNetworkDrive "M:", "\\oemphxdc00\Boeing Seattle\" > > ' setting default grp printer > objNetwork.AddWindowsPrinterConnection prnBoeingDefault > objNetwork.SetDefaultPrinter prnBoeingDefault > > ' adding other printers > objNetwork.AddWindowsPrinterConnection prnBoeingLS > objNetwork.AddWindowsPrinterConnection prnAdminCopier > > ElseIf InStr(strGroup, lcase(ExecutivesGroup)) Then > 'WScript.Echo " Executives " > objNetwork.MapNetworkDrive "N:", "\\oemphxdc00\Executive_Sales\" > > End If > > > ' setting default grp printer > ' objNetwork.AddWindowsPrinterConnection prnBoeingDefault > ' objNetwork.SetDefaultPrinter prnBoeingDefault > > ' ' adding other printers > ' objNetwork.AddWindowsPrinterConnection prnBoeingLS > ' objNetwork.AddWindowsPrinterConnection prnAdminCopier > ' objNetwork.AddWindowsPrinterConnection prnKittingCopier > > > 'Wscript.Echo "Finished Testing for Groups " > WScript.Quit > > ' End of GroupMaps The only other comment I have is that the Sleep would only be useful if you have Win9x clients. If errors are raised because of persistent drive mappings, I would suggest a subroutine that maps and if there is an error removes the existing mapping so it is no longer persistent, then tries again. The subroutine should raise an error if the second attempt fails so you are alerted to the problem (possibly permissions). For example: =============== If InStr(strGroup, lcase(BoeingGroup)) Then Call MapDrive("M:", "\\oemphxdc00\Boeing Seattle\") End If Sub MapDrive(ByVal strDrive, ByVal strShare) ' Subroutine to map a drive to a share. ' objNetwork must be defined in the main ' program so it has global scope. On Error Resume Next objNetwork.MapNetworkDrive strDrive, strShare If (Err.Number <> 0) Then On Error GoTo 0 ' Remove drive mapping even if it is in use and ' make the removal persistent. objNetwork.RemoveNetworkDrive strDrive, True, True ' Try again to map the drive to the share objNetwork.MapNetworkDrive strDrive, strShare End If End Sub =============== A more elaborate scheme (that handles more situations) is a function to map the drives that returns True if successful, False otherwise. This way the main program can alert the user to errors (so they can be fixed), but the logon script does not halt. This is demonstrated in this snippet: ========== ' objFSO must have global scope. Set objFSO = CreateObject("Scripting.FileSystemObject") If InStr(strGroup, lcase(BoeingGroup)) Then If (MapDrive("M:", "\\oemphxdc00\Boeing Seattle\") = False) Then Call MsgBox("Unable to map drive M: to \\oemphxdc00\Boeing Seattle\") End If End If Function MapDrive(ByVal strDrive, ByVal strShare) ' Function to map network share to a drive letter. ' If the drive letter specified is already in use, the function ' attempts to remove the network connection. ' objFSO is the File System Object, with global scope. ' objNetwork is the Network object, with global scope. ' Returns True if drive mapped, False otherwise. Dim objDrive On Error Resume Next If (objFSO.DriveExists(strDrive) = True) Then Set objDrive = objFSO.GetDrive(strDrive) If (Err.Number <> 0) Then On Error GoTo 0 MapDrive = False Exit Function End If If (objDrive.DriveType = 3) Then objNetwork.RemoveNetworkDrive strDrive, True, True Else MapDrive = False Exit Function End If Set objDrive = Nothing End If objNetwork.MapNetworkDrive strDrive, strShare If (Err.Number = 0) Then MapDrive = True Else Err.Clear MapDrive = False End If On Error GoTo 0 End Function ============ This is demonstrated in the logon script in this link, along with a membership checking procedure that handles nested groups. http://www.rlmueller.net/Logon3.htm -- Richard Mueller Microsoft MVP Scripting and ADSI Hilltop Lab - http://www.rlmueller.net --
Guest Rey Posted December 20, 2007 Posted December 20, 2007 Re: Several Questions on Login Scripts Howdy Richard. Thanks for the suggestions. Implemented your GetEx("memberOf") suggestion and it worked for test user. As part of test, copied the script over to the appropriate directory under sysvol\domain\Polices (windows 2003 server) as the group policy editor did not display any dialog box into which I could paste the script but then I could have been in the wrong place... Found that I also had to keep the file in the Netlogon directory as I was getting userinit.exe errors when loggin in a the test accounts; review of the application events showed that file could not be found under sysvol Once this was done, seemed like nothing was working until I added the servername\netlogon\GroupMaps.vbs to profile tab after adding domain users and everyone grp to Netlogon directory. In short, removed domain users, everyone grp and entry in profile tab and it now works as a new employee logged in and the correct mapping for a Boeing user occurred in addition to printers. Wonder if there was any lag time in updating group policy? Researching a different issue, had an existing user logged in to a different machine and she received no mappings and no errs displayed...logged out, logged back and she now had mappings. Guess I'll try making mappins persistant... Thanks again for the suggestions and links provided. Rey On Dec 19, 7:33 pm, "Richard Mueller [MVP]" <rlmueller- nos...@ameritech.nospam.net> wrote: > See comments inline below: > > "Rey" <reycoll...@cox.net> wrote in message > > news:5492b1f9-3250-4130-874e-e2d66a604c9b@s12g2000prg.googlegroups.com... > > > Howdy all. > > New to this group. Have several questions related to login scripts: > > > Does the NetLogon directory need to have the user's name added to it > > for read & execute permissions or would be be better to grant the > > Every One object read and execute permission - might be better to > > include the domain users group? Latter seems better as one may forget > > to add new user to Netlogon directory. > > By default the group "Everyone" has read permissions in the NetLogon share. > On the Security tab (in ADUC) the group "Authenticated Users" has Read and > Execute permissions. I've never altered this. > > > > > In addition to the NetLogon directory, the login script > > (GroupMaps.vbs) is also listed/included in a group policy for domain > > users. It is listed under User configuration, Window Settings, > > Scripts(logon/logoff), Logon. But it did not fire until I also listed > > the file under the User Profile Tab of the user account...and here I > > had to use the format \\ServerName\Netlogon\GroupMaps.vbs instead of C: > > \Windows\sysvol\domain\sysvol\scripts\GroupMaps.vbs which did not > > work. > > Seems like the way it worked for me was to use the Netlogon directory > > in conjunction w/User Profile path as testing w/just the group policy > > did not work...Which is the correct way? > > If you configure a logon script on the Profile tab and also in a Group > Policy it will run twice (or each will run). On the Profile tab for the user > in ADUC if you enter "GroupMaps.vbs" in the field labeled "Logon script", > the logon script becomes > > \\ServerName\NetLogon\GroupMaps.vbs > > where \\ServerName is the DC that authenticated the user. This is better > than being tied down to one DC. The way to configure logon scripts in a > group policy is to copy the logon script so it is on the Windows clipboard, > edit the Group Policy and navigate to the Logon script setting (User > Configuration, Windows Settings, Scripts), double click Logon, click the > "Show Files..." button, and past the logon script in the dialog. Otherwise > it's too difficult to figure out where the *.vbs file should go. Then close > the dialog and click the Add button and Browse to select the logon script. > > For more on configuring logon scripts, see this link: > > http://www.rlmueller.net/LogonScriptFAQ.htm > > In testing the script you post below, the first step is to remove "On Error > Resume Next". This makes troubleshooting nearly impossible. Logon scripts > are too important; if there is a problem, you want an error message to alert > you and give you a clue where to start (like a line number). Most logon > scripts can be initially tested as normal scripts run after logon is > complete, but you test with a normal user account. > > The most likely cause of your problem below is the statement: > > strGroup = LCase(Join(CurrentUser.MemberOf)) > > I know this is freqently suggested (and I think Microsoft might even use > this), but it is flawed. The memberOf attribute is multi-valued. It can have > no values, one value, or more than one. Your code must work in all three > situations. In this case, the Join function will raise a type mismatch error > unless the user is a member of at least two groups, so that memberOf is a > variant array. In you case one of your test users was a member of two or > more groups (other than the "primary" group, usually "Domain Users", which > is never included) while the other was not. > > If you want to use a similar method, I would suggest: > =============== > Set objSysInfo = CreateObject("ADSystemInfo") > strUserDN = objSysInfo.UserName > > Set objUser = GetObject("LDAP://" & strUserDN) > > On Error Resume Next > > arrGroups = objUser.GetEx("memberOf") > > If (Err.Number <> 0) Then > > On Error GoTo 0 > > strGroup = "" > > Else > > On Error GoTo 0 > > strGroup = LCase(Join(arrGroups)) > > End If > > =========== > Note that I use "On Error Resume Next", but only for the one statement I > expect might raise an error. Then I handle the error and restore normal > error handling with "On Error GoTo 0". I use the GetEx method because it > only raises an error if memberOf is empty (no group memberships other than > the "primary"). If the user is a member of only one group, GetEx returns a > variant array with one element. For more details, and other methods to check > direct membership in groups, see this link: > > http://www.rlmueller.net/MemberOf.htm > >
Recommended Posts