1

I'm working on adapting part of a powershell script to a WPF C# windows service and I'm having trouble finding a way to get the last installed windows update like the following script does. I need a way to check that a workstation has installed windows updates in the last 30 days, if it has it passes the audit if not it fails the audit.

$today = Get-Date   
$session = (New-Object -ComObject 'Microsoft.Update.Session')
$lastUpdate = ($session.QueryHistory("",0,100) | Where-Object 
{$_.ResultCode -eq 2}).Date | Sort-Object -descending
$compInfo = Get-ComputerInfo | select WindowsProductName, WindowsVersion
$OSversion = ($compInfo.WindowsProductName + " " + $compInfo.WindowsVersion).replace("Windows ","")

if (!$lastUpdate) {
    $never = $true
    $lastUpdate = Get-Date -Year 0001 -Month 01 -Day 01 -Hour 00 -Minute 00 -Second 00
} else {
    # Convert from UTC to timezone
    $timediff = [int]((Get-Timezone | select BaseUtcOffset | Out-String -Stream)[3][2].ToString())
    $lastUpdate = $lastUpdate[0].AddHours(-$timediff)
}

# Audit result
if ($never -or [datetime]$lastUpdate -le ($today.AddDays(-30))) {
    # Audit fail
    $pass = $false
    if ($never) {
        $lastUpdate = "Never"
    } else {
        $lastUpdate = [string]$lastUpdate
    }
} else {
    # Audit pass
}

I've been reading about the WUApi, but have not been able to get any variation of the following code to not produce errors when trying to use the IUpdateSearcher class. I've tried different namespaces an such and still haven't had any luck.

using WUApiLib;

UpdateSessionClass uSession = new UpdateSessionClass();
IUpdateSearcher uSearcher = uSession.CreateUpdateSearcher();
ISearchResult uResult = uSearcher.Search("IsInstalled=0 and Type='Software'");

It doesn't seem like I will be able to replicate the powershell version exactly, but from what I've researched on the WUAPI I could just check if the computer has any updates that haven't been installed and assign a pass if there are no updates and fail if there are.

  • 1
    Does this answer your question? [How do I get a list of installed updates and hotfixes?](https://stackoverflow.com/questions/815340/how-do-i-get-a-list-of-installed-updates-and-hotfixes) – Ruud Helderman Jul 07 '22 at 20:16
  • "not been able to get any variation of the following code to not produce errors when trying to use the IUpdateSearcher class." Compilation errors or runtime errors? Please copy/paste relevant error messages into your question. I tried with .NET Core 3.1 and had little trouble getting Interop.WUApiLib to work. Which version of .NET are you using? – Ruud Helderman Jul 07 '22 at 20:33
  • I am using .NET 6.0 and get the following errors. The type or namespace name 'UpdateSessionClass' could not be found (are you missing a using directive or an assembly reference?) The type or namespace name 'IUpdateSearcher' could not be found (are you missing a using directive or an assembly reference?) 5 Active – Landon George Jul 07 '22 at 21:12
  • This worked flawlessly for me (on a fresh .NET 6 console project; Visual Studio 2022). In the solution explorer, right-click on Dependencies and select "Add COM Reference..." Scroll down and check "WUAPI 2.0 Type Library"; click OK. Edit Program.cs into: `Console.WriteLine(new WUApiLib.UpdateSession().QueryHistory("", 0, 1)[0].Date);` Press F5 to build and run. – Ruud Helderman Jul 07 '22 at 21:32
  • This looks like exactly what I wanted, it ran fine for me too. Looks like the COM reference is what I was missing. Could you elaborate on how you chose those QueryHistory values? – Landon George Jul 07 '22 at 21:44
  • I can see your question is slightly more specific than the duplicate I proposed. I posted an answer. – Ruud Helderman Jul 08 '22 at 09:50

2 Answers2

0

As explained here, you could compile a file summarizing the updates.

By default, it is written to your desktop:

"%USERPROFILE%\Desktop\WindowsUpdate.log"

This operation can be started as sub-process of your skript or program. It does not require admininstrative privileges.

You can then read the file up to something like the following:

2022.07.06 16:56:05.5197996 3936  8528  UDP               Title = Security Intelligence-Update f??r Microsoft Defender Antivirus - KB2267602 (Version 1.369.880.0)
2022.07.06 16:56:05.5198024 3936  8528  UDP               UpdateId = B701392C-6DF8-4D94-A07F-35D06C5014E7.200

The Title lines contain datei/time and KB number of the updates in chronological order.

Axel Kemper
  • 10,544
  • 2
  • 31
  • 54
0

In comments, you mentioned these (compile-time) errors:

The type or namespace name 'UpdateSessionClass' could not be found (are you missing a using directive or an assembly reference?)
The type or namespace name 'IUpdateSearcher' could not be found (are you missing a using directive or an assembly reference?)

Apparently, something was wrong with your reference to WUApi.dll. This should work:

  1. In the solution explorer, directly below the project name, right-click on Dependencies. A context menu appears.
  2. From the context menu, select "Add COM Reference..." The "Reference Manager" dialog appears.
  3. In the dialog, on tab COM, scroll down and check "WUAPI 2.0 Type Library". Click OK.

Now you can query the update history, just like you did in the PowerShell script.

using WUApiLib;

IUpdateSession3 session = new UpdateSession();
IUpdateHistoryEntryCollection history = session.QueryHistory("", 0, 1);
if (history.Count > 0)
{
    Console.WriteLine($"Latest Windows update was on {history[0].Date}.");
}
else
{
    Console.WriteLine("Not a single Windows update found.");
}

Notice I am not sorting history myself. From the documentation (emphasis mine):

[out] retval A pointer to an IUpdateHistoryEntryCollection interface that contains the matching event records on the computer in descending chronological order.

In other words, the top row is the latest update. Hence these parameters when calling IUpdateSession3::QueryHistory:

  • "": no search criteria, just get me anything
  • 0: start from the top
  • 1: give me (at most) one row

Please keep in mind that the history may yield updates that have been rolled back afterwards. I don't know how to fix this. But I assume your PowerShell script was having the same issue.

Kudos to the useful code sample in this post: https://stackoverflow.com/a/815525/2485966

Ruud Helderman
  • 10,563
  • 1
  • 26
  • 45