The Road to Delphi – a Blog about programming

Delphi – Free Pascal – Oxygene

search for installed windows updates using Delphi, WMI and WUA

7 Comments

Sometimes we need determine if a particular windows hotfix or update is installed in the system. to do this task you can use two approaches

WMI (Windows Management Instrumentation)

using the Win32_QuickFixEngineering class, you can retrieve a small system-wide update, commonly referred to as a quick-fix engineering (QFE) update.

check this code which list the updates installed in the system

procedure  GetWin32_QuickFixEngineeringInfo;
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_QuickFixEngineering','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Caption                        %s',[FWbemObject.Caption]));// String
    //Writeln(Format('CSName                         %s',[FWbemObject.CSName]));// String
    Writeln(Format('Description                    %s',[FWbemObject.Description]));// String
    Writeln(Format('FixComments                    %s',[FWbemObject.FixComments]));// String
    Writeln(Format('HotFixID                       %s',[FWbemObject.HotFixID]));// String
    Writeln(Format('InstallDate                    %s',[FWbemObject.InstallDate]));// Datetime
    Writeln(Format('InstalledBy                    %s',[FWbemObject.InstalledBy]));// String
    Writeln(Format('InstalledOn                    %s',[FWbemObject.InstalledOn]));// String
    Writeln(Format('Name                           %s',[FWbemObject.Name]));// String
    Writeln(Format('ServicePackInEffect            %s',[FWbemObject.ServicePackInEffect]));// String
    Writeln(Format('Status                         %s',[FWbemObject.Status]));// String
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

Now to find if a particular update is installed you can check the HotFixID property value (which is the Unique identifier associated with a particular update) and write a function like this

//use in this way ISHotFixID_Installed('KB982799')
function  ISHotFixID_Installed(const HotFixID : string): Boolean;
const
  wbemFlagForwardOnly = $00000020;
  wbemFlagReturnImmediately = $00000010;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM Win32_QuickFixEngineering Where HotFixID="%s"',[HotFixID]),'WQL',wbemFlagForwardOnly OR wbemFlagReturnImmediately);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  Result:= oEnum.Next(1, FWbemObject, iValue) = 0;
end;

Ok this is fine, but Starting with Windows Vista, the Win32_QuickFixEngineering class returns only the updates supplied by Component Based Servicing (CBS), so some updates are not listed.

WUA (Windows Update Agent)

using the Windows Update Agent API is a best option to retrieve the list of updates, you can access the interfaces and objects from this API from delphi importing the wuapi.dll file or creating a late-binding com object using the Microsoft.Update.Session GUID. the next samples uses the late-binding way.

from the MSDN site :

The Windows Update Agent (WUA) API is a set of COM interfaces that enable system administrators and programmers to access Windows Update and Windows Server Update Services (WSUS). Scripts and programs can be written to examine which updates are currently available for a computer, and then you can install or uninstall updates.

to implement a search of the installed updates we need to use the IUpdateSearcher Interface using the Search method setting the search criteria.

check this sample

  //create the Com object instance
  updateSession:= CreateOleObject('Microsoft.Update.Session');
  updateSearcher    := updateSession.CreateUpdateSearcher;
  //set the search criteria, installed =1 means updates that are installed on the destination computer, Type='Software'  retrieve only applications updates
  updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 1 and Type=%s',[QuotedStr('Software')]));

Now to find if a particular update is installed you can parse the Title property of the IUpdate Interface which contains the name of the update like this Security Update for Windows 7 for x64-based Systems (KB978542)

//use in this way ISHotFixID_Installed('KB982799')
function  ISHotFixID_Installed(const HotFixID : string): Boolean;
var
  updateSession      : OleVariant;
  updateSearcher     : OleVariant;
  updateEntry        : OleVariant;
  updateSearchResult : OleVariant;
  UpdateCollection   : OleVariant;
  oEnum              : IEnumvariant;
  iValue             : LongWord;
begin
 result:=False;
  updateSession:= CreateOleObject('Microsoft.Update.Session');
  updateSearcher    := updateSession.CreateUpdateSearcher;
  //this line improves the performance , the online porperty indicates whether the UpdateSearcher goes online to search for updates. so how we are looking for already installed updates we can set this value to false
  updateSearcher.online:=False;
  updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 1 and Type=%s',[QuotedStr('Software')]));
  UpdateCollection  := updateSearchResult.Updates;
  oEnum         := IUnknown(UpdateCollection._NewEnum) as IEnumVariant;
  while oEnum.Next(1, updateEntry, iValue) = 0 do
  begin
    Result:=Pos(HotFixID,updateEntry.Title)>0;
    updateEntry:=Unassigned;
    if Result then break;
  end;
end;

