Can I Lock a Workstation Using a Script?

Can I Lock a Workstation Using a Script?

  • Comments 4
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! I know how I can shut down a computer using a script, and I even know how I can log a user off using a script. But is there any way I can lock a workstation using a script?

-- TO-R

SpacerHey, Scripting Guy! AnswerScript Center

Hey, TO-R. Most likely you’re familiar with the Win32Shutdown method found in the WMI class Win32_OperatingSystem; that method allows you to shutdown or reboot a computer, or log off the current user. For example, this script shuts down a computer:

Const SHUTDOWN = 1

strComputer = "."
Set objWMIService = GetObject_
    ("winmgmts:{impersonationLevel=impersonate,(Shutdown)}\\" & _
        strComputer & "\root\cimv2")

Set colOperating Systems = objWMIService.ExecQuery _
    ("Select * from Win32_OperatingSystem")
 
For Each objOperatingSystem in colOperatingSystems
    objOperatingSystem.Win32Shutdown(SHUTDOWN)
Next

What the Win32Shutdown method won’t let you do is lock a computer; as near as we can tell nothing within WMI allows you to lock a computer. In fact, the only way we could figure out how to lock a computer using a script was to write a script that did nothing more than use Rundll32.exe to call the LockWorkStation method of user32.dll:

On Error Resume Next

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "%windir%\System32\rundll32.exe user32.dll,LockWorkStation"

This works great for the local computer, but doesn’t do you much good if you’re trying to lock a remote computer; you can’t specify a remote computer name when running Rundll32.exe. But that’s OK: if this script only runs locally, then all we have to do is make sure it runs locally on the remote computer. Can we do such a thing? You bet we can.

First, save the preceding script - the one that actually locks the computer - as Lock_workstation.vbs and - for simplicity’s sake - save it to C:\Scripts. Next, create a second script - give it any name you want - and paste this code into it:

Const OverwriteExisting = TRUE

Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.CopyFile "C:\Scripts\lock_workstation.vbs", _
    "\\atl-ws-01\C$\Scripts\", OverWriteExisting

strComputer = "atl-ws-01"
Set objWMIService = GetObject _
("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")

Error = objWMIService.Create _
    ("cscript c:\scripts\lock_workstation.vbs", null, null, _
        intProcessID)

What does this code do? Well, to begin with, it copies our first script - C:\Scripts\Lock_workstation.vbs - to the C:\Scripts folder on the remote computer atl-ws-01. Two things to keep in mind here. First, the script assumes that you haven’t disabled the administrative share (C$) on the remote computer; second, it assumes that the folder C:\Scripts exists in the remote computer. (Of course, there’s no reason why the file has to be copied to C:\Scripts; you can copy it to any folder you want.)

After the first part of the script executes, the file Lock_workstation.vbs will be sitting in the C:\Scripts folder on the remote computer. In the second part of the script, we connect to the WMI service on the remote computer, and then call the Create method (which happens to be part of the Win32_Process class). And what exactly do we do with the Create method? Well, we simply run the script Lock_workstation.vbs. What’s cool about that, however, is that the Create method will cause the script to run on the remote machine. And because the script is running on the remote machine, Rundll32.exe will work, and the remote computer will be locked. Give it a try, and you’ll see for yourself.

Note. One caveat: this script runs under the security context of the user logged on the remote computer. If that user doesn’t have the right to lock the computer, then the script will fail.

Of course, this is bound to raise at least two questions. Let’s take the easy one first: can you write a script that unlocks a workstation? As far as we know, you can’t; in fact, as far as we know the only way to unlock a workstation is to have someone go to the computer, press Ctrl-Alt-Delete and log on. On the bright side, though, you can still run scripts against a locked workstation; after all, a locked computer is still up and running.

The second question is a bit trickier: is there any way to tell whether or not a computer actually is locked? Well, there’s no foolproof way, at least not that we’re aware of. But here’s a script that can work, as long as:

1. The remote computer is configured to use a screensaver.

2. The workstation is automatically locked any time the screensaver is running.

3. The “timeout” period has elapsed and the screensaver is actually running. (For example, by default the screensaver doesn’t start up until a computer has been inactive - or locked - for ten minutes.)

If all the above are true, this script can tell you if the computer is locked; it does that by grabbing the executable file name for the screen saver, and then checking to see if that executable file is running (by looking at instances of the Win32_Process class). If the screensaver is running then, by definition, the computer must be locked:

On Error Resume Next
HKEY_CURRENT_USER = &H80000001

strComputer = "crowtrobot2"

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")

strKeyPath = "Control Panel\Desktop"
ValueName = "ScrnSave.exe"
objWMIService.GetStringValue HKEY_CURRENT_USER, strKeyPath, ValueName, strValue
strValue = Replace(strValue, "\", "\\")

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery _
    ("Select * From Win32_Process Where ExecutablePath ='" & strValue & "'")

If colItems.Count > 0 Then
    Wscript.Echo "The computer is locked."
Else
    Wscript.Echo "The computer is not locked."
End If

Note that this script isn’t quite as complicated as it looks; the one weird part is this line of code:

strValue = Replace(strValue, "\", "\\")

That’s needed because the ExecutablePath will be something like this:

C:\WINDOWS\System32\logon.scr

However, when you use a path in a WMI query, you have to double up all your slashes, like so:

C:\\WINDOWS\\System32\\logon.scr

That’s what the Replace function is doing: replacing each \ with \\.

Like we said, it’s not exactly foolproof, but it’s the best we’ve been able to come up with so far. If you wanted to make it a little bit more bulletproof, you could add code that ensures that the computer is actually using a screensaver (ScreenSaverActive) and that the workstation automatically locks any time the screensaver is running (ScreenSaverSecure). If you wanted to get really fancy, you could even determine the screensaver timeout value (ScreenSaverTimeout), pause the script for that amount of time, and then check to see if the screensaver is running.

Of course, even that wouldn’t suffice in all cases: after all, this code won’t distinguish between a computer that’s locked and a computer where no one is logged on; it just tells us that the screensaver is running. Is there a way to tell whether or not any one is logged on to a computer? We’re not really sure, to tell you the truth, but that’s something we’re looking into.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • You could check for explorer.exe on the remote computer to see if anyone was logged in or not, if explorer.exe is not running then no-one is logged in even if the screensaver is running (unless they're using a different shell of course).

  • "... write a script that did nothing more than use Rundll32.exe to call the LockWorkStation method of user32.dll"

    Sorry for this dumb question but what type of file should I save the script into - vb, vbs, etc?

  • Script to check if a user is logged in. If it returns a blank value than no one is logged in. (tested against xp machines)

    ------------------------------------------------------------

    Function funChkUsername()

    Set objWMIService = GetObject("winmgmts:\\" & Hostname & "\root\cimv2")

    Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem")

       For Each objItem in colItems

         wscript.echo objItem.UserName  

    Next

    End Function

  • I created my scripts, the file does get created on the remote machine. the remote computer doesn't lock.

    This is what I used for my script:

    Const OverwriteExisting = TRUE

    Set objFSO = CreateObject("Scripting.FileSystemObject")

    objFSO.CopyFile "C:\BACKUP\Scripts\Lock_workstation.vbs", _

       "\\t61p\C$\", OverWriteExisting

    strComputer = "t61p"

    Set objWMIService = GetObject _

    ("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")

    Error = objWMIService.Create _

       ("cscript c:\Lock_workstation.vbs", null, null, _

           intProcessID)

    I assumed the 2nd to the last line should be the path to the file that was copied.

    I also don't understand why we use "Error = " (on the 3rd to the last line