Blog Post

Controlling Windows 10 Updates

How to enable installation of updates or to prevent it during a reboot or shutdown.

Controlling Windows 10 Updates - How to enable installation of updates or to prevent it during a reboot or shutdown.
Image courtesy of Olga Barinova
This article contains functions and features that are not documented by the original manufacturer. By following advice in this article, you're doing so at your own risk. The methods presented in this article may rely on internal implementation and may not work in the future.

Intro

In this blog post I want to share the results of our research into the undocumented world of updates in Windows 10, and namely, how do you control whether or not those updates are installed during a reboot (or shutdown), and how to find out if a restart is necessary to finish installation of updates.

This blog post is intended for the Windows developers. In case you are just an end-user that wants to take advantage of this research, please download our software that does that. It is called ShutdownWithUpdates.

Table Of Contents

Here's the table of contents for a quick access:

Reboot To Install Updates

This may be necessary since Microsoft decided to have users click this button to finish installation of updates:

'Restart Now' button
"Restart Now" button needed to finish installation of updates.

But what if you have 100, or 1000 computers that you need to click that button for? How are you supposed to do that?

In that case, you can automate it in your script, or in your software, to simply set the following System Registry key, before initiating a restart:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\InstallAtShutdown]
(Default) = REG_DWORD: 1
Note that this key is a redirected one in a 32-bit process that is running under a 64-bit OS.

You can also do it using the code like this:

C++[Copy]
//Enable installation of updates during the next reboot
DWORD dwV = 1;
if(!WriteValueToSystemRegistry(HKEY_LOCAL_MACHINE, TRUE,
	L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Orchestrator\\InstallAtShutdown",
	NULL, REG_DWORD, &dwV, sizeof(dwV)))
{
	//Failed - log OS error code from GetLastError()
	assert(false);
}

Note that we're using our WriteValueToSystemRegistry helper function to be able to access a 64-bit registry from a 32-bit process:

C++[Copy]
BOOL WriteValueToSystemRegistry(HKEY hIniKey, BOOL bWOW64, LPCTSTR lpSubKey, LPCTSTR lpKeyValue, DWORD dwValueType, const void* pData, int ncbDataSz)
{
	HKEY hKey;
	DWORD dwR;
	REGSAM dwSam;
	BOOL bRes = FALSE;

#ifdef _M_X64
	//64-bit build
	dwSam = KEY_SET_VALUE;
#else
	//32-bit build
	dwSam = KEY_SET_VALUE | (bWOW64 ? KEY_WOW64_64KEY : 0);
#endif

	dwR = RegCreateKeyEx(hIniKey, lpSubKey, NULL, NULL, 0, dwSam, NULL, &hKey, NULL);
	if(dwR == ERROR_SUCCESS)
	{
		if((dwR = RegSetValueEx(hKey, lpKeyValue, NULL, dwValueType, (const BYTE *)pData, ncbDataSz)) == ERROR_SUCCESS)
		{
			bRes = TRUE;
		}

		RegCloseKey(hKey);
	}

	SetLastError(dwR);
	return bRes;
}

Note that Microsoft actually set up a DACL on the InstallAtShutdown registry key to enable all authenticated users to set its value. This means that your code doesn't have to run with administrative privileges to do what I showed above.

Note that the InstallAtShutdown registry setting has no effect by itself if Windows updates are not downloaded, or otherwise are ready for an installation during a reboot.

Reboot Without Installing Updates

Note that I'm talking about preventing installation of updates during a reboot or shutdown only. This may be necessary if you don't want to lock up your PC for half an hour (to install an update) and just need to reboot it quickly. Also having such option in your software may be a good thing to give your users control over their computers.

Here's how you can do it: you basically need to set the following System Registry values before you initiate a reboot:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\InstallAtShutdown]
(Default) = REG_DWORD: 0

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\CommitStatus]
"NoCommit" = REG_DWORD: 1
Note that these keys are redirected in a 32-bit process that is running under a 64-bit OS.
Note that the CommitStatus registry key may not be reset in some circumstances during a reboot. Thus it is advisable to remove it as soon as your service starts running again. Failure to do so may prevent further installation of Windows updates!

You can achieve it using this code:

C++[Copy]
//To prevent installation of updates during the next reboot
DWORD dwV = 1;
if(WriteValueToSystemRegistry(HKEY_LOCAL_MACHINE, TRUE, 
	L"SOFTWARE\\Microsoft\\WindowsUpdate\\CommitStatus", L"NoCommit", REG_DWORD, &dwV, sizeof(dwV)))
{
	dwV = 0;
	if(!WriteValueToSystemRegistry(HKEY_LOCAL_MACHINE, TRUE, 
		L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Orchestrator\\InstallAtShutdown", NULL, 
		REG_DWORD, &dwV, sizeof(dwV)))
	{
		//Failed - log OS error code from GetLastError()
		assert(false);
	}
}
else
{
	//Failed - log OS error code from GetLastError()
	assert(false);
}

We used our WriteValueToSystemRegistry helper function again.

Note that the code above must be running as administrator to be able to write into the CommitStatus key. Interestingly enough, the InstallAtShutdown key seems to be open for writing by users without administrative privileges.

Reboot Or Shutdown

Then the reboot (or shutdown) is performed using the exact same function as you would do it otherwise:

C++[Copy]
int nOSError = InitiateShutdown(NULL, NULL, 0, dwPowerOpFlags, 
	SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED);
if(nOSError != ERROR_SUCCESS)
{
	//Failed - log OS error code in nOSError
	assert(false);
}

Where dwPowerOpFlags can be set to SHUTDOWN_RESTART for a reboot, or to SHUTDOWN_POWEROFF for a shutdown. Microsoft also likes to OR it with the SHUTDOWN_RESTARTAPPS flag to enable supporting apps to restore their data after a restart.

Additionally, the InitiateShutdown API requires the SE_SHUTDOWN_PRIVILEGE privilege to be enabled. You can do it with a helper function like this before you invoke InitiateShutdown:

C++[Copy]
AdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, NULL);
Note that the InstallAtShutdown registry key mentioned above will be reset during a reboot.

Check If Reboot Is Required To Install Updates

And finally, how can you tell if a reboot is required to finish installation of updates?

You can use the presence of the following registry key to check that:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\RebootRequired]
Note that this key is a redirected one in a 32-bit process that is running under a 64-bit OS.

You can read that key using the code like this:

C++[Copy]
HKEY hKey;
DWORD dwR = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
	L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Orchestrator\\RebootRequired", 0, 
#ifdef _M_X64
	//64-bit build
	KEY_READ,
#else
	//32-bit build
	KEY_READ | KEY_WOW64_64KEY,
#endif
	&hKey);

if (dwR == ERROR_SUCCESS)
{
	//Reboot is required to install updates

	RegCloseKey(hKey);
}
else if(dwR == ERROR_FILE_NOT_FOUND)
{
	//Reboot is not required to install updates

}
else
{
	//Failed - log OS error code in dwR
	assert(false);
}

Note that the code above does not have to run elevated to read that key.

Conclusion

In conclusion, let me say that this is a highly undocumented stuff. If you rely on it in your software, be prepared to have it changed by Microsoft in one of their future updates. I went through this several times already in the ShutdownWithUpdates tool.

Related Articles