check these another useful functions

Getting the installed updates list

procedure  GetListInstalledUpdates;
var
  updateSession        : OleVariant;
  updateSearcher       : OleVariant;
  updateSearchResult   : OleVariant;
  updateEntry          : OleVariant;
  UpdateCollection     : OleVariant;
  oEnum                : IEnumvariant;
  iValue               : LongWord;
begin
  updateSession:= CreateOleObject('Microsoft.Update.Session');
  updateSearcher := updateSession.CreateUpdateSearcher;
  Writeln('Searching');
  //IUpdateSearcher::Search Method http://msdn.microsoft.com/en-us/library/aa386526%28v=VS.85%29.aspx
  updateSearcher.online:=False;
  updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 1 and Type=%s',[QuotedStr('Software')]));
  UpdateCollection  := updateSearchResult.Updates;
  oEnum         := IUnknown(UpdateCollection._NewEnum) as IEnumVariant;
  //IUpdate Interface http://msdn.microsoft.com/en-us/library/aa386099%28v=VS.85%29.aspx
  while oEnum.Next(1, updateEntry, iValue) = 0 do
  begin
    Writeln(updateEntry.Title);
    updateEntry:=Unassigned;
  end;
  Writeln('Done');
end;

Getting the not installed updates list (slow because need to check online)

procedure  GetListNotInstalledUpdates;
var
  updateSession        : OleVariant;
  updateSearcher       : OleVariant;
  updateSearchResult   : OleVariant;
  updateEntry          : OleVariant;
  UpdateCollection     : OleVariant;
  oEnum                : IEnumvariant;
  iValue               : LongWord;
begin
  updateSession:= CreateOleObject('Microsoft.Update.Session');
  updateSearcher := updateSession.CreateUpdateSearcher;
  Writeln('Searching');
  updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 0 and Type=%s',[QuotedStr('Software')]));
  UpdateCollection  := updateSearchResult.Updates;
  oEnum         := IUnknown(UpdateCollection._NewEnum) as IEnumVariant;
  while oEnum.Next(1, updateEntry, iValue) = 0 do
  begin
    Writeln(updateEntry.Title);
    updateEntry:=Unassigned;
  end;
  Writeln('Done');
end;

Getting the hidden installed updates list

procedure  GetListInstalledHiddenUpdates;
var
  updateSession        : OleVariant;
  updateSearcher       : OleVariant;
  updateSearchResult   : OleVariant;
  updateEntry          : OleVariant;
  UpdateCollection     : OleVariant;
  oEnum                : IEnumvariant;
  iValue               : LongWord;
begin
  updateSession:= CreateOleObject('Microsoft.Update.Session');
  updateSearcher := updateSession.CreateUpdateSearcher;
  Writeln('Searching');
  updateSearcher.online:=False;
  updateSearchResult:= updateSearcher.Search(Format('IsHidden=1 and IsInstalled = 1 and Type=%s',[QuotedStr('Software')]));
  UpdateCollection  := updateSearchResult.Updates;
  oEnum         := IUnknown(UpdateCollection._NewEnum) as IEnumVariant;
  while oEnum.Next(1, updateEntry, iValue) = 0 do
  begin
    Writeln(updateEntry.Title);
    updateEntry:=Unassigned;
  end;
  Writeln('Done');
end;
About these ads

Author: Rodrigo

Just another Delphi guy.

7 thoughts on “search for installed windows updates using Delphi, WMI and WUA

  1. that’s very good~

  2. It’s ok, but didn’t find all hotfix.
    I have installed this one:
    “Image Mastering API v2.0 (IMAPIv2.0) for Windows Server 2003 (KB932716) ”

    It is installed on those keys:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Updates\Windows XP\SP4\KB932716-v2
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache\KB932716-v2
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KB932716-v2
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\HotFix\KB932716-v2

    But it is not in the result list.

    I searched in WUA library but i didn’t find how to resolve this.
    I use “IncludePotentiallySupersededUpdates := true;” and don’t succeed.

    I saw that with “Add or Remove Progrmas” utility and with “Show updates” checked i can see.

    Do you have a solution fot this, please.

    Thank you.

  3. hi,

    can you please provide the same for remote machine access for windows updates list

  4. Pingback: WMI Tasks using Delphi – Operating Systems « The Road to Delphi – a Blog about programming

  5. Rodrigo :
    Do you want a sample using the WMI or WUA?

    It would be nice for WMI!!!

    Thanks in advance !

  6. Rodrigo :
    Do you want a sample using the WMI or WUA?

    Hello Rodrigo,

    i’m looking for an example to query the updatelist of a remote machine as well.
    Could you please provide an example of using WUA.

    Your help would be highly appreciated…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 586 other followers