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
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 = 1strComputer = “.” 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 NextSet 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 = TRUESet 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 = &H80000001strComputer = “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.
0 comments