Autolock - lock your laptop when not at home

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Bon
Posts: 17
Joined: 11 Jan 2014, 07:31

Autolock - lock your laptop when not at home

29 May 2014, 03:24

If you are like me, you like to fire up your laptop, grab a cup of coffee, and then come back to a computer that is all ready and waiting for you. But that means you have to logon automatically, which is very handy, but not very secure. So the ideal solution would be enable autologon when at home, or any other "safe" place, while disbling autologon at any other place. This script does just that. But please read the comments - they are essential to make it work!
Suggestions and comments are welcome.

Code: Select all

/*
	AutoLock - locks your laptop when not at home.
	
	This is done by checking which wireless networks (SSIDs) are visible, and comparing them to a predefined list.
	If there is at least one match, the computer is considered to be "at home", otherwise possibly stolen.
	
	Normally, Autologon for Windows (see below) logs you in automatically.
	But if your laptop is not "at home", your computer will be locked and you must press the correct unlock key (PassChar).
	Failing to do that, you get one (1) chance to enter the correct password, thus unlocking and restoring Autologon.
	The wrong password takes you to the login screen, where you from now on must log in manually.
	(Until you reset the password).
	
	Prerequisites:
	1) A password-protected Windows account
	2) Autologon for Windows, a nifty little utility from SysInternals, which you can get at 
	http://technet.microsoft.com/en-us/sysinternals/bb963905.aspx
		
	Mostly for fun, I stored the passcharacter and password in an Alternate Data Stream (ADS) in the script file itself (or in the compiled exe)
	Not many editors can handle ADS, although Notepad.exe actually does.
	
	You can use "t" as PassChar for testing purposes; this will always assume you are not at home.
	If you feel uncomfortable storing your Windows password, you can use any other password. 
	In this case, you will have to manually reset your password in AutoLogon for Windows.
	
	Note: UAC may cause trouble (it usually does!), especially on Win8. 
	You need to run the script with elevated privileges, thus also raising Autologon's privileges.
	To do this, you can, instead of creating an ordinary shortcut to the script in Autostart, use Task Scheduler: 
	Schtasks /Create /RU "<mycomputername>\<myusername>" /SC ONLOGON /TN "AUTOLOCK" /TR "'C:\Program Files (x86)\AHK\AutoLock.ahk'" /IT /V1
	(of course, use your own path, computername and username)
	NOTE!!! This will create a task that will *not* run when the computer is on battery power. You must manually 
	(there is no way to do this via the command line, afaik (please correct me if I'm wrong)) uncheck 
	"Start the task only if the computer is on AC power" and "Stop if the computer switches to battery power" 
	in the "Conditions" tab in the GUI of Task Scheduler!
	OR
	try Jeff Main's cool Program Elevator at http://www.autohotkey.com/board/topic/61042-create-a-scheduled-task-natively-ahk-l/
	
	You might also try ElevatedShortcut, which can be found at http://winaero.com/comment.php?comment.news.152
	
	Written by BON 2014-04-29 for AHK_L. Should work for AHK Basic, but not tested.
*/

#SingleInstance force
#NoEnv

SetWorkingDir %A_ScriptDir%
Menu, Tray, Icon, Shell32.dll, -259
Menu, Tray, NoStandard
Menu, Tray, Add, Reset, Reset
Menu, Tray, Add, Exit, Exit
Menu, Tray, Disable, Reset
Menu, Tray, Disable, Exit
Menu, Tray, Tip, Location unknown

