Windows 7 login scripts and missing network drives

Most Windows sysadmins use a Group Policy object to launch their login script. You may have noticed that Windows 7 and Vista fail to connect network drives defined in the login script if the user is a local admin and UAC is enabled. The script completes successfully and no error condition is encountered, but no drive mappings. Run it again manually and everything’s fine.

This is in fact by design, and it’s caused by the way UAC works. When you’re a member of the Administrators group and you log in, your account is busted down to a non-privileged user by UAC. This running context is completely separate from the context you get when you right-click Command Prompt and launch as an administrator. As you’ll probably have noticed, network drives connected in one context are not visible in the other. The problem is that GPO-based login scripts are being executed in the Administrator context – not the ordinary user context.

So, how do we get it working? Microsoft offer an unsupported kludge in KB937624 – getting around the issue by weakening Windows security and forcing network connections to be common to both user contexts. They carefully designed this not to be the case, so modifying the behaviour does seem like a bad idea.

However, Microsoft’s preferred solution (example launchapp.wsf script in the appendix of that page) is to use the GPO-triggered script to set a Scheduled Task to run immediately in the other (non-admin) context, and run your login script from there – much better.
The reasons I’m writing all this up are that:

  • Microsoft’s example script has some illegal character/line-wrap in there – copying and pasting it won’t work!
  • This method doesn’t work with XP so some forking logic is needed if you have mixed clients.
  • They make no allowances for multiple admin/non-admin users sharing the same PC.
  • This appears to be Microsoft’s sole example document of how to program using the Task Scheduler 2.0 API, and it neglects to define several absolutely essential object properties if you want to do something more useful than simply open Notepad.

My particular problem was that I needed to launch a script with a space character in the path, e.g.:

cscript.exe //nologo "\\domain.com\netlogon\departmentX users\logon.vbs"

For me changing this path name was not an option as there were many other dependencies. I spent a long time wondering why the API was eating my quotes as I fed it the above string and I tried various ways to escape them. Eventually I launched the Scheduled Tasks MMC tool (click on the root of Task Scheduler Library to see the job). Looking in the Action properties I realised that there are separate fields for the starting directory and for the arguments. Manually editing the job to use these got it working:
Task Properties Dialog
Frustratingly, there don’t seem to be any examples on the Web showing you how to populate these fields programmatically. Guessing the Arguments property was straighforward but StartIn is not a valid propery name. I read on Wikipedia that Task Scheduler 2.0 uses XML to store its jobs so I exported the job and viewed it. Luckily they used consistent property names in the XML (Arguments and WorkingDirectory) and I was able to set them in VBScript (see highlighted lines below).

There was an additional complication though. Once a user has run the Scheduled Task, it’s left behind on the system. In my initial testing this wasn’t a problem because I was testing admin users, but I soon discovered that a non-privileged user cannot delete and recreate the task if one created by another user already exists. So we need only schedule the task if the current user is running in an elevated security context. By far the simplest method is to parse the output of the whoami /groups command, as explained in this post:
http://blogs.technet.com/b/jhoward/archive/2008/11/19/how-to-detect-uac-elevation-from-vbscript.aspx

UPDATE – added some logic to prevent the login script from launching for RemoteApp sessions to Terminal Servers.

'launchapp.vbs, modified from Microsoft's launchapp.wsf
'launches a process as interactive user, NOT as the elevated privilege user context

Option Explicit

Const TriggerTypeRegistration = 7
Const ActionTypeExecutable = 0
Const FlagTaskCreate = 2
Const LogonTypeInteractive = 3

Dim strWorkingDirectory, strHostname, strOSVer, colProcessList, strUser, strDomain
Dim objNetwork, objComputer, objShell, objExec, objWMI, objItem, strScriptName, strStdOut

strWorkingDirectory = "\\domain.com\netlogon\DepartmentX Users"

'launch this login script
strScriptName = "logon.vbs"

Set objNetwork = CreateObject("WScript.Network")
Set objShell = CreateObject("WScript.Shell")
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") 
strHostname = objNetwork.ComputerName
Set objComputer = GetObject("WinNT://" & strHostname & ",computer")
strOSVer = objComputer.OperatingSystemVersion

