Changing what happens when a laptop lid is closed depending on its location

The other day a user complained that whenever he’d shut the laptop lid it would go to sleep. I checked the power settings in Windows 7 and sure enough it was set that way. So I changed it to not sleep, but the user called back the next day to say it slept off again! This looked like a policy setting so I ran gpresult. to get the policies applied to the computer:

Sure enough there was a policy that set the laptop to sleep when its lid was closed.

I checked with our Desktops team to change this but apparently this was intentional. For security reasons the firm didn’t want users closing their laptop lid when out of office – and the laptop stays powered on – with the risk that it could get stolen and its data can be accessed. If the laptop were to sleep at least the data is encrypted and cannot be accessed unless a user signs in. That made sense so what I needed was a way to set the laptop to sleep only if it’s in the office.

Step 1: Create a batch file

My immediate idea was to give the user a batch file he can double click on when in the office so it changes the laptop setting to not sleep. I knew that the powercfg command can do this so all I had to do was create a batch file with the two commands and leave it on the user desktop. When in office and the user wants to close his laptop lid, double click the file so the setting is changed. After a while GPOs will refresh and reset the setting anyways. Not great, but a quick and dirty fix to get things going.

The link I refer to earlier is for Windows Vista and it didn’t work on Windows 7. Not an issue, found one that does work.

To avoid the user running the batch file when out of the office, I added a bit to ping one of our DCs first before running the powercfg commands. ;-)

Final batch file was like this:

Easy peasy!

Step 2: Modify batch file for WiFi too

Then I thought why limit myself to the office LAN. What about when the user is in one of our meeting rooms for instance? The ping to DC will fail but we have office-wide WiFi so I can ping that instead. Thus the batch file was modified:

Step 3: Make batch file more generic

Nice! Ok, what can I do to target the laptop being in one of our offices in another country? They too have office WiFi but a different address. Yes I could create more GOTO sections like above but that’s not very neat is it? Moreover I don’t want users or my colleagues in IT to have to modify the batch file each time they want to add an IP address. The code and data should be independent. Less chances of errors too when modifications are made!

Thus was born the idea of putting all these IP addresses in a file and using a FOR loop to go through them. Wish I could have put the IP addresses in the same batch file but I couldn’t find a way of making a FOR loop iterate over elements in a variable. Anyhoo, not a big deal – a separate file is better too as there’s zero chance of anyone changing the code by mistake.

I wish my DOS Batch file skills were great, but they are not. I know the basics – like I knew the FOR loop could do what I want – but it’s been ages since I used batch files for any complicated stuff. Not a problem, did a bit of searching and I found an example I could modify. The important bit for me was to break out of the FOR loop once I find an office that match. For that I needed an IF clause.

While I was at it I also removed the ECHO line – which the user will never see as the batch file runs and closes anyway! – with a msg line. This command is present on Windows XP onwards so all our laptops have it by default. Here’s the net result:

Here’s the breakdown of what’s happening:

First, I create a file called C:\officepoints.txt. That file has IP addresses each on a line (or put them all in a line comma separated – that too will work):

The above file is read by the FOR loop. If the addresses are comma-separated that’s ok. Else it expects them on a line each. Read the address, ping it with one packet, check whether the result has the word “TTL” in it, and if yes set a variable bHOSTUP to 1. Unlike earlier I am now searching whether the ping output has the word “TTL” in it because I realized that when pinging the office WiFi the ping command would return with a non-error ERRORLEVEL (i.e. ERRORLEVEL is 0 and not 1 even though it can’t ping) because it thinks the destination is unreachable from the router rather than being unreachable from the laptop – so as far as ping is concerned it isn’t a laptop issue and so there’s no error. Not sure why it does that. Searching for the word “TTL” means such problems are overcome because all successful pings will contain the word “TTL” in them.

And that’s it really. Depending on whether it gets a ping for one of the IP addresses the FOR loop is existed and the appropriate powercfg command runs. If the loop is never exited thus, once it exits normally a powercfg command is run to ensure the laptop sleeps when the lid is closed.

Step 4: Automating it

This is all fine and dandy, so how about automating it? Rather than have the user double click a batch file can I make this happen automatically whenever he connects and disconnects? Yup … time is running out now so I will go into that in my next post! Stay tuned.