A patch may take as long or longer to install than the target product

A patch may take as long or longer to install than the target product

  • Comments 12

Often I’m asked why installing a Windows Installer patch (MSP) takes as long or longer to install than the target product (MSI). While this isn’t always the case for every patch, it’s certainly possible for a number of reasons. It may also come as a surprise that the size of the patch can have little to do with the time to install the patch.

Several copies of the patch may be created

When you install a Windows Installer package, many copies of either the MSI or MSP package are created. But even before you start an installation, a bootstrap application will often download or copy the package locally so already time has been spent copying the package.

The first time a patch is installed – as identified by its unique patch code – Windows Installer will make multiple copies. When the client application (msiexec.exe or a setup bootstrap application) installs the package, eventually the package and other information is passed to the Windows Installer that does the actual installation (copying files, writing registry values, etc.). The Windows Installer service will validate the file and make a copy into a protected location as seen below.

MSI (s) (48:88) [15:52:28:971]: Original patch ==> \\server\share\patch.msp
MSI (s) (48:88) [15:52:28:973]: Patch we're running from ==> C:\Windows\Installer\16005163.msp

If the patch is installed successfully, the patch is cached and the temporary copy is deleted.

MSI (s) (48:88) [15:56:47:457]: Executing op: PatchCache(PatchId={29A69684-DEB7-31EE-9559-B29ECDFF0563},PatchPath=C:\Windows\Installer\16005163.msp)
MSI (s) (48:88) [15:56:56:194]: Executing op: CleanupTempFiles(TempFiles=C:\Windows\Installer\16005163.msp)
MSI (s) (48:88) [15:56:56:196]: Scheduling file 'C:\Windows\Installer\16005163.msp' for deletion during post-install cleanup (not post-reboot).
MSI (s) (48:88) [16:00:16:380]: Attempting to delete file C:\Windows\Installer\16005163.msp

If the patch is applied to another product or reapplied, the cached patch is copied again to avoid any sharing violates or changes to the patch while it is being installed.

MSI (s) (48:B0) [16:02:42:683]: Original patch ==> \\server\share\patch.msp
MSI (s) (48:B0) [16:02:42:683]: Patch we're running from ==> C:\Windows\Installer\16005237.msp
MSI (s) (48:B0) [16:02:42:688]: Opening existing patch 'C:\Windows\Installer\16005235.msp'.

Since the patch was already cached, it is not cached again but the temporary copy is deleted.

MSI (s) (48:B0) [16:04:05:827]: Executing op: PatchCache(PatchId={29A69684-DEB7-31EE-9559-B29ECDFF0563},PatchPath=C:\Windows\Installer\16005235.msp)
MSI (s) (48:B0) [16:04:05:827]: Patch {29A69684-DEB7-31EE-9559-B29ECDFF0563} is already present in this context, so it will not be cached again.
MSI (s) (48:B0) [16:04:05:977]: Executing op: CleanupTempFiles(TempFiles=C:\Windows\Installer\16005237.msp)
MSI (s) (48:B0) [16:04:05:977]: Scheduling file 'C:\Windows\Installer\16005237.msp' for deletion during post-install cleanup (not post-reboot).

Like any other file, the larger the patch package file the longer it will take to copy. Copying larger patch packages can account for significant time during installation.

The patch may apply to multiple products

To maintain the integrity of the machine in case any products are repaired or uninstalled, a patch will apply to all products that it targets and that are currently installed.

For example, if you have Visual Studio 2010 Ultimate and Visual Studio 2010 Express for Windows Phone installed and then install SP1, some patches in SP1 are applied multiple times. Patching Express will take less time than Ultimate, but still accounts for additional time.

Packages may be verified several times

The first time any Windows Installer package is installed, it is validated using WinVerifyTrust() against its Authenticode signature (if any) and through a SAFER policy check. This makes sure the package has not been tampered with and is allowed to install on the machine for the current user. If an Authenticode signature is present, the entire package must be read in order to generate a file hash and compare that against the signed hash. If the package was not installed from a local directory, WinVerifyTrust() streams the file from across the network as shown below.

MSI (s) (48:88) [15:52:28:971]: Original patch ==> \\server\share\patch.msp
MSI (s) (48:88) [15:52:28:973]: Patch we're running from ==> C:\Windows\Installer\16005163.msp
MSI (s) (48:88) [15:52:28:976]: SOFTWARE RESTRICTION POLICY: Verifying patch --> '\\server\share\patch.msp' against software restriction policy
MSI (s) (48:88) [15:52:28:976]: SOFTWARE RESTRICTION POLICY: \\server\share\patch.msp has a digital signature
MSI (s) (48:88) [15:54:31:055]: SOFTWARE RESTRICTION POLICY: \\server\share\patch.msp is permitted to run at the 'unrestricted' authorization level.

Any time a package is opened from outside the cache, this validation occurs. For example, if you were prompted for source and provided the path to an MSI file, Windows Installer will perform these same checks to validate the file.