If strOSVer >= "6.0" Then
  If IsElevated() Then
    'Machine has UAC and user is elevated so use LAUNCHAPP.WSF Task Scheduler method based
    'on appendix from http://technet.microsoft.com/en-us/library/cc766208(WS.10).aspx

    'Are we launched in a RemoteApp session on a Terminal Server? If so, quit.
    Set colProcessList = objWMI.ExecQuery("Select * from Win32_Process Where Name = 'rdpshell.exe'")
    For Each objItem In colProcessList
      objItem.GetOwner strUser, strDomain
      'If we're an admin we can see all users' processes so we need to check only our own
      If strUser = objNetwork.UserName Then
        WScript.Quit
      End If  
    Next

    LaunchApp
  Else
    'User is not elevated, so launch the script normally
    objShell.Run "cscript.exe //nologo " & Chr(34) & strWorkingDirectory & "\" & strScriptName & Chr(34), 1
  End If
Else
  'This is a Windows XP/2003 machine, so launch the script normally
  objShell.Run "cscript.exe //nologo " & Chr(34) & strWorkingDirectory & "\" & strScriptName & Chr(34), 1
End If

Set objNetwork = nothing
Set objComputer = nothing
Set objShell = nothing

Function IsElevated()
  IsElevated = False
  strStdOut = ""
  Set objExec = objShell.Exec ("whoami /groups")
  Do While (objExec.Status = 0)
    WScript.Sleep 100
    If Not objExec.StdOut.AtEndOfStream Then
      strStdOut = strStdOut & objExec.StdOut.ReadAll
    End If
  Loop
  If InStr(strStdOut,"S-1-16-12288") Then
    IsElevated = True
  End If
  Set objExec = nothing
End Function

