Totalitarian Control: How We Used PowerShell to Manipulate User Behavior

by Sum Yunggai

At my place of employment, there is a culture of totalitarianism, an isolationist departmental approach, and a lot of misunderstanding and outright rebellion when it comes to rules, policy, or any kind of standardization.

I'll try to be brief, but let me set the scene: our workforce is on a virtual environment for the most part, but a select few users have actual PCs instead of thin clients.  There has been much argument and near fist fights from the PC users to also have a laptop that they can use to travel in the field.  Now, normally that would not be an issue.  Users are responsible, right?  Our issue is that we turn on offline file sync because we use folder redirection.  (Don't give me grief; I'm not paid the decision making salary.)

This presents a problem because the users will never bring their laptops in to connect to the domain to sync.  Enter PowerShell and Group Policy Objects (GPO).

With some rather simple scripting, a few new GPOs, and some tweaking, we were able to "fix" (force) the issue and, at the same time, we have created a solution to the decades-old argument of security issues behind cached credentials.

First things first, the PowerShell script.  There are three sets of code needed.  The first is a script to output the current date to a text file and save it on the C drive.  It resets two registry keys to their default values for allowing credential caching:

get-date -format u > c:\windows\date.txt
New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\Current Version\Winlogon" -Name "ForceUnlockLogon" -Value "0" -PropertyType DWORD -Force | Out-Null
New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\Current Version\Winlogon" -Name "CachedLogonsCount" -Value "10" -PropertyType String -Force | Out-Null

The ForceUnlockLogon key with value 0 ensures that a domain controller is not required to unlock the workstation.  The CachedLogonsCount key with value 10 allows for ten different sets of credentials to be cached in the OS credential vault.  These values are the default for these keys.

Creating a text file with the current date and saving it to C is an essential part for the operations to follow.  The above code is executed as a logon script via a GPO when the user authenticates to the network.  (Creating GPOs and setting logon scripts is beyond the scope of this article.)  The GPO also installs the next two scripts onto the laptop.  All of this is rather simple and non-damaging.

Next, we come to the interesting bits of the whole thing.  We have two security groups we have created on our domain for this operation: one for users on a seven-day timer and one for a 30-day timer.  The seven-day group is for laptop users who do not do extended days in the field and should be bringing their laptop in to the office and authenticating to the domain on a regular basis.  The 30-day group is for users on extended leave or some kind of extended project to allow for leeway.  We then have a GPO that will initiate a scheduled task on the local machine.  This task will run the following script every hour:

$logontime = Get-Content c:\windows\date.txt
$currenttime = get-date -format u
$timespan = (New-TimeSpan -Start $logontime -End $currenttime).TotalDays
if ($timespan -gt 8) {
  New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "ForceUnlockLogon" -Value "1" -PropertyType DWORD -Force | Out-Null
  New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "CachedLogonsCount" -Value "0" -PropertyType String -Force | Out-Null
}

Essentially, this script looks at the date file we created on C earlier and compares it to the current date and time of the local machine.

The above script being for the seven-day users, if the current date is greater than eight days from the date in the file, the registry value for ForceUnlockLogon is changed to 1 (true), which causes the machine to require authentication to a domain controller to unlock from a locked state, and it also changes CachedLogonsCount to 0 which effectively causes the user to have to be authenticated to a domain controller to be able to log in.

Thus, if the user locks the machine or powers down and this script has triggered because they have not authenticated their machine to the network within seven days to sync offline files like we asked them to time and time again, they are now effectively locked out from being able to work until they authenticate.

We set the counter to eight days because if the laptop is authenticated on the domain, the timer still runs.  Therefore, if they spend a day in the office with the machine, we don't want that day counting against them, so it's a freebie.  For the 30-day group, we simply changed the if statement to read: ($timespan -gt 30)

How does the task determine which script to trigger?  We used Item Level Targeting for that at the GPO level in an effort to keep the number of GPOs in use on our network a little cleaner, but it could also be done with two different GPOs.

So remember kids, the next time your IT department asks you to do something very simple but very important, and you refuse to follow instructions, just know that we have ways of making you do what we want you to do!

Return to $2600 Index