Understanding DISM – /CheckHealth, /ScanHealth and /RestoreHealth
There appears to be much confusion about what the switches available for DISM actually do. I’ve seen countless occasions where people have recommended forum users who are suffering from Windows Update issues (and even BSODs) to run DISM /ScanHealth followed by /RestoreHealth. Please stop! It’s pointless.
DISM is designed for servicing the Windows operating system and provides an option to ensure that the Component Store is not corrupt. There is two main options for doing this: /ScanHealth and /RestoreHealth. They actually almost do the same thing, however, the latter option will actually attempt to perform repairs using the Windows Update servers as the primary source. Although, typically, this is only for corrupted packages and payload files – I’m yet to see a case whereby DISM was able to repair registry corruption, although, it usually does an excellent job of finding it.
The /CheckHealth is the fastest option and simply checks for the presence of two different store flags which are part of the CBS subkey. These are the Corruption value and Unserviceable value. These two flags are queried by a CBS worker process called TiWorker.exe.
/ScanHealth and /RestoreHealth do largely the same as each other and perform an extensive check of the Component Store. If there is no corruption then the two previously mentioned flags are cleared, otherwise they’re set to 0x1 or true. DISM does a good job of checking for registry corruption within the COMPONENTS and CBS subkey, however, tends to struggle when it comes to checking actual files. With this in mind, it is often best to run SFC as well which will only check for file corruption within the WinSxS folder. SFC does attempt to perform repairs if possible by checking the Backup directory of the WinSxS folder for a suitable replacement file, if none can be found, then the file is reported as corrupted or missing from the backup folder.
DISM and the Servicing Stack:
Now, there is an important registry key which is queried just before DISM is executed and that is the Image File Execution Options (IFEO) subkey. There is a particular value named Debugger and if this is set to 0x1, the DISM will not start at all and will throw DISM Error 2.
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\DismHost.exe" /v Debugger
Additionally, prior to the TrustedInstaller (Windows Module Installer) service starting, the same subkey is queried but for the TrustedInstaller.exe instead.
Eventually, DismHost.exe looks up a few different subkeys under HKEY_CLASSES_ROOT, there is quite a few important subkeys here and if they’re missing or corrupted, then DISM will fail to run correctly.
HKEY_CLASSES_ROOT\Interface\{00020400-0000-0000-C000-000000000046}
(Default) REG_SZ IDispatch
HKEY_CLASSES_ROOT\Interface\{00020400-0000-0000-C000-000000000046}\ProxyStubClsid32
(Default) REG_SZ {00020420-0000-0000-C000-000000000046}
The default value is checked here and then used in conjunction with another subkey of the same name.
HKEY_CLASSES_ROOT\CLSID\{00020420-0000-0000-C000-000000000046}
(Default) REG_SZ PSDispatch
HKEY_CLASSES_ROOT\CLSID\{00020420-0000-0000-C000-000000000046}\InprocServer32
(Default) REG_SZ C:\Windows\System32\oleaut32.dll
ThreadingModel REG_SZ Both
The above two subkeys aren’t too interesting and quite standard. However, eventually DismHost.exe will begin to start interacting with the servicing stack – this is commonly where issues begin to arise. The servicing directory is queried to check which version of the servicing stack is installed and active. The folder in question in the following:
%systemroot%\servicing\version\{SSU version}\*_installed
The folder will always contain two files: amd64_installed and x86_installed. These can be found in the corresponding SSU component folders within the WinSxS folder. DISM uses these files to look up the appropriate servicing stack component to run.
On my server instance, it was looking up and creating a file handle to the wcp.dll file which is part of the following component:
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\wcp.dll
The file attributes were examined and the file handle closed shortly afterwards; note, if this folder is corrupt or missing in any way, then DISM will crash and refuse to run. The DISM log will contain the following error message:
2022-07-21 15:07:10, Warning DISM DISM OS Provider: PID=6236 TID=6932 Failed to bind the online servicing stack – CDISMOSServiceManager::get_ServicingStackDirectory(hr:0x80070003)
2022-07-21 15:07:10, Error DISM DISM OS Provider: PID=6236 TID=6932 Unable to retrieve servicing stack folder for DLL search path modification. – CDISMOSServiceManager::SetDllSearchPath(hr:0x80070003)
2022-07-21 15:07:10, Error DISM DISM OS Provider: PID=6236 TID=6932 Unable to set the DLL search path to the servicing stack folder. C:\Windows may not point to a valid Windows folder. – CDISMOSServiceManager::SetWindowsDirectory(hr:0x80070003)
2022-07-21 15:07:10, Error DISM DISM.EXE: Failed to set the windows directory to ‘C:\Windows’. HRESULT=80070003
The active search path will be the same value as the one under Version subkey of the CBS key. This will be mentioned further later.
DISM then eventually returns to the WinSxS folder mentioned previously and then opens the CbsCore.dll.
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\CbsCore.dll
The following value is then queried:
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CMF\Config" /v SYSTEM
HKEY_CLASSES_ROOT\CLSID\{75207391-23F2-4396-85F0-8FDB879ED0ED}
(Default) REG_SZ Component Based Servicing Session Proxy/Stub
HKEY_CLASSES_ROOT\CLSID\{75207391-23F2-4396-85F0-8FDB879ED0ED}\InProcServer32
(Default) REG_EXPAND_SZ %SystemRoot%\servicing\CbsApi.dll
ThreadingModel REG_SZ Both
The above two subkeys are then examined which seem to be used to set up a CBS session. The second subkey points to the location of the CbsApi.dll.
HKEY_CLASSES_ROOT\CLSID\{752073A1-23F2-4396-85F0-8FDB879ED0ED}
(Default) REG_SZ Component Based Servicing Session
AppID REG_SZ {752073A2-23F2-4396-85F0-8FDB879ED0ED}
The AppId value is then examined which is used to look up the value data which corresponds to the following subkey name:
HKEY_CLASSES_ROOT\AppID\{752073A2-23F2-4396-85F0-8FDB879ED0ED}
(Default) REG_SZ Trusted Installer Service
AccessPermission REG_BINARY 01000480840000009400000000000000140000000200700005000000000014000700000001010000000000050A0000000000140003000000010100000000000512000000000018000300000001020000000000052000000020020000000014000300000001010000000000050400000000001400030000000101000000000005060000000102000000000005200000002002000001020000000000052000000020020000
LaunchPermission REG_BINARY 01000480700000008C000000000000001400000002005C0004000000000014000B000000010100000000000512000000000018000B00000001020000000000052000000020020000000014000B000000010100000000000504000000000014000B000000010100000000000506000000010500000000000515000000A05F841F5E2E6B49CE120303F4010000010500000000000515000000A05F841F5E2E6B49CE120303F4010000
LocalService REG_SZ TrustedInstaller
As the LocalService value suggests, this subkey is related to the Trusted Installer Service which is the principal owner of almost all the files and registry keys required for servicing the operating system.
The services.exe then checks the services configuration for the Trusted Installer service within the following registry subkey:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TrustedInstaller
BlockTime REG_DWORD 0x2a30
BlockTimeIncrement REG_DWORD 0x384
Description REG_SZ @%SystemRoot%\servicing\TrustedInstaller.exe,-101
DisplayName REG_SZ @%SystemRoot%\servicing\TrustedInstaller.exe,-100
ErrorControl REG_DWORD 0x1
FailureActions REG_BINARY 840300000000000000000000030000001400000001000000C0D4010001000000E09304000000000000000000
Group REG_SZ ProfSvc_Group
ImagePath REG_EXPAND_SZ %SystemRoot%\servicing\TrustedInstaller.exe
ObjectName REG_SZ localSystem
PreshutdownTimeout REG_DWORD 0x36ee80
ServiceSidType REG_DWORD 0x1
Start REG_DWORD 0x3
Type REG_DWORD 0x10
The TrustedInstaller service is then launched from the same directory as the ImagePath value. The service then enumerates the values under the Version subkey:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Version
The TrustedInstaller eventually checks the CBS log configuration by examining the following four values:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\EnableLog
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Configuration\CBSLogMaxInMB
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Configuration\CBSLogHardMaxInMB
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Configuration\NumCBSPersistLogs
The following key is then created to indicate that the Trusted Installer service is actively running:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\TiRunning
To ensure there is no pending reboots required or that one is actively taking place, the service will query the following two values:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress
HKLM\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending
The TrustedInstaller then examines the default values of the following subkeys:
HKEY_CLASSES_ROOT\CLSID\{8F5DF053-3013-4DD8-B5F4-88214E81C0CF}
(Default) REG_SZ SFP Repair Class
AppID REG_SZ {752073A2-23F2-4396-85F0-8FDB879ED0ED}
HKEY_CLASSES_ROOT\CLSID\{3C6859CE-230B-48A4-BE6C-932C0C202048}
(Default) REG_SZ Sxs Store Class
AppID REG_SZ {752073A2-23F2-4396-85F0-8FDB879ED0ED}
HKEY_CLASSES_ROOT\CLSID\{F556F9B2-C810-44A2-BA7A-3AB8C24E666D}
(Default) REG_SZ GenValObject Outer Class
AppID REG_SZ {D8D4249F-A8FB-44A7-8AA0-564E8C385BD6}
The AppId value for the final subkey corresponds to the software protection platform:
HKEY_CLASSES_ROOT\AppID\{D8D4249F-A8FB-44A7-8AA0-564E8C385BD6}
(Default) REG_SZ Microsoft Software Protection Platform Admin Object (outer)
AccessPermission REG_BINARY 010014808800000098000000140000003000000002001C0001000000110014000100000001010000000000100010000002005800020000000000280003000000010600000000000550000000F05B5807C3438C9AC78A72DD8F8CB4DF4447E7F80000280003000000010600000000000550000000B589FB381984C2CB5C6C236D5700776EC00264870102000000000005200000002002000001020000000000052000000020020000
LaunchPermission REG_BINARY 010014808800000098000000140000003000000002001C000100000011001400010000000101000000000010001000000200580002000000000028000B000000010600000000000550000000F05B5807C3438C9AC78A72DD8F8CB4DF4447E7F8000028000B000000010600000000000550000000B589FB381984C2CB5C6C236D5700776EC00264870102000000000005200000002002000001020000000000052000000020020000
LocalService REG_SZ TrustedInstaller
Another CBS session interface related subkey is then examined:
HKEY_CLASSES_ROOT\Interface\{F568C899-AF4F-4EAA-B12A-B8E5F1B219DE}
(Default) REG_SZ ICbsSession8
HKEY_CLASSES_ROOT\Interface\{F568C899-AF4F-4EAA-B12A-B8E5F1B219DE}\ProxyStubClsid32
(Default) REG_SZ {75207391-23F2-4396-85F0-8FDB879ED0ED}
The InProcServer32 value is then looked up from the same subkey mentioned earlier, this is the same one as the default value for ProxyStubClsid32 subkey. The CbsApi.dll is then has a file handle opened to by the Trusted Installer service:
%systemroot%\servicing\CbsApi.dll
The image is then loaded by the Trusted Installer, DismHost.exe then queries our CBS session stub subkey from earlier a few times. After some time of DismHost.exe repeatedly examining a CLSID subkey which doesn’t exist; we eventually get to a very important subkey which will throw DISM Error 87 if it doesn’t exist or is corrupt:
HKEY_CLASSES_ROOT\CLSID\{0823B6F8-F499-4D5E-B885-EA9CB4F43B24}
(Default) REG_SZ Component Based Servicing Worker
AppID REG_SZ {8D15A4F3-1BE5-4120-8A4D-2EF92A5DD58D}
HKEY_CLASSES_ROOT\CLSID\{0823B6F8-F499-4D5E-B885-EA9CB4F43B24}\LocalServer32
(Default) REG_EXPAND_SZ %SystemRoot%\winsxs\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\TiWorker.exe
This subkey is used to store the location of the TiWorker process which is a child process of the Trusted Installer service. The TiWorker process will create a number of threads which are sometimes referred to in the CBS log as a CBS worker. If this subkey is missing or corrupted then you will experience DISM Error 87 or an error message stating that the /Cleanup-Image switch is not recognised. Additionally, if you disable the Trusted Installer service, the same error code will be produced. Thanks to Maxstar for discovering the cause of this error.
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\TiWorker.exe
The TiWorker.exe is then launched and the subsequent subkey is then examined:
HKEY_CLASSES_ROOT\AppID\{8D15A4F3-1BE5-4120-8A4D-2EF92A5DD58D}
(Default) REG_SZ TiWorker
AccessPermission REG_BINARY 01000480740000008400000000000000140000000200600004000000000014000700000001010000000000050A00000000001400030000000101000000000005120000000000180007000000010200000000000520000000200200000000180003000000010200000000000520000000210200000102000000000005200000002002000001020000000000052000000020020000
LaunchPermission REG_BINARY 01000480700000008C000000000000001400000002005C0004000000000014000B000000010100000000000512000000000018000B00000001020000000000052000000020020000000014000B000000010100000000000504000000000014000B000000010100000000000506000000010500000000000515000000A05F841F5E2E6B49CE120303F4010000010500000000000515000000A05F841F5E2E6B49CE120303F4010000
The AppId corresponds to the same AppId value as the Component Based Servicing Worker CLSID subeky. The TiWorker thread then opens a file handle to the following file and reads it.
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\wdscore.dll
The TiWorker.exe eventually loads the CbsApi.dll from the servicing folder and the Trusted Installer service once again examines two other subkeys:
HKEY_CLASSES_ROOT\Interface\{A70DBECC-3734-4B22-B2D1-648C0E43E177}
(Default) REG_SZ ICbsWorker
HKEY_CLASSES_ROOT\Interface\{A70DBECC-3734-4B22-B2D1-648C0E43E177}\ProxyStubClsid32
(Default) REG_SZ {75207391-23F2-4396-85F0-8FDB879ED0ED}
HKEY_CLASSES_ROOT\Interface\{365DE52E-EE7E-4975-AEC8-06588234BB3C}
(Default) REG_SZ ITrustedInstallerService
HKEY_CLASSES_ROOT\Interface\{365DE52E-EE7E-4975-AEC8-06588234BB3C}\ProxyStubClsid32
(Default) REG_SZ {75207391-23F2-4396-85F0-8FDB879ED0ED}
This leads to the TiWorker thread loads a few other images from the servicing component within the WinSxS folder.
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\CbsCore.dll
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\USERENV.dll
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\profapi.dll
The TiWorker ensures that the following subkeys don’t exist:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Configuration\DisablePSRL
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\DisableKernelTransactions
A few other images are then loaded:
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\dpx.dll
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\wcp.dll
%systemroot%\WinSxS\amd64_microsoft-windows-servicingstack_31bf3856ad364e35_6.3.9600.17031_none_fa50b3979b1bcb4a\DrUpdate.dll
The service host (svchost.exe) then queries the following subkey:
HKEY_CLASSES_ROOT\CLSID\{D5978620-5B9F-11D1-8DD2-00AA004ABD5E}
(Default) REG_SZ SENS Network Events
HKEY_CLASSES_ROOT\CLSID\{D5978620-5B9F-11D1-8DD2-00AA004ABD5E}\InprocServer32
(Default) REG_EXPAND_SZ %systemroot%\system32\ES.DLL
ThreadingModel REG_SZ Both
This causes the TiWorker to look for the following file which never appears to exist, seems to be related to the Software Quality Management component:
%systemroot%\servicing\SQM\*_all.sqm
The TiWorker then sets the session times for the latest CBS session and then begins to either check for the corruption flags (/CheckHealth) or check the Component Store for corruption (/ScanHealth).
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\SessionIdHigh
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\SessionIdLow
References:
Process Monitor Trace from Windows Server 2012 R2
Pingback: Windows Servicing Stack Exploration Notes – yihanwu1024