Skip to content

A Simple PowerShell Script that once ran will prevent windows update from every rebooting your PC again automatically.

License

Notifications You must be signed in to change notification settings

cboileau/FWindowsUpdateReboot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FWindowsUpdateReboot

example workflow

A Simple PowerShell Script that once ran will prevent windows update from every rebooting your PC again automatically.

How to install

Option 1:

  1. Download the script
  2. Right click the script and select "Run with Powershell"
  3. When prompted, click "Yes" to run the script with administrator privileges
  4. Give Windows Update the finger, you have finally defeated it.

Option 2:

  1. Download the script
  2. Open a PowerShell window with administrator privileges
  3. Navigate to the directory where the script is located
  4. Run the script with the following command: powershell -ExecutionPolicy Bypass -File FWindowsUpdateReboot.ps1
  5. Give Windows Update the finger, you have finally defeated it.

How to uninstall

  1. Open a PowerShell window with administrator privileges
  2. Run the following command: FWindowsUpdateReboot -Uninstall

How does it get around Windows Update restarting your PC?

Windows Update forces you to reboot your PC to install updates, however it won't do so if the current time is within your Active Hours. You are limited to 18 hours for Active Hours, and if you are outside of that, you will be rebooted. The script works by to permanently prevent Windows Update from restarting your PC by continuously rotating your Windows Active Hours every hour so you're never outside of Active Hours.

What is the script doing?

  1. If not run with administrator privileges, the script will request elevation to run as administrator.
  2. The script will then:
    • Copy itself to the Windows System32 directory
    • Create a scheduled task called "FWindowsUpdateReboot" that runs every hour
  3. The scheduled task runs the script with the -Rotate parameter, which:
    • Sets Active Hours to start at the current hour
    • Sets Active Hours to end 18 hours later (the maximum allowed duration)
    • Updates these settings in the Windows registry

By dynamically adjusting Active Hours every hour, you are never outside of Active Hours, and Windows Update will never find a suitable time outside of Active Hours to restart your computer.

The script runs silently in the background using minimal resources.

For example, if you're using your PC at 2 PM:

  • Active Hours will be set to 2 PM - 8 AM
  • An hour later at 3 PM, they'll adjust to 3 PM - 9 AM
  • This continues as long as your PC is running

The script requires a one-time setup with administrator privileges, but then runs automatically as a system service requiring no further interaction.

⚠️ Security Reminder

Before running any PowerShell script downloaded from the internet (including this one), you should always review its contents to ensure it's safe. While this script is open source and safe to use, it's good security practice to verify scripts before executing them with administrator privileges.

The full source code is available in this repository for transparency and security verification.

Review the script source code to ensure it's safe:

