Prevent Windows 10 from automatically restarting after an update programmatically
Asked Answered
H

3

13

QUESTION: Is there a programmatic way to prevent Windows 10 from automatically restarting after an update?

We work on "mission-critical" software that runs in Windows. In general, it is bad if a Windows automatic update interrupts our process as it can mean lost money in scrapped material (you cannot stop and resume later, the job must work from start to finish uninterrupted).

In the past, we were able to get around this by having our software installer set a parameter in the Windows Registry (with the user-installer's consent) that would prevent rebooting automatically after an automatic update when a user is logged in. So, instead of an automatic update, the user would be notified that there is an update requiring a restart and to click a button when they were ready for it. This worked for Windows Vista, 7, and 8/8.1. However, for the latest Windows 10 (I'm working with the Creators' update), the parameter seems to have no effect anymore as I have observed my computer go through an automatic update where I knew that the registry entry was already in effect.

In my research, I found what appears to be one place of hope where a setting can be selected where Windows will offer the user the opportunity to schedule the update instead of just doing it automatically at a time Windows thinks it is appropriate (information here). However, I'm not sure how to go about setting Windows programmatically so that the option to schedule an update becomes the default.

Is there a programmatic way to set Windows 10 (in a friendly manner, preferably) so that it won't auto-restart?

Hilar answered 13/7, 2017 at 14:24 Comment(8)
That's done using group policies and domain policies. It doesn't need code. Controlling updates is easy in a domain - set up and configure Update Services to cache and distribute updates as appropriateOverabundance
To put it another way - I have to manually force updates in my domainOverabundance
This isn't a policy that you should be trying to set. This is something for the sysadmin of the machine on which your program runs.Dar
To put it yet another way: you are asking for a seatbelt defeater. Not a good idea. Why does this "mission-critical" machine have direct access to the public internet anyway? How is it going to get the security updates it obviously needs, since it accesses the public Internet? That's the owner's and responsibilityOverabundance
@PanagiotisKanavos, I'm not looking to completely defeat it. I'm looking to set it so that it will prompt the user to schedule a time to automatically update as opposed Windows just doing so at a time whenever it feels like. We also ask the admin installer/user permission to change this setting when they install our software (or else we leave it alone if they click "No"). As for your question on "mission critical" and Internet connections... some owners want both so that they can monitor their machines remotely.Hilar
@Hilar For the last point, it's perfectly possible to do this with VPN - the mission critical system can still have no outside network access (just internal network, domain controller, WSUS server, etc) and remote access is enableld through first making a VPN connection to the site.Unmistakable
We use the "NoAutoRebootWithLoggedOnUsers" setting and so far as I can tell Windows 10 has continued to respect this - as long as nobody opens the Windows Update control panel, at least. (However, we don't have very many machines running 1703. I'll do some testing and see if that changed anything.)Seven
... NoAutoRebootWithLoggedOnUsers still seems to be working on 1703. However, it is possible that this depends on other configuration settings, e.g., WSUS.Seven
V
8

Try the shutdown block reason APIs. ShutdownBlockReasonCreate

The API documentation cites CD burning as an example, but the same would apply to your "mission-critical" process.

Applications should call this function as they begin an operation that cannot be interrupted, such as burning a CD or DVD. When the operation has completed, call the ShutdownBlockReasonDestroy function to indicate that the system can be shut down.

Note the documentation specifically references user shutdown, but I don't see why it shouldn't also apply to update restarts as well.

NB: Remember to check that the function is successful; and to destroy the Shutdown Reason when the process completes.


Based on your comment it seems you need help using the Windows API routines. I suggest you declare the external functions in an appropriate library. (But you can test in the same unit without concern.)

function ShutdownBlockReasonCreate(hWnd: HWND; Reason: LPCWSTR): BOOL; stdcall; external user32;
function ShutdownBlockReasonDestroy(hWnd: HWND): BOOL; stdcall; external user32;

The following demonstrates how to use the API. NB: Pay attention to error checking. I've demonstrated how you can get error information. What you do with it is up to you.

The other important thing to point out (repeated in comments) is that you should not block the main thread. For more information, refer to the Microsoft documentation from when these changes were first introduced in Vista here.

procedure TForm1.JobStartClick(Sender: TObject);
var
  LErr: Cardinal;
begin
  ListBox1.Items.Add('Attempting to block shutdown:');
  if (not ShutdownBlockReasonCreate(Application.MainForm.Handle, 
      'Super Critical Job')) then
  begin
    LErr := GetLastError;
    ListBox1.Items.Add('... failed: ' + SysErrorMessage(LErr));
    //Probably not safe to start your job in this case, but perhaps you
    //choose to give it a shot anyway.
    Exit;
  end;
  ListBox1.Items.Add('... success');

  FJobRunning := True;
  //Start the job.
  //However, NB do not run the job here.
  //If it takes a long time and is not asynchronous, you should probably
  //run your job on a separate thread.   ***Do not block the main thread
  //  otherwise Windows will still kill your app for not responding***
end;

procedure TForm1.JobEndClick(Sender: TObject);
var
  LErr: Cardinal;
begin
  if (not FJobRunning) then Exit;
  //End the job.
  //Again, do not block the main thread, so perhaps this is rather something
  //to do after you already know the job is done.
  FJobRunning := False;

  ListBox1.Items.Add('Allow shutdown');
  if (not ShutdownBlockReasonDestroy(Application.MainForm.Handle)) then
  begin
    LErr := GetLastError;
    ListBox1.Items.Add('... failed: ' + SysErrorMessage(LErr));
  end;
end;

//Declare the handler for the WM_QUERYENDSESSION message as follows.
//procedure WMQueryEndSession(var AMsg : TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure TForm1.WMQueryEndSession(var AMsg: TWMQueryEndSession);
begin
  ListBox1.Items.Add('WMQueryEndSession');
  if (FJobRunning) then
    //NB: This is very important.
    //You still need to confirm that your application wants to block
    //shutdown whenever you receive this message.
    AMsg.Result := 0
  else
    inherited;
end;
Vitelline answered 13/7, 2017 at 23:41 Comment(4)
... I dunno, Windows can be pretty ... obsessive ... about those automatic reboots. But this is definitely worth a try.Seven
@Craig Young, I'm working in Delphi with this project and didn't have access to "ShutdownBlockReasonCreate". However, I did find something else "WMQueryEndSession" here. I tried it and it holds up a normal shutdown or restart Do you think that would stop a restart from automatic updates as well (don't have a convenient update to test against :) )?Hilar
@Hilar First of all, why do you tag C# if you're using Delphi? Secondly, my advice is applicable to Delphi. Presumably you don't know how to call Windows API functions if they haven't already been declared for you? I've updated my answer with information that should get you going. But I strongly recommend you familiarise yourself with how to work more effectively with the Windows API in Delphi. (And other external DLLs for that matter.)Vitelline
At long last! I can finally mark this as the answer! It works fine in Windows 10 Build 1909. The worst that happens is that the user's account gets locked and you just have to log in again to get back to the application. A banner appears stating that the app interrupted the Windows Update restart, but you can reschedule.Hilar
W
4

The registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings contains two entries: ActiveHoursStart and ActiveHoursEnd. Change these entries as needed inside your program to prohibit a reboot. This way you can control the reboot not to take place while your program runs. Note that you need elevated privilege to change these settings.

Windgall answered 13/7, 2017 at 15:6 Comment(4)
It's surely wrong for an app to modify these settings.Dar
@DavidHeffernan, Well, I have a service running that does exactly that and only that. It is instead surely wrong that MS forces my system to crash any running program (especially running VMs) while I am not sitting in front of it. And: no, it doesn't emit a shutdown message before, that I could intercept and react on. Actually I am doing the reboots, but at a time when I can control it.Windgall
On your machine fine. Not on somebody else's machine.Dar
@DavidHeffernan, The OP mentioned that he gets the users consent. Prohibiting the updates, at least while the task is running, is the actual goal acknowledged by the user. The previous way doesn't work any more. My answer shows a working alternative. The question was not about automatic updates being good or bad - in which case it probably would have been deleted already.Windgall
E
0

The solution I use for Windows 11 is along the lines proposed by @UweRaabe. I use Task Scheduler to run this command line batch program every hour:

for /f %%i in ('powershell "((get-date).Hour+18) %% 24"') do set startHour=%%i
for /f %%i in ('powershell "((get-date).Hour+12) %% 24"') do set endHour=%%i

reg add HKLM\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings /v ActiveHoursStart /t REG_DWORD /d %startHour% /f 
reg add HKLM\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings /v ActiveHoursEnd /t REG_DWORD /d %endHour% /f 
Eugenie answered 28/5, 2024 at 6:36 Comment(4)
How long has this script managed to prevent an active waiting reboot for you?Vidavidal
I am now up to 9 days without a restart for an update I installed on 30th MayEugenie
Optimised code by using powershell commands to get the time modulo 24. This is now locale indpendent . It is still a command line batch file. Now only 4 lines.Eugenie
Now up to 21 days and countingEugenie

© 2022 - 2025 — McMap. All rights reserved.