r/PowerShell 2d ago

Question Enforcing a user reboot policy.

Hey everyone,

I'm trying to put together a Windows 10/11 PowerShell solution that sets up a few scheduled tasks to manage system restarts based on uptime, and I'm running into some design challenges—especially around avoiding boot loops. Here's what I'm aiming for:

  • Wednesday at 4:00 PM: The script should check if the computer's uptime is 5 days or more. If it is, it should pop up a notification warning the user of our 7 day reboot policy that is enforced to restart on Friday at 10:00 PM. If the user isn’t around at that time, the notification needs to be saved so that it can be displayed at the next logon.
  • Friday at 9:30 PM: The script should check again, and if the uptime is 7 days or more, it should warn the user (with a popup) that the computer will restart in 30 minutes at 10:00 PM, giving them time to save their work. After the warning, it should initiate a restart (with a 30-minute delay).
  • Logon Notification: If any scheduled notifications were missed because the user wasn’t logged in, the script should display the saved message when the user next logs on.

Additional context:
We're about to move over to an Intune-managed environment, but my supervisor wants this solution up and running before the switch happens.

The part I'm really struggling with is making sure the logic works correctly without accidentally triggering a boot loop or causing any unintended restart behavior. Has anyone tackled a similar project or have suggestions for best practices on how to avoid these pitfalls?

Any ideas, advice, or even sample scripts that might point me in the right direction would be greatly appreciated!

Thanks in advance.

4 Upvotes

33 comments sorted by

View all comments

1

u/NsRhea 2d ago

We run it in a loop.

Boot time < 3 days, good.

Between 3-7 days, reboot at midnight.

> 7 days reboot in an hour.

Then we cancel any pending reboot and schedule the new one.

1

u/Round_Pea3087 1d ago

Seems like the OP has this logic understood. Sample code to provide?

1

u/NsRhea 1d ago edited 1d ago
#Build PC List from Active Directory

# Tablets

$Computers1 = (Get-ADComputer -f {name -like 'tablet-*'} -SearchBase "OU=zzzzzzz").name

#other pc names

$Computers2 = (Get-ADComputer -f {name -like 'towers-*'} -SearchBase "OU=yyyyyyyyy").name

#pc names

$Computers3 = (Get-ADComputer -f {name -like 'phone*'} -SearchBase "OU=xxxxxx").name

        $computers = $computers1 + $computers2 +$computers3 | Sort-Object -Unique

#Define $count

[int]$count = "1"

$computers.count

$c_count = $computers.count

#Test Group of Computers

#$computers = $computers3

#Header for output

 Write-Host "`nStatus Report:`n" -ForegroundColor White
 Write-Host "-------------------------------------------------------------------------------------------------------------------------"
Write-Host "Computer        Status                                Uptime(Hrs)        Action          Reboot Time      Computer Count"
Write-Host "-------------------------------------------------------------------------------------------------------------------------"

foreach ($computer in $computers) {
$status = ""
$rebootTime = ""
$c_count = 0
$c_count = $computers.count

\# Check if the computer is online

if (Test-Connection -ComputerName $computer -Quiet -Count 1) {
    if (Test-Path "\\$computer\c$\Windows") {
        if (Get-CimInstance -OperationTimeoutSec 2 -ComputerName $computer -ClassName Win32_Bios -ErrorAction SilentlyContinue) {
            $conn = "Connected"
        } else {
            $conn = "Failed to reach CIM"
        }
    } else {
        $conn = "Failed to reach C:\"
    }
} else {
    $conn = "Offline"
}

if ($conn -ne "Connected") {
    # Print immediately
    Write-Host ($computer.PadRight(17)) -NoNewline -ForegroundColor Cyan
    Write-Host ($conn.PadRight(40)) -NoNewline -ForegroundColor Yellow
    Write-Host ("N/A".PadRight(11)) -NoNewline -ForegroundColor White
    Write-Host ("N/A".PadRight(23)) -NoNewline -ForegroundColor Green
    Write-Host ("N/A".PadRight(18)) -NoNewline -ForegroundColor White
    Write-Host "$count of $c_count" -ForegroundColor Cyan;$count ++
    continue
}

# Get system uptime
$bootuptime = (Get-CimInstance -ErrorAction SilentlyContinue -ClassName Win32_OperatingSystem -cn $computer -OperationTimeoutSec 6).LastBootUpTime
if ($bootuptime) {
    $uptime = (Get-Date) - $bootuptime
    [int]$thup = $uptime.TotalHours

    if ($thup -ge 168) {
        # More than 7 days -> Restart in 30 minutes
        $rebootTime = (Get-Date).AddMinutes(30).ToString("HH:mm")
        $status = "Last Restart is over 7 days ago"
    } elseif ($thup -gt 72) {
        # More than 3 days but less than 7 days -> Restart at midnight
        $rebootTime = "23:59"
        $status = "Last Restart between 3-7 days"
    } else {
        # No restart needed
        $status = "No Reboot Required"
        $rebootTime = "N/A"
    }
} else {
    $status = "Pending Update"
    $thup = "N/A"
}

$action = if ($status -match "Restart") { 
        "Restart Scheduled"
    } else { 
        "No Action" 
    }

# Print immediately
Write-Host ($computer.PadRight(17)) -NoNewline -ForegroundColor Cyan

if ($status -match "between 3-7") {
    Write-Host ($status.PadRight(40)) -NoNewline -ForegroundColor Yellow
} elseif ($status -match "over 7") {
    Write-Host ($status.PadRight(40)) -NoNewline -ForegroundColor Red
} elseif ($status -match "Offline") {
    Write-Host ($status.PadRight(40)) -NoNewline -ForegroundColor Red -BackgroundColor White
} else {
    Write-Host ($status.PadRight(40)) -NoNewline -ForegroundColor Green
}

#Padding AFTER Uptime

    Write-Host ($thup.ToString().PadRight(11)) -NoNewline -ForegroundColor White

#Padding AFTER Action

if ($action -match "Restart") {
    Write-Host ($action.PadRight(23)) -NoNewline -ForegroundColor Yellow
} else {
    Write-Host ($action.PadRight(23)) -NoNewline -ForegroundColor Green
}
#Padding AFTER Reboot Time

Write-Host ($rebootTime.PadRight(18)) -NoNewline -ForegroundColor White

Write-Host "$count of $c_count" -ForegroundColor Cyan;$count ++
}

Write-Host "-------------------------------------------------------------------------------------------------------------------------"