Deployment developers can mitigate this problem by shipping fewer patches that target more products. This will prevent having to validate packages multiple times. Copying the package locally may also improve performance since validating the package across the network may be prone to network latency and disconnections.

A single change will reinstall the entire parent feature

By default Windows Installer will detect which components have updated – those components which have newer files or updated registry values, for example. But because state of the package depends on features defined within the package, any features that contain those components are reinstalled in whole. This means that if a feature has many components and only just one of those is updated, all the components in that feature are reinstalled. That doesn’t necessarily mean the files are copied again – that depends on what REINSTALLMODE is set to (default is “omus” if not set) – but can incur a noticeable performance penalty to compare the current machine state with the expected machine state. Any non-versioned resources like text files and registry values may also be rewritten.


Deployment developers can mitigate this problem by fragmenting components into smaller features in the target product – patches cannot refactor components out of existing features. To maintain parity with the visible feature tree, refactor components into hidden child features that follow their parents’ install actions.

Several copies of updated files may be created

Windows Installer is a transactional installation engine. Any time a file is to be replaced, a copy of the installed file is created in case the installation fails and must rollback. With patch packages, a second copy may be created to support binary patch installation and patch uninstall for any patch that supports it. If a component is not authored with attribute msidbComponentAttributesShared (0x800), files are only copied to the baseline cache when they are first replace. So at least for any shared files, only a single persistent copy of the file replaced is retained. If a file is authored with that attribute, a copy is made across all products that installed the component (clients). This feature was introduced in Windows Installer 4.5 to prevent files from being downgraded during patch uninstall.