Sub LaunchApp
  Dim objTaskService
  Dim strTaskName, rootFolder, taskDefinition, triggers, trigger, Action

  'Create the TaskService object
  Set objTaskService = CreateObject("Schedule.Service")
  Call objTaskService.Connect()
  strTaskName = "Launch App As Interactive User"

  'Get a folder to create a task definition in
  Set rootFolder = objTaskService.GetFolder("\")

  'Delete the task if already present
  On Error Resume Next
  Call rootFolder.DeleteTask(strTaskName, 0)
  Err.Clear

  'Create the new task
  Set taskDefinition = objTaskService.NewTask(0)

  'Create a registration trigger
  Set triggers = taskDefinition.Triggers
  Set trigger = triggers.Create(TriggerTypeRegistration)

  'Create the action for the task to execute
  Set Action = taskDefinition.Actions.Create(ActionTypeExecutable)
  Action.Path = "cscript.exe"
  Action.Arguments = "//nologo " & strScriptName
  Action.WorkingDirectory = strWorkingDirectory

  'Register (create) the task
  call rootFolder.RegisterTaskDefinition(strTaskName, taskDefinition, FlagTaskCreate,,, LogonTypeInteractive)

  Set objTaskService = nothing
End Sub
Advertisements

48 thoughts on “Windows 7 login scripts and missing network drives

    1. patters Post author

      Thanks Eric. I edited it a couple of times and hadn’t spotted that. Note the extra End If on line 44. I had tried to roll all of it into one single condition but the whoami.exe command is missing on XP machines so you can’t run the IsElevated function.

      Reply
    2. Yong Kam Wah

      We are facing the similar issue in one of our client place recently, and their environment is
      1. The file server is not part of the AD Domain
      2. Windows 7 users can manually execute the login script and mapped to the file server
      3. Users are NOT part of the local administrator group

      The login script defined in GPO completed successfully, but users will only see a RED Cross on the mapped network drive.

      After several days of finding, the root cause of this issues due to the “Act as part of the operating system” configure for only domain users and administrator. Once we disable this in the GPO, this issue had been resolved.

      Hope the information helps.

      Reply
  1. Stephen

    Can this script be made to act like the standard launchapp.wsf script so that you do not have to hard-code the path and script variables?

    Reply
  2. Stephen

    When the the file is run as .vbs with a windows 7 client I get:

    Script: launchapp.vbs
    Line: 31
    Char: 5
    Error: Object required: ”
    Code: 800A01A8
    Source: Microsoft VBScript runtime error

    Still works fine with XP clients.

    Reply
    1. patters Post author

      Definitely works on XP/Win7x86/Win7x64 for me. Are you sure you’re copying the text properly (use the icons at the top of the script pane which appear when you mouse over)? If not then perhaps you have some group policy set that stops users querying WMI, since line 31 checks the running process list through WMI.

      Reply
    2. William

      There is no line to create the objWMI object. The script needs to include something like:

      Set objWMI = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2”)

      That should clear up the “Object Required” issue.

      And the reason it works fine on XP is because that code isn’t run on XP, only on strOSVer >= 6.0″, i.e. Vista or greater.

      Reply
      1. patters Post author

        Well spotted William – thanks. I only added the RemoteApp session detection bit later in my production environment, and edited the script posted here, but forgetting that line. Oops!

  3. Stephen

    I determined the error is from users that login with an administrative context. That is their domain login is a member of the local administrators group so they have elevated privileges. The users that do not work fine. Any tips on remedying this?

    Thanks

    Reply
    1. patters Post author

      This definitely works for me, and I’m a local admin. As I mentioned, it looks to me like you have something stopping you connecting to WMI (which is what happens on line 31) – perhaps an ACL in Group Policy is stopping this. Run the Group Policy Modelling tool from the GPMC and check.

      How about you download the scriptomatic tool here:
      http://www.microsoft.com/downloads/en/details.aspx?FamilyID=09dfc342-648b-4119-b7eb-783b0f7d1178

      and query some WMI objects, specifically say the running processes. If that doesn’t work then you have a generic problem with your workstation security settings.

      Reply
      1. patters Post author

        If all else fails Stephen, you can delete lines 29-39 if you don’t use RemoteApp on terminal servers in your environment.

      2. hottotrot911@hotmail.com

        Having this same problem in a major way at my company. Trying to move all workstations and render nodes to win7x64 before upgrading domain controllers from win2k3 SP2. Bletch. such a pain.

        In response to Stephen: If you care about getting the terminal services bit of the code working, I got this script running by setting the objWMI above where all the other objects are declared:

        Set objShell = CreateObject(“WScript.Shell”)
        Set objWMI = GetObject(“winmgmts:”)
        strHostname = objNetwork.ComputerName

        Seems to work,

        HOWEVER, here’s my question. When I set it as a domain group policy login script, it still fails to mount any drives. If I navigate all the way to the folder where the scripts are located, and run the vbs file manually, it works fine. I even see the various taskeng.exe shells running when a user logs in. But the drives won’t actually mount until the computer is more… awake? happy? I’m honestly not sure. Is win7 trying to execute this script before it is fully established on the network, and if so, is there any way to build a 5 second timer or something slick in here to fix it?
        Any help appreciated! Hope this thread isn’t dead.

      3. patters Post author

        Something must be going wrong, because this script is designed to prevent the very thing you’re talking about. Are you sure that your workstations are not invoking several different scripts? You mention multiple taskeng windows appearing. When the drives fail to mount, can you see the drive letters when you launch a command prompt as Administrator?

      4. hottotrot911@hotmail.com

        Hey Patters, thanks for your reply.
        It’s at the point where, if I’m really lucky, the AD pushing the script through Default Domain Policy will work 1 in maybe 10 times. The script works 100% if I navigate to it and double click it.

        I found and added a 5 second timer in case it was so problem with getting the network online, which was dumb… given that it doesn’t have a problem finding the vbs script… on the network.

        UAC is turned off completely on the machines I’ve been testing on. The accounts I log into to test are added from our domain and then set as local admins.

        Can’t CD to the drives in CMD as Admin. Please let me know if I can provide any helpful details.
        Thanks again!

      5. hottotrot911@hotmail.com

        No love with UAC back at original level.
        I might also mention that I’m running these under the user logon default policy, not the machine startup default policy, if it matters, if it’s not obvious.

        Is there any way I can modify the script to just leave itself up on screen, like a echo on type thing. Then I could actually see if it’s posting an error.
        Best,

      6. patters Post author

        Well you could launch it from policy with something like:
        cscript “\\domain\netlogon\scripts\launchapp.vbs” > c:\temp\error.log 2>&1

        The 2>&1 redirects standard error to the file, together with standard output.

      7. hottotrot911@hotmail.com

        Patters, thanks again for all your help.
        Unfortunately we stumbled upon a solution that just works, no vBS, every time.
        Win2k8 R2. Well, we didn’t discover it. I just finally convinced them upgrading was a must.

      8. Matt

        Shouldn’t disabling the UAC all together make this a far simpler affair? do i really need to enable it to get this to run properly? I would really rather not…

        I am in the same boat as Hot. If i log in as a standard user, member of only the domain users group, with no admin rights what so ever the script runs, but still fails to mount the drives. Once the machine is logged in, if i drill down to the domain\sysvol\policies\{sid}\scripts…. etc i can double click and run the .vbs just fine.

  4. Stephen

    I also have noticed a bit of latency with the drives mapping but I also assume that is part in the complexity of my actual login script. I have left UAC enabled on all of my hosts and User and Administrators map fine on WinXP and Win7 hosts.

    Reply
  5. Eric

    Have anyone noticed that if Task Scheduler launch the logon.vbs script that has a objShell.Run syntax to run another script, you will basically be prompted with the “Unknown Publisher” security warning when the new script is run. This doesn’t happen if the logon.vbs script is ran via the actual logon script GPO, only in Task Scheduler. This is giving me headaches as I have the logon.vbs calling some other scripts for users with administrative rights.

    Reply
  6. Steve

    Hi,

    I don’t know if this post is still being checked, but I recently implemented this script into our environment, and it worked almost very well. We have a mixture of laptops and desktops. The crazy thing seems to be that in XP, on laptops it worked just fine, but on desktops, it almost completely failed to map anyone’s drives (300+ users). Any idea why this would be? I can’t imagine this script is hardware-dependant.

    Thanks!

    Reply
    1. patters Post author

      Sounds like it could be down to some kind of Group Policy difference between the two types of machine in your environment perhaps?

      Reply
  7. Eric

    No. And it’s funny that no one seems to have this issue except for us. I haven’t really tried it but I did play around with the idea of creating multiple tasks in the Task Scheduler for each objShell.Run command.. What do you think?

    Reply
  8. PeterW

    Forget the launchapp. Add the registry key:

    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
    Create “EnableLinkedConnections” REG_DWORD, set value to 1

    This allows “muliple level” accounts to see the mappings made during logon by a script.
    The ultimate catch here is that this does not only affect Administrators but the “dummy” group Power Users as well.
    Have fun.
    Peter

    Reply
    1. patters Post author

      Doing that is a really bad idea. You’re merging two different security contexts, and disabling a security feature that Microsoft went out of their way to design. It’s not solving a problem, it’s setting up a huge one for later. It also clearly states in Microsoft’s KB article for this workaround (referenced in the 3rd paragraph of my post) that it’s unsupported – not a great situation for a production infrastructure.

      Reply
      1. Graham

        That’s all well and good patters, but what are we supposed to do?!
        Setting up mapped drives for multiple user types in a W2K3 domain is about as common a task as there is, & yet there is a Documented Problem stretching back to Vista on this!
        The registry hack isn’t ideal, but the workaround referenced in the technet article doesn’t work!!!!
        Typically poor form from Microsoft…
        Miscrosoft example script doesn’t work as is, & the echo lines are unnecessary & annoying.
        I’ve spent over an hour looking at various forums & the only reliable solution seems to be the registry hack.
        Options seem to be:
        i. the launchapp.wsf which doesn’t work for many users ( http://technet.microsoft.com/en-us/library/cc766208%28WS.10%29.aspx )
        ii. install additional power tools to elevate the script: ( http://social.technet.microsoft.com/Forums/en-IE/winserverGP/thread/ca9681db-8483-49c6-bb67-de52068fd494 )
        iii. install RSAT to Windows 7 to manage the domain ( http://www.sevenforums.com/network-sharing/21644-login-script-problems-2.html )
        iv. use the registry hack – referenced by MS themselves – http://support.microsoft.com/default.aspx?scid=kb;EN-US;937624

        A Frustrated Support Engineer

  9. Pingback: Problème de script de lecteurs réseaux par GPO sous Windows 7 : La Solution « Kevin PECQUET

  10. Pingback: What does registry setting EnableLinkedConnections do on a technical level? - Admins Goodies

  11. Pingback: Working in the new year

  12. Tim Crosby

    Wow, great script and many thanks for the time and effort you put into this. I had been wrestling with this for a few days now as we try to roll out Windows 7. I had read all the stuff saying that Admin users wouldn’t see their mapped drives because of the UAC problem. In our environment though, it was standard users who could not get mapped drives, but Admin users worked fine. But implementing your script in a Group Policy User Login script seems to have resolved it for us.

    Tim

    Reply
  13. Russ Collier

    I did not want to use the MS reg hack, but also I did not want to use Task Scheduler as I want to make sure the logon sciprt runs before the user gets the desktop. I found a simply modification to my existing logon scirpt solved the problem.

    In the existing logon script where you have code such as:
    objNetwork.MapNetworkDrive strDriveLetter, strUNC
    objNetwork.RemoveNetworkDrive strDriveLetter

    Replace with:
    objShell.Run “net use ” & strDriveLetter & ” ” & chr(34) & strUNC & Chr(34),0,True
    objShell.Run “net use ” & strDriveLetter & ” /d”,0,True

    This code maps drives for admins & non-admins alike and should be ok on any OS although I only tested on Win7 myself.

    I believe this works as the command line items called by the objShell.Run command are excecuted with the user token rather than the admin token (whereas the VBS is runnign in admin token), eitherway it works for me and seemed the simplest solution to the problem.

    Russ

    Reply
    1. Jose

      Russ, this doesn’t work. I get an error saying Object required: “.

      Code 800A01A8. I used your exact net use line to connect the drive and even changed my variables to match yours. Any ideas?

      Reply
  14. James

    Worked great, thanks. I’ve been putting off fixing this problem for months… Thanks again for posting the solution.

    Reply
  15. Pedroj

    Its great that others are willing to share their efforts, I am using this to add an extra ‘home drive’ for a migration of staff (teachers) to a new environment. We use group policy preferences usually and this works a treat for me.

    Reply
  16. John L

    Wow, leave it to the brilliant folks at Microsoft to mess up something as simple as logon scripts! Thanks for the write up, this was driving me nuts but I never did get around to diving in to the “why” behind the problem.

    As another solution, you can still use the old-style logon scripts by setting in User Profile…especially for things that don’t need to operate on users within a specific OU.

    Reply
  17. Chris

    Is there something that can be added to make the scheduled task Hidden? I’d prefer the users didn’t see the taskeng.exe window popup when they log in to their computer.

    Reply
  18. Chris Sanford

    Thanks for the script! In my case, the scheduled task took care of the elevated Win7 users, but did not work for non-elevated ones, or on WinXP. The script appeared to run, but drives were not getting mapped. Turns out that the fix was to disable the “run logon scripts syncronously” property in the GPO, as mentioned here: http://joshuamorgan.wordpress.com/2012/01/30/windows-7-wscript-shell-run-method-from-logon-script/ .

    Hope this helps somebody out there.

    chris

    Reply
  19. Pingback: Answer: Why won't my logon scripts map drives under Windows 7? #fix #answer #programming | Good Answer

  20. Pingback: How to: Why won't my logon scripts map drives under Windows 7? #answer #it #dev | IT Info

  21. Pingback: Answer: Why won't my logon scripts map drives under Windows 7? #solution #answer #it | SevenNet

  22. Pingback: Answer: What does registry setting EnableLinkedConnections do on a technical level? #solution #computers #answer | IT Info

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s