Trying to read the last succesful Windows Update time from a remote machine, but getting an error on the key
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\
sample code:
var hive = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machineName);
var soft = hive.OpenSubKey("SOFTWARE");
var micro = soft.OpenSubKey("Microsoft");
var wind = micro.OpenSubKey("Windows");
var currver = wind.OpenSubKey("CurrentVersion");
var wu = currver.OpenSubKey("WindowsUpdate"); // returns NULL
var au = wu.OpenSubKey("Auto Update"); // throws exception "Object referece not set to an instance of an object"
var res = au.OpenSubKey("Results");
var inst = res.OpenSubKey("Install");
var lastUpdate = inst.GetValue("LastSuccessTime").ToString();
Console.WriteLine(lastUpdate);
I have verified the key is correct, and I'm not sure what the problem is.
EDIT The error I receive is
Object reference not set to an instance of an object.
because the subkey "WindowsUpdate" is returning NULL.
The reason I was getting NULL from the OpenSubKey() method was because I needed to add a RegistryView parameter to OpenRemoteBaseKey(RegistryHive.LocalMachine, machineName, RegistryView.Default|64|32);
Thanks to comments from Alex K and this StackOverflow Answer, I was able to resolve my issue by replacing my code with the following static methods. Just add a reference to WUApiLib.dll, then
using WUApiLib;
public static IEnumerable<IUpdateHistoryEntry> GetAllUpdates(string machineName)
{
Type t = Type.GetTypeFromProgID("Microsoft.Update.Session", machineName);
UpdateSession session = (UpdateSession)Activator.CreateInstance(t);
IUpdateSearcher updateSearcher = session.CreateUpdateSearcher();
int count = updateSearcher.GetTotalHistoryCount();
IUpdateHistoryEntryCollection history = updateSearcher.QueryHistory(0, count);
return history.Cast<IUpdateHistoryEntry>();
}
public static DateTime GetLastSuccessfulUpdateTime(string machineName)
{
DateTime lastUpdate = DateTime.Parse("0001-01-01 00:00:01");
var updates = GetAllUpdates(machineName);
if (updates.Where(u => u.HResult == 0).Count() > 0)
{
lastUpdate = updates.Where(u => u.HResult == 0).OrderBy(x => x.Date).Last().Date;
}
return lastUpdate;
}
To use,
DateTime lastSuccessfulUpdate = GetLastSuccessfulUpdateTime("PC-01");
NOTE: For reference, this only returns the single most recent, successful update package's timestamp. It does not mean that all other Windows Updates have been successful. In order to get a list of failed updates, use the following:
IList<IUpdateHistoryEntry> failedUpdates = GetAllUpdates("PC-01")
.Where(upd => upd.HResult != 0).ToList();
To get all timestamps of failed updates,
IList<DateTime> failedUpdates = GetAllUpdates("PC01")
.Where(upd => upd.HResult != 0)
.Select(upd => upd.Date).ToList();