Restrict Local Account Logon Hours

Restrict non-domain accounts from logging in outside business hours using a scheduled task.

Script

$hour = (Get-Date).Hour
$day  = (Get-Date).DayOfWeek
 
$adminSids = @("S-1-5-32-544") # Local Administrators group SID
 
$nonAdminUsers = Get-LocalUser | Where-Object {
    $_.Enabled -ne $null -and
    (Get-LocalGroupMember -SID $adminSids[0] -ErrorAction SilentlyContinue).Name -notcontains "$env:COMPUTERNAME\$($_.Name)"
}
 
if ($day -ne 'Saturday' -and $day -ne 'Sunday' -and ($hour -ge 6 -and $hour -lt 21)) {
    $nonAdminUsers | Enable-LocalUser
} else {
    $nonAdminUsers | Disable-LocalUser
}

Checks that the time is the within the specified hours and the day isn’t a weekend. If it’s not it runs a loop to target and disable all non admin accounts.

The script to create this as a .ps1 in Program Data remotely can be found below.

Scheduled Task Setup

Create a single task with two triggers:

  • On schedule — Runs hourly to make sure it doesn’t get caught out
  • At startup — handles cases where the machine was off when a trigger fired

The startup trigger ensures the account state is correct regardless of when the machine was last on — the script checks the current time and enables or disables accordingly.

Script for that

$scriptPath = "C:\ProgramData\Scripts\Set-LocalAccountHours.ps1"
 
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
    -Argument "-ExecutionPolicy Bypass -NonInteractive -File `"$scriptPath`""
 
$triggerStartup = New-ScheduledTaskTrigger -AtStartup
$triggerHourly  = New-ScheduledTaskTrigger -Once -At (Get-Date) `
    -RepetitionInterval (New-TimeSpan -Hours 1)
 
$settings   = New-ScheduledTaskSettingsSet -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Minutes 1) -DisallowStartIfOnBatteries:$false -StopIfGoingOnBatteries:$false
$principal  = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
 
Register-ScheduledTask -TaskName "Set-LocalAccountHours" `
    -Action $action `
    -Trigger $triggerStartup, $triggerHourly `
    -Settings $settings `
    -Principal $principal `
    -Force

Create the script via RMM etc

All non-admin accounts

$dir = "C:\ProgramData\Scripts"
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
 
$content = @'
$hour = (Get-Date).Hour
$day  = (Get-Date).DayOfWeek
 
$adminSids = @("S-1-5-32-544")
 
$nonAdminUsers = Get-LocalUser | Where-Object {
    $_.Enabled -ne $null -and
    (Get-LocalGroupMember -SID $adminSids[0] -ErrorAction SilentlyContinue).Name -notcontains "$env:COMPUTERNAME\$($_.Name)"
}
 
if ($day -ne 'Saturday' -and $day -ne 'Sunday' -and ($hour -ge 6 -and $hour -lt 21)) {
    $nonAdminUsers | Enable-LocalUser
} else {
    $nonAdminUsers | Disable-LocalUser
}
'@
 
Set-Content -Path "$dir\Set-LocalAccountHours.ps1" -Value $content -Encoding UTF8

Single named account (Ninja — uses $env:accountname variable)

$dir = "C:\ProgramData\Scripts"
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
 
$content = @"
`$hour = (Get-Date).Hour
`$day  = (Get-Date).DayOfWeek
 
`$accounts = @("$env:accountname")
 
if (`$day -ne 'Saturday' -and `$day -ne 'Sunday' -and (`$hour -ge 6 -and `$hour -lt 21)) {
    `$accounts | ForEach-Object { Enable-LocalUser -Name `$_ }
} else {
    `$accounts | ForEach-Object { Disable-LocalUser -Name `$_ }
}
"@
 
Set-Content -Path "$dir\Set-LocalAccountHours.ps1" -Value $content -Encoding UTF8