FileReadLine, Pass, %A_ScriptFullPath%:ini,1						; Password and -character are hidden in an alternate stream in this file
If Pass =
	{
		MsgBox, 36, No password,No password found!`rWould you like to set a password and passcharacter now?
		IfMsgBox Yes
			{
				Loop
					{
						InputBox, PassChar,,Type the character you want to use as passcharacter`r(only one character!),,250,200
						If ErrorLevel
							ExitApp
						If StrLen(PassChar) = 1
							Break
						MsgBox,48,,Only ONE character!`rTry again!
					}
				InputBox, PassWord,Enter password,
				(
Enter your Windows password:

Make sure you get it right!
It is used to set the Autologon password.

If you enter the wrong password here, you must 
reset all passwords from the menu.
				)
				,HIDE,400,350
				If ErrorLevel
					ExitApp
					
				;Write encrypted passchar & password to ADS
				Pass := Encrypt(PassChar Password, "We dont want no stinkin unencrypted password")
				RunWait, %comspec% /c "echo %Pass%>"%A_ScriptFullPath%":ini",,Hide
					
				;Enable Autologon with the given password
				AutoLogonLocation := A_ProgramFiles "\Autologon.exe"		; An educated guess
				If !FileExist(AutoLogonLocation)
					{
						FileSelectFile AutoLogonLocation, 1, Autologon.exe, Show me where AutoLogon is:, Autologon.exe 
						If ErrorLevel
							ExitApp
					}
				RunWait, %comspec% /c "echo %AutoLogonLocation%>>"%A_ScriptFullPath%":ini",,Hide
				Run, %AutoLogonLocation% %A_UserName% %A_ComputerName% %PassWord%
								
				;Create a list of "safe" networks
				x := ListOfNetworks()
				RegExReplace(x,",",",",y)							; Count # commas, ie networks-1
				If ++y > 0
					{
						RunWait, %comspec% /c "echo %x%>>"%A_ScriptFullPath%":ini",,Hide
						MsgBox, 64,, List of %y% home networks successfully created.
					}
			}
	}
	
Pass := Decrypt(Pass, "We dont want no stinkin unencrypted password")
global PassChar := Substr(Pass, 1, 1)								; PassChar: First character
global PassWord := SubStr(Pass, 2)									; PassWord: Your Windows account pw, starting in col 2
If PassWord =
	ExitApp
	
global AutoLogonLocation	
FileReadLine, AutoLogonLocation, %A_ScriptFullPath%:ini,2
	If !FileExist(AutoLogonLocation)
		{
			MsgBox,48,,Cannot find AutoLogon.exe - quitting!,10
			RunWait, %comspec% /c "echo.>"%A_ScriptFullPath%":ini",,Hide	;Empty the ini-ADS -> forces initialization on next run
			ExitApp
		}	
		
global AllPredefinedNetworks		
FileReadLine, AllPredefinedNetworks, %A_ScriptFullPath%:ini,3
If AllPredefinedNetworks =
	{
		MsgBox,48,,No visible networks - cannot continue!,10
		RunWait, %comspec% /c "echo.>"%A_ScriptFullPath%":ini",,Hide	;Empty the ini-ADS -> forces initialization on next run
		ExitApp
	}
						
OnMessage(0x218, "PowerChg")										; Will kick in as soon as the computer wakes up from sleep
SetTimer LockIfNotAtHome, -30000									; Wait half a minute; then check ONCE
Return

PowerChg(wParam, lParam)
	{
		If wParam In 7,8,18                                     	; Waking up...
			SetTimer LockIfNotAtHome, -30000						; Wait half a minute; then check ONCE
	}

LockIfNotAtHome:
		SetTimer LockIfNotAtHome, 1800000							; Check every 30 minutes, in case stolen while not sleeping
		If PassChar <> T											; Test
			If AtHome()
				{
					Menu, Tray, Tip, At home
					Menu, Tray, Enable, Reset
					Menu, Tray, Enable, Exit
					Return
				}
				
		Menu, Tray, DeleteAll
		Run, %AutoLogonLocation% "" "" ""							; Disable Autologon
		Hotkey !Tab, NULL                   						; Disable alt-tab
		BlockInput, MouseMove               						; Disable MouseMoves
		ToolTip Locked! Waiting for Input
		SoundPlay *48												; Exclamation sound
		Input, SingleKey, L1                						; Wait for user to press a key
		ToolTip														; Remove tooltip
		If (SingleKey <> PassChar)          						; PassChar?
			{                               						; No, so demand full password
				String =
				InputBox String, Computer is locked!, Password:, HIDE, 250, 150
				If String <> %PassWord%
					{
						Shutdown, 0									; Log off
						ExitApp
					}
			}
			
		SoundPlay *-1                       ; Play sound to announce computer successfully unlocked
		Hotkey !Tab, Off                    ; Restore alt-tab
		BlockInput MouseMoveOff             ; Restore Mouse moves
		Run, %AutoLogonLocation% %A_UserName% %A_ComputerName% %PassWord%	; Enable Autologon with the given password				

		x := ListOfNetworks()
		If x <>
			{
				MsgBox,33,,Do you wish to add the currently visible locations to the list of predefined home locations?
				IfMsgBox OK
						{
							AllPredefinedNetworks .= "," x
							Pass := Encrypt(PassChar Password, "We dont want no stinkin unencrypted password")
							RunWait, %comspec% /c "echo %Pass%>"%A_ScriptFullPath%":ini",,Hide
							RunWait, %comspec% /c "echo %AutoLogonLocation%>>"%A_ScriptFullPath%":ini",,Hide
							RunWait, %comspec% /c "echo %AllPredefinedNetworks%>>"%A_ScriptFullPath%":ini",,Hide
					}
			}
		Menu, Tray, Tip, Not at home
		Menu, Tray, Enable, Reset
		Menu, Tray, Enable, Exit
		Return
    
AtHome()	
	{
		x := ListOfNetworks()
		If x Contains %AllPredefinedNetworks%
			Return True
	}
	
NULL:                                   ; Dummy routine for alt-tab (does nothing)
	Return    
	
ListOfNetworks()	
	{
		RunWait, %comspec% /c netsh wlan show networks > %A_Temp%\Nets.txt,,Hide
		FileRead, Nets, %A_Temp%\Nets.txt
		Loop
			{
				Nets := TL_Rightof(Nets, "SSID ")
				Networks := Networks . TL_Between(Nets, " : ","`r") . ","
			} Until Nets = ""
			
		Networks := TL_Leftof(Networks, ",,")
		If Networks = ,
			Networks =
		Else
			FileDelete %A_Temp%\Nets.txt				; Delete in case of success; otherwise keep for debugging
		Return Networks
	}
	
