Dayan Dayan - 27 days ago 10
C# Question

WUApiLib IUpdateInstaller2 yields Error; Some OS updates install others throw HResult -2145124318

Updates are being downloaded from a local server and not from WUS or Microsoft Repositories. Local server is Linux based which host's the contents for each update.

I'm not using

UpdateDownloader
to download from Microsoft Servers, i manually download the update content and then use
CopyToCache
.

These installed fine

Security Update for Microsoft .NET Framework 3.5 SP1 on Windows XP, Server 2003, Vista, Server 2008 x86 (KB2736416)

Security Update for Microsoft Visual Studio 2010 (KB2542054)

These Didn't


Security Update for Microsoft .NET Framework 4 on XP, Server 2003,
Vista, Windows 7, Server 2008 x86 (KB2840628)


Update for Microsoft .NET Framework 3.5 SP1 on Windows XP, Server 2003, Vista and Server 2008 x86 (KB2836940)

How my process works

I receive this for an install from a local server which i use to download all download content for the update. (The blockquote text above KB2840628 is the example provided below)

{
"app_uris": [
{
"file_name": "msipatchregfix-x86_94a84b80b8b45a1ac53a0e5d085513da0f099655.exe",
"file_uri": "https://192.168.5.108/packages/d13c13c81f94fbb48f39c817a71ff239a31773d3a0e821a968dc42a913892841/msipatchregfix-x86_94a84b80b8b45a1ac53a0e5d085513da0f099655.exe",
"file_size": 130600
},
{
"file_name": "ndp40-kb2840628-v2-x86_891d50ff3c1322db3fb0fde222ebb0aaa5260272.exe",
"file_uri": "https://192.168.5.108/packages/d13c13c81f94fbb48f39c817a71ff239a31773d3a0e821a968dc42a913892841/ndp40-kb2840628-v2-x86_891d50ff3c1322db3fb0fde222ebb0aaa5260272.exe",
"file_size": 13294216
}
],
"app_id": "d13c13c81f94fbb48f39c817a71ff239a31773d3a0e821a968dc42a913892841",
"app_name": "Security Update for Microsoft .NET Framework 4 on XP, Server 2003, Vista, Windows 7, Server 2008 x86 (KB2840628)"
}


With that said, the problem is that some updates install perfectly fine, but certain updates (I believe the ones that have more than one
bundle-updates
) don't go thru, its driving me mad!

I first download each
Uri
and then load them into the update with
CopyToCache
.

var collection = new UpdateCollection();
IList<string> updateFiles = Directory.GetFiles(updateFolder);
var fileCollection = new StringCollection();

try
{
foreach (var file in updateFiles)
fileCollection.Add(file);

//Error happens here on certain updates. Not all.
((IUpdate2)update.BundledUpdates[0]).CopyToCache(fileCollection);
collection.Add(update);
return collection;
}
catch (Exception e)
{
return null;
}


After this, the returned collection is passed through my
WindowsUpdateInstaller
Method shown below:

IUpdateSession Session = new UpdateSession();
var updatesToInstall = //THIS GETS THE RETURN FROM THE ABOVE CODE...
var installer = (IUpdateInstaller2)Session.CreateUpdateInstaller();

installer.ForceQuiet = true;
installer.AllowSourcePrompts = false;
installer.Updates = updatesToInstall;

foreach (IUpdate updateNode in installer.Updates)
{
updateNode.AcceptEula();
}

//FAILS HERE WITH "-2145124318, Result code: orcFailed",
var installationRes = installer.Install();
var installResult = installationRes.GetUpdateResult(0);


The update installs just fine if i manually double click on the executable it and install it manually without using the code.

Answer

It appears that the WUApi exposes IUpdate which holds multiple levels of bundleUpdates. Before, I was simply retrieving the top level of bundleUpdates which by doing so, made certain updates fail due to missing content required by the update; most windows updates have more than 1 level of bundles.

For example, imagine this tree like structure for 1 Update (aka IUpdate):

Update 1
    ---> Bundle 1
       *URL 1
       *URL 2
         ----> Bundle 1A
               *URL 1
               *URL 2
               *URL 3

    ---> Bundle 2
       *URL 1
         ----> Bundle 2A
               *URL 1
               *URL 2
         ----> Bundle 2B
               *URL 1

   ----> Bundle 3
         *URL 1
          ----> Bundle 3A
                *URL 1
                *URL 2

My Solution was to create a Recursive function to parse each update individually and keep all URIs in a dictionary of key type "bundleName" and list of values that will hold all URIs for that particular bundle.

Like So:

Dictionary<string, List<string>>

The Recursive function is the following:

 private static Dictionary<string, List<string>> GetAllUpdates(IUpdate iUpdate)
        {
            var bundleDict = new Dictionary<string, List<string>>();

            foreach (IUpdate bundle in iUpdate.BundledUpdates)
            {
                foreach (IUpdateDownloadContent udc in bundle.DownloadContents)
                {
                    var downloadContents = new List<string>();
                    if (String.IsNullOrEmpty(udc.DownloadUrl))
                        continue;

                    var url = udc.DownloadUrl;
                    downloadContents.Add(url);

                    if (!bundleDict.ContainsKey(bundle.Title))   
                        bundleDict.Add(bundle.Title, downloadContents);
                }

                if (bundle.BundledUpdates.Count > 0)
                {
                    var valuesReturned = GetAllUpdates(bundle);
                    foreach (var data in valuesReturned)
                    {
                      if(!bundleDict.ContainsKey(data.Key))     
                         bundleDict.Add(data.Key, data.Value);
                    }

                }
            }

            return bundleDict;
        }