MSI (s) (48:88) [15:55:08:389]: Caching file.dll from C:\Program Files (x86)\Product\file.dll for baseline 0
MSI (s) (48:88) [15:55:35:803]: Executing op: SetBaseline(Baseline=0,ProductVersion=1.0.0)
MSI (s) (48:88) [15:55:35:813]: Executing op: SetBaseline(Baseline=1,)
MSI (s) (48:88) [15:55:52:947]: Executing op: CacheBaselineFile(Baseline=0,FileKey=file.dll,FilePath=C:\Program Files (x86)\Product\file.dll,,Existing=1)
MSI (s) (48:88) [15:55:53:062]: Executing op: CacheRTMFile(SourceFilePath=C:\Program Files (x86)\Product\file.dll,FileKey=file.dll,,ProductCode={CFB91CB0-17D9-44EB-BFB2-5307AB7E7DDC},ProductVersion=1.0.0,Attributes=4608,,,,CopierFlags=0,,,,,,)
MSI (s) (48:88) [15:55:53:062]: Executing op: RegisterSharedComponentProvider(PatchGUID={29A69684-DEB7-31EE-9559-B29ECDFF0563},MediaCabinet=#patch.cab,File=file.dll,Component={35F5C74C-4322-4729-9053-228044B7FD10},ComponentVersion=,ProductCode={CFB91CB0-17D9-44EB-BFB2-5307AB7E7DDC},ProductVersion=1.0.0,PatchSize=0,PatchAttributes=0,PatchSequence=10045,SharedComponent=0,IsFullFile=1)
MSI (s) (48:88) [15:55:53:062]: Executing op: FileCopy(SourceName=600|file.dll,SourceCabKey=file.dll,DestName=file.dll,Attributes=4608,FileSize=508416,PerTick=65536,,VerifyMedia=1,,,,,CheckCRC=0,Version=,Language=1033,InstallMode=58982400,,,,,,,)
MSI (s) (48:88) [15:55:53:067]: File: C:\Program Files (x86)\Product\file.dll;    Overwrite;    Won't patch;    Existing file is a lower version


Administrators or end users can disable the baseline cache by setting the MaxPatchCacheSize policy. Deployment developers should not set this policy. Developers may consider not authoring a component as a shared components, or just avoid authoring shared components all together. However, if shared components are necessary this features in Windows Installer 4.5 and newer can help maintain the stability of your product when patches are uninstalled.

Custom actions may be run again

Because a change to even a single component will reinstall the parent feature and all its child components, custom actions may be run again. This may often be by design, but can impact performance if the custom action performs a significant amount of work.


Deployment developers may be able to mitigate the impact of custom actions by designing when they run carefully, or eliminate them all together. Conditioning custom actions on components is most often a good strategy, assuming custom actions execute against component resources like native image generation (NGEN). As with the reinstallation of entire features, developers with such custom actions can reduce how often the custom actions run or even how much work they perform by refactoring components into more features.

Other general factors

There are also a number of factors that affect even initial installation of an MSI.

Hard disk performance

The speed of a hard disk will affect disk I/O. Multiply the effect of disk performance times the number of file copies mentioned above and it will have a negative impact on the overall install time.

Network performance

If the file is being installed from the network, before it is copied locally it is verified across the network first. This results in an extra read across the network. A bootstrap application itself may download the package before attempting to install which will mitigate this extra read operation.

Updated (3/14/2011): Added section about patches that update multiple installed products.

Leave a Comment
  • Please add 4 and 3 and type the answer here:
  • Post
  • Hello, Heath,

    I'm wondering how I can (and, actually is it possible) to determine what checks patch made to determine if it applicable to the system. For example, some windows patches such as MS10-034 for Win7 32-bit (KB980195), can be applied, then uninstalled. And when I try to install this patch again, I've got a message "This patch is not applicable to your system".

    So, how can I know for sure if I can or not use this patch before I run it? What is checking during patching start - registry keys? file versions? installed product IDs and versions? or something else?

    How can I retrieve this information from the patch? may be any reference... any advice is priceless. Please help.

    Thank you in advance.

  • @Yury, Windows patches are not MSPs and I'm not aware of any APIs. For Windows Installer patches (MSPs), you can call various APIs like MsiEnumProducts, for each then MsiDeterminePatchSequence, and filter out the filled array from that to see if the patch is applicable.

  • Heath, thank you!

    Actually, I know about such kind of possibilities, or using WUA (Microsoft.Update.Session.CreateupdateSearcher) and search online or offline  (I supposed that it is a preferable way or I'm wrong?).

    But unfortunately by my limitations I would like to know if I can determine it without any dynamic code, using only static state of the system such as registry, file size, date, version etc.

    And is it possible to retrieve such kind of information from wsusscn2.cab for example? Or from any other source?

    But thank you for answering anyway.

  • @Yury, for MSUs (Windows updates for Vista+) I'm not sure. For MSIs and MSPs, only the documented APIs are recommended. The binary file structure is not documented and can change.

  • Hello Heath,

    Is there a way rather than setting the MaxPatchCacheSize value (to zero) to disable the baseline caching when installing a patch?



  • @Donna Makhoul, no, unfortunately.

  • Thanks a lot Heath

  • is there anyway this could be put on a download manager no matter how i download this it never makes it here. :-(  

    I have tried about 20 times various machines all download the 1.5gb none successfully complete the copy after the download leaving files missing ???

  • @john m, the internal download mechanism uses BITS, but you can download the ISO from go.microsoft.com/fwlink. Be sure to verify the checksum before burning it, and verify the burn. See blogs.msdn.com/.../verify-the-iso-checksum-for-visual-studio-2010-service-pack-1-before-installing.aspx for more information.

  • Can you explain more about 'Deployment developers can mitigate this problem by fragmenting components into smaller features in the target product'? Does this mean creating new child features and moving(deviding) existing components into them? AIK patch can't reorganize feture-component tree.


  • @sky, you should better fragment your components into smaller features *before* you ship your MSI. Yes, patches cannot remove components from features (they can certain remove features and their components, or add components to existing features). This is why it's important to understand the nuances of patching, design for them, and test your servicing model with patches before you ship your baseline MSIs.

  • I'm facing a little bit different problem with patch installation performance. We deliver almost empty MSI to our customers and bunch of MSP packages, which can be installed simultaneously to this particular MSI (through the patch family topologies). If our customer chose to install multiple MSP files onto this MSI we are doing installation of multiple MSP files at once. It still be better performance if we install let's say 12 MSPs at once rather than doing 12 times installation of single MSP.

    But, I'm wondering, why are in-memory transformations during this process so slowly? The most suspicious part is the InstallFiles section at the costing part. It takes more than one second per component to detect the state, even if the component is not installed.

    It looks like:

    MSI (s) (C0:B0) [12:37:49:987]: Entering MsiQueryComponentStateW. szProductCode: {5EABB6C2-FA29-473C-8BB1-5EF28A5CBDFF}, szUserSid: , dwInstallContext: 4, szComponentCode: {2D99BE2C-A2C2-5DF3-8142-D1146ED7FDD0}

    MSI (s) (C0:B0) [12:37:50:003]: MsiQueryComponentStateW is returning: 1607

    MSI (s) (C0:B0) [12:37:50:050]: Transforming table Property.

    MSI (s) (C0:B0) [12:37:50:097]: Transforming table Property.

    MSI (s) (C0:B0) [12:37:50:144]: Transforming table Property.

    ... (repeated 20 times)

    MSI (s) (C0:B0) [12:37:51:128]: Transforming table Property.

    MSI (s) (C0:B0) [12:37:51:175]: Transforming table Property.

    MSI (s) (C0:B0) [12:37:51:206]: Transforming table Property.

    MSI (s) (C0:B0) [12:37:51:237]: Transforming table Property.

    MSI (s) (C0:B0) [12:37:51:269]: Entering MsiQueryComponentStateW. szProductCode: {5EABBDC2-FA26-473C-8BB1-5EF28A5CBDFF}, szUserSid: , dwInstallContext: 4, szComponentCode: {57E5E157-3495-5639-B292-CBA2EE263C13}

    How can that be explained? What is Windows Installer doing behind those "Transforming table Property" for every component so many times?

Page 1 of 1 (12 items)