Reset:
	RunWait, %comspec% /c "echo.>"%A_ScriptFullPath%":ini",,Hide	;Empty the ini-ADS -> forces initialization on next run
	Reload
	Return
	
Exit:	
	ExitApp
	Return
/*
***************************************************************************************************************	
Some helper routines
***************************************************************************************************************
*/

TL_Word(Haystack, Nr, Delim)                            

;Returns any "word" in Haystack ("word" being defined as anything between delimiters)    
;If Nr is negative, count from back
;Examples:
;TL_Word("c:\abc\def.x", 1, "\") returns "c:"
;TL_Word("c:\abc\def.x", -1, "\") returns "def.x"
;TL_Word("c:\abc\def.x", -2, "\") returns "abc"

    {
        StringReplace, X, Haystack, %Delim%, ¢, All     ;Make sure delim is only one character

        If Nr < 0
            StringReplace, X, X, ¢, ¢, UseErrorLevel    ;Count # occurences
        MaxInd := ++ErrorLevel

        Loop, Parse, X, ¢
        If (A_Index = Nr) || (A_Index = MaxInd + Nr + 1)
            Return, A_LoopField             
    }

TL_LeftOf(Haystack, Needle)     

;Returns substring of Haystack from beginning of Haystack up to, but not including, Needle
;If Needle is not found, returns entire string
;Note: works diffently than RightOf - might seem awkward, but imagine a virtual delimiter at the end of Haystack

    {
        i := InStr(Haystack, Needle)
        If i
        	Return SubStr(Haystack, 1, --i)
        Else
            Return Haystack
    }    
    
TL_RightOf(Haystack, Needle)

;Returns substring of Haystack from Needle to end of Haystack
;If Needle is not found, returns empty string
;Note: works diffently than LeftOf - might seem awkward, but imagine a virtual delimiter at the end of Haystack

    {
        i := InStr(Haystack, Needle)
        If i
            Return SubStr(Haystack, i + StrLen(Needle))            
    }    
    
TL_Between(Haystack, Needle1, Needle2="")

;Returns substring of Haystack between Needles
;If Needle1 is not found, returns empty string
;If Needle2 is not found, returns from Needle1 to end of Haystack
;Needle2 is optional

    {                                       
        If Needle2 = 
            Needle2 := Needle1
        Return TL_LeftOf(TL_RightOf(Haystack, Needle1), Needle2)
    }
	
/* 
	Encrypt / decrypt
	Stolen from Laszlo, http://www.autohotkey.com/board/topic/6316-rc4-encryption-to-hex-stream/ 
*/

Encrypt(Data,Pass) {
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*2)
   Loop 256
      a := A_Index - 1
     ,Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
     ,sBox%a% := a
   Loop 256
      a := A_Index - 1
     ,b := b + sBox%a% + Key%a%  & 255
     ,sBox%a% := (sBox%b%+0, sBox%b% := sBox%a%) ; SWAP(a,b)
   Loop Parse, Data
      i := A_Index & 255
     ,j := sBox%i% + j  & 255
     ,k := sBox%i% + sBox%j%  & 255
     ,sBox%i% := (sBox%j%+0, sBox%j% := sBox%i%) ; SWAP(i,j)
     ,Result .= SubStr(Asc(A_LoopField)^sBox%k%, -1, 2)
   StringReplace Result, Result, x, 0, All
   SetFormat Integer, %Format%
   Return Result
}

Decrypt(Data,Pass) {
   b := 0, j := 0, x := "0x"
   VarSetCapacity(Result,StrLen(Data)//2)
   Loop 256
      a := A_Index - 1
     ,Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
     ,sBox%a% := a
   Loop 256
      a := A_Index - 1
     ,b := b + sBox%a% + Key%a%  & 255
     ,sBox%a% := (sBox%b%+0, sBox%b% := sBox%a%) ; SWAP(a,b)
   Loop % StrLen(Data)//2
      i := A_Index  & 255
     ,j := sBox%i% + j  & 255
     ,k := sBox%i% + sBox%j%  & 255
     ,sBox%i% := (sBox%j%+0, sBox%j% := sBox%i%) ; SWAP(i,j)
     ,Result .= Chr((x . SubStr(Data,2*A_Index-1,2)) ^ sBox%k%)
   Return Result
}
Quidquid Latine dictum sit altum videtur
"Anything said in Latin sounds profound"
User avatar
Grendahl
Posts: 170
Joined: 30 Sep 2013, 08:21

Re: Autolock - lock your laptop when not at home

02 Jun 2014, 07:33

Is there an advantage to using the SysInternals app, when all you need for autologin is to set a few registry keys?

Code: Select all

RegWrite, REG_SZ, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon, AutoAdminLogon, 1
RegWrite, REG_SZ, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon, DefaultUserName, %User%
RegWrite, REG_SZ, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon, DefaultPassword, %Password%
RegWrite, REG_SZ, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon, DefaultDomainName, %Domain%
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Autolock - lock your laptop when not at home

02 Jun 2014, 12:44

The SysInternals app encrypts the password.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
User avatar
Thoughtfu1Tux
Posts: 125
Joined: 31 May 2018, 23:26

Re: Autolock - lock your laptop when not at home

04 Jul 2019, 23:47

I've been looking everywhere for a way to run a script when i'm on my home network and run a different script when i'm away from home.This is perfect, thank you!
User avatar
watagan
Posts: 80
Joined: 03 Nov 2020, 05:17

Re: Autolock - lock your laptop when not at home

26 Nov 2020, 03:51

Inspired by your TL_LeftOf function, I created a shorter one with some changes.

-Work for both sides.
-Works for strings longer than one character.
-Optional parameter to return empty if needle not found.

Code: Select all

#noEnv
#persistent
#singleInstance force
setWorkingDir %a_scriptDir%

msgBox, % str_befAf( "cats are cool" , "cats " , "R"    )
msgBox, % str_befAf( "cats are cool" , "ca-ts ", "R", 0 )
msgBox, % str_befAf( "cats are cool" , "ca-ts ", "R", 1 )
msgBox, % str_befAf( "cats are cool" , " are " , "l"    )
msgBox, % str_befAf( "cats are cool" , " ar-e ", "l", 0 )
msgBox, % str_befAf( "cats are cool" , " ar-e ", "l", 1 )
exitApp

str_befAf(Haystack, Needle, Pos:="L", elseRetEmpty:=0){
	HS:=Haystack
	NL:=Needle
	EL:=elseRetEmpty
	return (Pos="R") ? ((I:=InStr(HS, NL)) ? subStr(HS, I+strLen(NL)) : (EL ? "" : HS))
		: (I := InStr(HS, NL)) ? subStr(HS, 1, --I) : (EL ? "" : HS)
}

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 104 guests