# rotate-active-hours.ps1
# PowerShell script to rotate Active Hours and set up scheduled task
param (
[switch]$Rotate,
[switch]$Uninstall
)
# Check if running as administrator
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
# Relaunch the script with administrator privileges
$arguments = "& `"${PSCommandPath}`""
if ($Rotate) {
$arguments += " -Rotate"
}
if ($Uninstall) {
$arguments += " -Uninstall"
}
Start-Process -FilePath "PowerShell" -Verb RunAs -ArgumentList $arguments
exit
}
# Define variables
$taskName = "FWindowsUpdateReboot"
$system32Path = "$env:windir\System32"
$scriptName = "FWindowsUpdateReboot.ps1"
$destinationPath = Join-Path -Path $system32Path -ChildPath $scriptName
$sourceScriptPath = $MyInvocation.MyCommand.Path
if ($Uninstall) {
# Remove the scheduled task if it exists
try {
Get-ScheduledTask -TaskName $taskName -ErrorAction Stop
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
Write-Host "Scheduled task '$taskName' has been removed."
} catch {
Write-Host "Error removing scheduled task: $_"
Write-Host "Scheduled task '$taskName' does not exist."
}
# Prompt user about script removal
$removeScript = Read-Host "Would you like to remove the script from System32? (Y/N)"
if ($removeScript -eq 'Y' -or $removeScript -eq 'y') {
if (Test-Path $destinationPath) {
Remove-Item -Path $destinationPath -Force
Write-Host "Script removed from System32."
} else {
Write-Host "Script not found in System32."
}
}
Write-Host "Successfully uninstalled $taskName. Press Enter to exit..."
$null = Read-Host
exit
}
if ($Rotate) {
# Rotate Active Hours
$activeHoursDuration = 18 # Maximum allowed active hours duration in hours
$currentHour = (Get-Date).Hour
$newActiveHoursStart = $currentHour
$newActiveHoursEnd = ($currentHour + $activeHoursDuration) % 24
# Update the registry keys
$registryPath = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
Set-ItemProperty -Path $registryPath -Name "ActiveHoursStart" -Value $newActiveHoursStart -Type DWord
Set-ItemProperty -Path $registryPath -Name "ActiveHoursEnd" -Value $newActiveHoursEnd -Type DWord
Write-Host "Active hours updated: Start=$newActiveHoursStart, End=$newActiveHoursEnd"
} else {
# Copy the script to System32 if it's not already there
if ($sourceScriptPath -ieq $destinationPath) {
Write-Host "Script is already in System32."
} else {
Write-Host "Copying script to System32..."
try {
Copy-Item -Path $sourceScriptPath -Destination $destinationPath -Force
Write-Host "Script copied to $destinationPath"
} catch {
Write-Error "Failed to copy script to System32."
exit 1
}
}
# Remove existing scheduled task if it exists and set it up again
try {
# Check if the task exists
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction Stop
# If it exists, remove it
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
Write-Host "Scheduled task '$taskName' existed and has been removed."
} catch {
Write-Host "Scheduled task '$taskName' does not exist. Proceeding to create it."
}
Write-Host "Creating scheduled task '$taskName'..."
# Define the action to run the script from System32 with the -Rotate parameter
$scriptPath = Join-Path $system32Path $scriptName
# Build the action command without inner quotes
$action = "powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File $scriptPath -Rotate"
# Enclose the entire action in double quotes for the /TR parameter
$actionArgument = "`"$action`""
# Use SchTasks.exe to create a task that runs every hour indefinitely
$schtasksArguments = @(
'/Create'
'/RU', 'SYSTEM'
'/SC', 'HOURLY'
'/TN', $taskName
'/TR', $actionArgument
'/F'
)
# Execute the command to create the scheduled task
$result = Start-Process -FilePath "schtasks.exe" -ArgumentList $schtasksArguments -Wait -PassThru -NoNewWindow
if ($result.ExitCode -ne 0) {
Write-Error "Failed to create scheduled task. Exit code: $($result.ExitCode)"
Write-Host "Failed to create scheduled task. See the above error message for details."
}
else {
Write-Host "Scheduled task '$taskName' has been created successfully."
Write-Host "$taskName has been installed successfully."
Write-Host "Give Windows Update the finger, you have finally defeated it."
Write-Host "`n"
Write-Host " / \"
Write-Host " |\_/|"
Write-Host " |---|"
Write-Host " | |"
Write-Host " | |"
Write-Host " _ |=-=| _"
Write-Host " _ / \| |/ \"
Write-Host " / \| | | ||\"
Write-Host "| | | | | \>"
Write-Host "| | | | | \"
Write-Host "| - - - - |) )"
Write-Host "| /"
Write-Host " \ /"
Write-Host " \ /"
Write-Host " \ /"
Write-Host " \ /"
Write-Host "F Windows Update Reboot!"
Write-Host "`n"
}
Write-Host "Press Enter to exit..."
$null = Read-Host
exit
}

Development

Testing

The project includes unit tests written using Pester, the standard testing framework for PowerShell. Tests can be run locally or through GitHub Actions CI pipeline.

Running Tests Locally

Option 1: Using the Test Runner Script (Recommended)
  1. Clone the repository:
git clone https://github.com/cboileau/FWindowsUpdateReboot.git
cd FWindowsUpdateReboot

You can also run specific test categories from PowerShell:

# Run all tests
.\Run-Tests.ps1 -TestType All

# Run only installation tests
.\Run-Tests.ps1 -TestType Installation

# Run only active hours tests
.\Run-Tests.ps1 -TestType ActiveHours

# Run only uninstallation tests
.\Run-Tests.ps1 -TestType Uninstallation

CI/CD

The project uses GitHub Actions to run tests automatically on:

  • Every push to the main branch
  • Every pull request to the main branch

Test results can be viewed in the Actions tab of the repository.

Running Individual Test Cases

To run specific test cases, you can use Pester's filtering:

# Run only installation tests
$config = New-PesterConfiguration
$config.Filter.Tag = "Installation"
$config.Run.Path = "Tests"
Invoke-Pester -Configuration $config

# Run only active hours tests
$config = New-PesterConfiguration
$config.Filter.Tag = "ActiveHours"
$config.Run.Path = "Tests"
Invoke-Pester -Configuration $config

Troubleshooting Tests

If tests fail, check:

  1. Pester is installed correctly
  2. You're in the correct directory
  3. Your PowerShell execution policy allows running scripts

About

A Simple PowerShell Script that once ran will prevent windows update from every rebooting your PC again automatically.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published