The Road to Delphi

Delphi – Free Pascal – Oxygene


Leave a comment

WMI Tasks using Delphi – Processes

How do I run an application in a hidden window?

Call the application from an app that uses the Win32_Process and Win32_ProcessStartup classes.

const
  wbemFlagForwardOnly = $00000020;
  HIDDEN_WINDOW       = 0;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObject   : OLEVariant;
  objProcess    : OLEVariant;
  objConfig     : OLEVariant;
  ProcessID     : Integer;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObject   := FWMIService.Get('Win32_ProcessStartup');
  objConfig     := FWbemObject.SpawnInstance_;
  objConfig.ShowWindow := HIDDEN_WINDOW;
  objProcess    := FWMIService.Get('Win32_Process');
  objProcess.Create('Notepad.exe', null, objConfig, ProcessID);
  Writeln(Format('Pid %d',[ProcessID]));
end;

How do I determine which scripts are running on the local computer?

Use the Win32_Process class and return all processes with the name Cscript.exe or Wscript.exe. To determine the individual scripts running in these processes, check the value of the CommandLine property.

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(Format('SELECT Name, CommandLine FROM Win32_Process Where Name="%s" or Name="%s"',['cscript.exe','wscript.exe']),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Name         %s',[String(FWbemObject.Name)]));
    Writeln(Format('Command Line %s',[String(FWbemObject.CommandLine)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I find out the account name under which a process is running?

Use the Win32_Process class and the GetOwner method.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  NameOfUser    : OleVariant;
  UserDomain    : OleVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.GetOwner(NameOfUser, UserDomain);
    Writeln(Format('Process  %s is owned by %s\%s',[String(FWbemObject.Name),String(NameOfUser), String(UserDomain)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I change the priority of a running process?

Use the Win32_Process class and the SetPriority method.

const
  wbemFlagForwardOnly = $00000020;
  ABOVE_NORMAL = 32768;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  Value         : OleVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process Where Name="Notepad.exe"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Value:=ABOVE_NORMAL;
    FWbemObject.SetPriority(Value);
    FWbemObject:=Unassigned;
  end;
end;

How do I terminate a process?

Use the Win32_Process class and the Terminate method.

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_Process Where Name="Notepad.exe"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.Terminate();
    FWbemObject:=Unassigned;
  end;
end;

How do I determine how much processor time and memory each process is using?

Use the Win32_Process class and properties such as KernelModeTime, WorkingSetSize, PageFileUsage, and PageFaults.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  sngProcessTime: Double;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_Process','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Process          %s',[String(FWbemObject.Name)]));
    sngProcessTime := (Int64(FWbemObject.KernelModeTime) +  Int64(FWbemObject.UserModeTime)) / 10000000.0;
    Writeln(Format('Processor Time   %n',[sngProcessTime]));
    Writeln(Format('Process Id       %d',[Integer(FWbemObject.ProcessID)]));
    Writeln(Format('Working SetSize  %d',[Int64(FWbemObject.WorkingSetSize)]));
    Writeln(Format('Page File Usage  %d',[Int64(FWbemObject.PageFileUsage)]));
    Writeln(Format('Page Faults      %d',[Int64(FWbemObject.PageFaults)]));
    FWbemObject:=Unassigned;
  end;
end;

This article is based in the MSDN entry WMI Tasks: Processes


1 Comment

WMI Tasks using Delphi – Printers and Printing

How do I add a new printer connection to a remote computer?

Use the Win32_Printer class and the AddPrinterConnection method.

var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObject   : OLEVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObject   := FWMIService.Get('Win32_Printer');
  FWbemObject.AddPrinterConnection('\\PrintServer1\ArtDepartmentPrinter');
end;

How do I set the default printer?

Use the Win32_Printer class and the SetDefaultPrinter method.

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(Format('SELECT * FROM Win32_Printer Where Name = "%s"',['PrinterName']),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
    FWbemObject.SetDefaultPrinter();
end;

How do I cancel print jobs using WMI?

Use the Win32_Printer class, and the CancelAllJobs method.

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_Printer','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.CancelAllJobs();
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the default printer for a computer?

Use the Win32_Printer class, and check whether the Default property is True.

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_Printer Where Default = True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Name    %s',[String(FWbemObject.Name)]));// String
    FWbemObject:=Unassigned;
  end;
end;

This post is based in the MSDN entry WMI Tasks: Printers and Printing


12 Comments

Implementing a Delphi for..in loop on COM collections and Variant Arrays

Enumerating a collection of Variants

Many times when you are working with COM objects you need iterate over a collection, and usually the way to do this is using the _NewEnum function (which return a IUnknown interface) implemented by the COM class and then assign that value to a IEnumVariant variable. something like this

var
 Enum   : IEnumVariant;
 iValue : LongWord;
begin
 oEnum    := IUnknown(ACollection._NewEnum) as IEnumVariant;
  while oEnum.Next(1, AItem, iValue) = S_OK do
  begin
    //do something 
         
  end;

This not look very complicated, but when do you have to work with many nested COM collections, the code turns more difficult to follow. Check this sample :

begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  wmiDiskDrives := FWMIService.ExecQuery('SELECT Caption, DeviceID FROM Win32_DiskDrive','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(wmiDiskDrives._NewEnum) as IEnumVariant;//first enumerator
  while oEnum.Next(1, wmiDiskDrive, iValue) = 0 do
  begin
     DeviceID:=StringReplace(String(wmiDiskDrive.DeviceID),'\','\\',[rfReplaceAll]);
     wmiDiskPartitions := FWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="%s"} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[String(DeviceID)]),'WQL',wbemFlagForwardOnly);
     oEnum2          := IUnknown(wmiDiskPartitions._NewEnum) as IEnumVariant;//second enumerator
     while oEnum2.Next(1, wmiDiskPartition, iValue) = 0 do
     begin
        wmiLogicalDisks := FWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="%s"} WHERE AssocClass = Win32_LogicalDiskToPartition',[String(wmiDiskPartition.DeviceID)]),'WQL',wbemFlagForwardOnly);
        oEnum3          := IUnknown(wmiLogicalDisks._NewEnum) as IEnumVariant;//third enumerator
        while oEnum3.Next(1, wmiLogicalDisk, iValue) = 0 do
        begin
          Writeln(Format('Drive letter associated with disk drive  %s %s Partition %s is %s',[String(wmiDiskDrive.Caption),String(wmiDiskDrive.DeviceID),String(wmiDiskPartition.DeviceID),String(wmiLogicalDisk.DeviceID)]));
          wmiLogicalDisk:=Unassigned;
        end;
       wmiDiskPartition:=Unassigned;
     end;
    wmiDiskDrive:=Unassigned;
    Writeln;
  end;
end;

Now look the same code using a for in loop in vbscript, which looks much more easy to follow and understeand

ComputerName = "."
Set wmiServices  = GetObject ("winmgmts:{impersonationLevel=Impersonate}!//" & ComputerName)
Set wmiDiskDrives =  wmiServices.ExecQuery("SELECT Caption, DeviceID FROM Win32_DiskDrive")

For Each wmiDiskDrive In wmiDiskDrives
    WScript.Echo "Disk drive Caption: " & wmiDiskDrive.Caption & VbNewLine & "DeviceID: " & " (" & wmiDiskDrive.DeviceID & ")"
    query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='"  & wmiDiskDrive.DeviceID & "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition"    
    Set wmiDiskPartitions = wmiServices.ExecQuery(query)
    For Each wmiDiskPartition In wmiDiskPartition
        Set wmiLogicalDisks = wmiServices.ExecQuery ("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" & wmiDiskPartition.DeviceID & "'} WHERE AssocClass = Win32_LogicalDiskToPartition") 
        For Each wmiLogicalDisk In wmiLogicalDisks
            WScript.Echo "Drive letter associated with disk drive = " & wmiDiskDrive.Caption & wmiDiskDrive.DeviceID & VbNewLine & " Partition = " & wmiDiskPartition.DeviceID & VbNewLine & " is " & wmiLogicalDisk.DeviceID
        Next      
    Next
Next

Now look back again the delphi code using for..in loop for iterate over the COM collection

begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  wmiDiskDrives := FWMIService.ExecQuery('SELECT Caption, DeviceID FROM Win32_DiskDrive','WQL',wbemFlagForwardOnly);
  for wmiDiskDrive in GetOleVariantEnum(wmiDiskDrives) do
  begin
     DeviceID:=StringReplace(String(wmiDiskDrive.DeviceID),'\','\\',[rfReplaceAll]);
     wmiDiskPartitions := FWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="%s"} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[String(DeviceID)]),'WQL',wbemFlagForwardOnly);
     for wmiDiskPartition in GetOleVariantEnum(wmiDiskPartitions) do
     begin
        wmiLogicalDisks := FWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="%s"} WHERE AssocClass = Win32_LogicalDiskToPartition',[String(wmiDiskPartition.DeviceID)]),'WQL',wbemFlagForwardOnly);
        for wmiLogicalDisk in GetOleVariantEnum(wmiLogicalDisks)  do
          Writeln(Format('Drive letter associated with disk drive  %s %s Partition %s is %s',[String(wmiDiskDrive.Caption),String(wmiDiskDrive.DeviceID),String(wmiDiskPartition.DeviceID),String(wmiLogicalDisk.DeviceID)]));
     end;
    Writeln;
  end;
end;

The delphi code now looks more cleaner and easy to follow. Now you are wondering how this was made? the answer is writting a class with an enumerator and a function which returns an interface with the implemented enumerator.

check how the class looks

type
  IOleVariantEnum  = interface
    function  GetCurrent: OLEVariant;
    function  MoveNext: Boolean;
    property  Current: OLEVariant read GetCurrent;
  end;

  IGetOleVariantEnum = interface
    function GetEnumerator: IOleVariantEnum;
  end;

  TOleVariantEnum = class(TInterfacedObject, IOleVariantEnum, IGetOleVariantEnum)
  private
    FCurrent : OLEVariant;
    FEnum    : IEnumVARIANT;
  public
    function GetEnumerator: IOleVariantEnum;
    constructor Create(Collection: OLEVariant);
    function  GetCurrent: OLEVariant;
    function  MoveNext: Boolean;
    property  Current: OLEVariant read GetCurrent;
  end;

As you see we have a base interface (IOleVariantEnum) with the methods to implement a enumerator, another interface (IGetOleVariantEnum) which return a enumerator and finally a class which descend from both interfaces and implements the logic of the enumerator.

The implementation of the last class is very simple and uses the IEnumVARIANT interface to iterate over the collection and return the current item.

constructor TOleVariantEnum.Create(Collection: OLEVariant);
begin
  inherited Create;
  FEnum := IUnknown(Collection._NewEnum) As IEnumVARIANT; //Set the COM enumerator for the variants collection
end;

function TOleVariantEnum.MoveNext: Boolean;
var
  iValue        : LongWord;
begin
  FCurrent:=Unassigned;//clear the previous value stored in FCurrent avoiding memory leaks
  Result:= FEnum.Next(1, FCurrent, iValue) = S_OK; //Get the next item in the collection into FCurrent
end;

function TOleVariantEnum.GetCurrent: OLEVariant;
begin
  Result:=FCurrent;
end;

function TOleVariantEnum.GetEnumerator: IOleVariantEnum;
begin
  Result:=Self;
end;

And now finally the function which makes the magic

function GetOleVariantEnum(Collection:OleVariant):IGetOleVariantEnum;
begin
 Result := TOleVariantEnum.Create(Collection);
end;

Now the good part of this is which you don’t need to worry of release the value returned by the GetOleVariantEnum function.

Finally you can rewrite your code using the TOleVariantEnum class

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: TOleVariantEnum;
  FWbemObject   : OLEVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= TOleVariantEnum.Create(FWMIService.ExecQuery('SELECT ProcessId FROM Win32_Process','WQL',wbemFlagForwardOnly));
  try
    for FWbemObject in FWbemObjectSet do
      Writeln(Format('Pid %d',[Integer(FWbemObject.ProcessId)]));
  finally
    FWbemObjectSet:=nil;
  end;
end;

or simply using the GetOleVariantEnum function.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT ProcessId FROM Win32_Process','WQL',wbemFlagForwardOnly);
  for FWbemObject in GetOleVariantEnum(FWbemObjectSet) do
    Writeln(Format('Pid %d',[Integer(FWbemObject.ProcessId)]));
end;

Enumerating a Variant Array

Tipically when you need iterate over a Variant Array you must get the bounds of the array using the VarArrayLowBound and VarArrayHighBound functions and from there you can access every item in the array only using the [] notation.

    for i := VarArrayLowBound(AvarArray, 1) to VarArrayHighBound(AvarArray, 1) do
     Item:=AvarArray[i];

Now using the same base interfaces you can implement a class to get a enumerator for this kind of arrays.

  TOleVariantArrayEnum = class(TInterfacedObject, IOleVariantEnum, IGetOleVariantEnum)
  private
    FCollection : OLEVariant;
    FIndex      : Integer;
    FLowBound   : Integer;
    FHighBound  : Integer;
  public
    function GetEnumerator: IOleVariantEnum;
    constructor Create(Collection: OLEVariant);
    function  GetCurrent: OLEVariant;
    function  MoveNext: Boolean;
    property  Current: OLEVariant read GetCurrent;
  end;

and the implementation

constructor TOleVariantArrayEnum.Create(Collection: OLEVariant);
begin
  inherited Create;
  FCollection:=Collection;
  FLowBound :=VarArrayLowBound(FCollection, 1);
  FHighBound:=VarArrayHighBound(FCollection, 1);
  FIndex:=FLowBound-1;
end;

function TOleVariantArrayEnum.GetCurrent: OLEVariant;
begin
  Result:=FCollection[FIndex];
end;

function TOleVariantArrayEnum.GetEnumerator: IOleVariantEnum;
begin
  Result:=Self;
end;

function TOleVariantArrayEnum.MoveNext: Boolean;
begin
  Result := FIndex < FHighBound;
  if Result then
    Inc(FIndex);
end;

and the helper function

function GetOleVariantArrEnum(Collection:OleVariant):IGetOleVariantEnum;
begin
 Result := TOleVariantArrayEnum.Create(Collection);
end;

And now you can iterate over the array using a for..in loop

  for Item in GetOleVariantArrEnum(AvarArray) do       

you can get the full source code of these classes and interfaces here.


3 Comments

WMI Tasks using Delphi – Operating Systems

How do I determine if a service pack has been installed on a computer?

Use the Win32_OperatingSystem class and check the value of the ServicePackMajorVersion and ServicePackMinorVersion properties.

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 ServicePackMajorVersion,ServicePackMinorVersion FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('ServicePack  %d.%d',[Integer(FWbemObject.ServicePackMajorVersion),Integer(FWbemObject.ServicePackMinorVersion)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine when the operating system was installed on a computer?

Use the Win32_OperatingSystem class and the InstallDate property.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  FWbemDateObj  : OleVariant;
  Dt            : TDateTime;
begin;
  FWbemDateObj  := CreateOleObject('WbemScripting.SWbemDateTime');
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT InstallDate FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemDateObj.Value:=FWbemObject.InstallDate;
    Dt:=FWbemDateObj.GetVarDate;
    Writeln(Format('InstallDate %s',[FormatDateTime('dd mmm yyyy',dt)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine which version of the Windows operating system is installed on a computer?

Use the Win32_OperatingSystem class, and retrieve both the Name and Version properties.

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 Name, Version FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('%s %s',[String(FWbemObject.Name),String(FWbemObject.Version)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine which folder is the Windows folder (%Windir%) on a computer?

Use the Win32_OperatingSystem class, and check the value of the WindowsDirectory property.

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 WindowsDirectory  FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Windows Path %s',[String(FWbemObject.WindowsDirectory)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine what hotfixes have been installed on a computer?

Use the Win32_QuickFixEngineering class. for more samples about this topic check this article search for installed windows updates using Delphi, WMI and WUA

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 Description,HotFixID  FROM Win32_QuickFixEngineering','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('HotFix %s',[String(FWbemObject.HotFixID)]));
    Writeln(Format('Description %s',[String(FWbemObject.Description)]));
    FWbemObject:=Unassigned;
  end;
end;

This entry is based in the MSDN article WMI Tasks: Operating Systems


15 Comments

WMI Tasks using Delphi – Networking

How do I disable a network connection using WMI?

If you are using DHCP, use the Win32_NetworkAdapterConfiguration and the ReleaseDHCPLease method to release the IP address. If you are not using DHCP, you cannot use WMI to disable a network connection. To re-enable the network connection, use objNetCard.RenewDHCPLease. You can also release or renew all of the DHCP leases using the ReleaseDHCPLeaseAll and RenewDHCPLeaseAll methods.

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_NetworkAdapterConfiguration Where IPEnabled = True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.ReleaseDHCPLease();
    FWbemObject:=Unassigned;
  end;
end;

How do I disable or enable a NIC?

Use the Win32_NetworkAdapter class and the Disable or Enable methods.

//Disable a NIC
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_NetworkAdapter Where NetEnabled=True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.Disable();
    FWbemObject:=Unassigned;
  end;
end;
//Enable a NIC
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_NetworkAdapter Where NetEnabled=False','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.Enable();
    FWbemObject:=Unassigned;
  end;
end;

How do I determine which IP address has been assigned to a given network connection?

Use the Win32_NetworkAdapter class and the NetConnectionID property to determine the MAC address of the network connection. Then, use the Win32_NetworkAdapterConfiguration class to find the IP address associated with the MAC address.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  strMACAddress : string;
  i             : Integer;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');

  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT MACAddress FROM Win32_NetworkAdapter Where NetConnectionID="%s"',['Local Area Connection 2']),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    strMACAddress:=String(FWbemObject.MACAddress);
    FWbemObject:=Unassigned;
  end;

  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT IPAddress FROM Win32_NetworkAdapterConfiguration Where MACAddress="%s"',[strMACAddress]),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    if not VarIsClear(FWbemObject.IPAddress) then
    for i := VarArrayLowBound(FWbemObject.IPAddress, 1) to VarArrayHighBound(FWbemObject.IPAddress, 1) do
     Writeln(Format('IP Address %s',[String(FWbemObject.IPAddress[i])]));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the MAC address of a network adapter?

Use the Win32_NetworkAdapterConfiguration class and check the value of the MACAddress property.

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 Description,MACAddress FROM Win32_NetworkAdapterConfiguration','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Description %s',[String(FWbemObject.Description)]));
    if not VarIsNull(FWbemObject.MACAddress) then
      Writeln(Format('  MAC Address %s',[String(FWbemObject.MACAddress)]))
    else
      Writeln(Format('  MAC Address %s',['Empty']));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the IP address(es) of a computer?

Use the Win32_NetworkAdapterConfiguration class and check the value of the IPAddress property.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  i             : Integer;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT IPAddress FROM Win32_NetworkAdapterConfiguration','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    if not VarIsClear(FWbemObject.IPAddress) and not VarIsNull(FWbemObject.IPAddress) then
    for i := VarArrayLowBound(FWbemObject.IPAddress, 1) to VarArrayHighBound(FWbemObject.IPAddress, 1) do
     Writeln(Format('IP Address %s',[String(FWbemObject.IPAddress[i])]));
    FWbemObject:=Unassigned;
  end;
end;

How do I configure a computer to start getting its IP address through DHCP?

Use the Win32_NetworkAdapterConfiguration class and the EnableDHCP method.

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_NetworkAdapterConfiguration Where IPEnabled=True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    FWbemObject.EnableDHCP();
    FWbemObject:=Unassigned;
  end;
end;

How do I assign a computer a static IP address?

Use the Win32_NetworkAdapterConfiguration class and the EnableStatic method.

function ArrayToVarArray(Arr : Array Of string):OleVariant; overload;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Word):OleVariant;overload;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

procedure  SetStaticIP;
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  vIPAddress         : OleVariant;
  vSubnetMask        : OleVariant;
  vDefaultIPGateway  : OleVariant;
  vGatewayCostMetric : OleVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_NetworkAdapterConfiguration Where IPEnabled=True','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    vIPAddress   := ArrayToVarArray(['192.168.1.141']);
    vSubnetMask  := ArrayToVarArray(['255.255.255.0']);
    if FWbemObject.EnableStatic(vIPAddress, vSubnetMask) = 0 then
    begin
      vDefaultIPGateway  := ArrayToVarArray(['192.168.1.100']);
      vGatewayCostMetric := ArrayToVarArray([1]);
      FWbemObject.SetGateways(vDefaultIPGateway,vGatewayCostMetric);
    end;

    VarClear(vIPAddress);
    VarClear(vSubnetMask);
    VarClear(vDefaultIPGateway);
    VarClear(vGatewayCostMetric);
    FWbemObject:=Unassigned;
  end;
end;

How do I ping a computer without using Ping.exe?

Use the Win32_PingStatus class. Starting with Windows Vista, Win32_PingStatus can return data for computers that have both IPv4 addresses and IPv6 addresses.

For a delphi sample code check this article Making a PING with Delphi and the WMI.

This post is based in the MSDN entry WMI Tasks: Networking


4 Comments

WMI Tasks using Delphi – Files and Folders

How do I rename a local or remote file?

Use the CIM_DataFile class. Ensure that you pass the entire path name when calling the Rename method, for example, “C:\Foo\Test.txt” instead of “Text.txt”.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  FileName      : string;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FileName      := 'C:\\Foo\\Test.txt';//look how the name of the file to rename is escaped
  FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_DataFile Where Name="%s"',[FileName]),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemObject.Rename('C:\Foo\Test_new.txt');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine whether users have .MP3 files stored on their computer?

Use the CIM_DataFile class and select files using the following WQL WHERE clause: Where Extension = “MP3”.

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(Format('SELECT Name,Extension,Path FROM CIM_DataFile Where Extension="%s"',['mp3']),'WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('File Name %s.%s',[String(FWbemObject.Name),String(FWbemObject.Extension)]));
    Writeln(Format('Path      %s',[String(FWbemObject.Path)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I create shared folders on a computer?

Use the Win32_Share class and the Create method.

const
  FILE_SHARE          = 0;
  MAXIMUM_CONNECTIONS = 25;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObject   : OLEVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObject   := FWMIService.Get('Win32_Share');
  FWbemObject.Create('C:\Finance', 'FinanceShare', FILE_SHARE, MAXIMUM_CONNECTIONS, 'Public share for the Finance group.');
end;

For more samples of using the WMI and Delphi to handle files and folders in local and remote machines check this article Manipulating local/remote files and folders using Delphi and WMI

This post is based in the MSDN entry WMI Tasks: Files and Folders


11 Comments

WMI Tasks using Delphi – Event Logs

How do I retrieve information about the Security event log?

Use the Win32_NTEventlogFile class.

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 MaxFileSize ,NumberOfRecords FROM Win32_NTEventlogFile Where LogFileName="Security"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Max File Size        %d',[Integer(FWbemObject.MaxFileSize)]));
    Writeln(Format('Number Of Records    %d',[Integer(FWbemObject.NumberOfRecords)]));
    Writeln;
    FWbemObject:=Unassigned;
  end;
end;

How do I back up an event log?

Use the Win32_NTEventlogFile class and the BackupEventLog method

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_NTEventlogFile Where LogFileName="Application"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemObject.BackupEventLog('c:\logs\backup.evt');
    FWbemObject:=Unassigned;
  end;
end;

How do I back up an event log more than once?

Ensure that the backup file has a unique name before using the Win32_NTEventlogFile and the BackupEventLog method. The operating system does not allow you to overwrite an existing backup file; you must either move the backup file or rename it before you can run the script again.

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_NTEventlogFile Where LogFileName="Application"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemObject.BackupEventLog(Format('c:\logs\backup_%s.evt',[FormatDateTime('hhnnsszzz',Now)]));
    FWbemObject.ClearEventLog();
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the number of records in an event log?

Use the Win32_NTEventlogFile class and check the value of the NumberOfRecords property.

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 NumberOfRecords FROM Win32_NTEventlogFile Where LogFileName="Security"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Number Of Records    %d',[Integer(FWbemObject.NumberOfRecords)]));
    Writeln;
    FWbemObject:=Unassigned;
  end;
end;

How do I clear my event logs?

Use the Win32_NTEventlogFile class and the ClearEventLog method.

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_NTEventlogFile Where LogFileName="Application"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemObject.ClearEventLog();
    FWbemObject:=Unassigned;
  end;
end;

How do I read events from the event logs?

Use the Win32_NTLogEvent class.

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_NTLogEvent  Where Logfile="System"','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Category          %s',[String(FWbemObject.Category)]));
    Writeln(Format('Computer Name     %s',[String(FWbemObject.ComputerName)]));
    Writeln(Format('EventCode         %d',[Integer(FWbemObject.EventCode)]));
    Writeln(Format('Message           %s',[String(FWbemObject.Message)]));
    Writeln(Format('RecordNumber      %d',[Integer(FWbemObject.RecordNumber)]));
    FWbemObject:=Unassigned;
  end;
end;

This post is based in the MSDN entry WMI Tasks: Event Logs


10 Comments

WMI Tasks using Delphi – Disks and File Systems

How do I find out how much disk space each user is currently using on a computer?

If you are using disk quotas, then use the Win32_DiskQuota class and retrieve the values of the User and DiskSpaceUsed properties.

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_DiskQuota','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Disk Space Used    %d',[Integer(FWbemObject.DiskSpaceUsed)]));
    Writeln(Format('Quota Volume       %s',[String(FWbemObject.QuotaVolume)]));
    Writeln(Format('User               %s',[String(FWbemObject.User)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine when a removable drive has been added to or removed from a computer?

Use a monitoring code that queries the Win32_VolumeChangeEvent class.

    function EventTypeStr(EventType:Integer):string;
    begin
       case EventType of
        1 : Result:='Configuration Changed';
        2 : Result:='Device Arrival';
        3 : Result:='Device Removal';
        4 : Result:='Docking';
       end;
    end;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
begin;
  Writeln('Press Ctrl-C to terminate');
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecNotificationQuery('SELECT * FROM Win32_VolumeChangeEvent');
  while true do
  begin
    FWbemObject := FWbemObjectSet.NextEvent;
    if not VarIsClear(FWbemObject) then
    begin
      Writeln(Format('Drive Name   %s',[String(FWbemObject.DriveName)]));
      Writeln(Format('Event Type   %s',[EventTypeStr(FWbemObject.EventType)]));
    end;
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine if a CD is in a CD-ROM drive?

Use the Win32_CDROMDrive class and the MediaLoaded property.

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_CDROMDrive','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Device ID    %s',[String(FWbemObject.DeviceID)]));
    Writeln(Format('Media Loaded %s',[String(FWbemObject.MediaLoaded)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I distinguish between a fixed hard disk and a removable hard disk?

Use the Win32_LogicalDisk class and check the value of the DriveType property.

Value Meaning
0
Unknown
1
No Root Directory
2
Removable Disk
3
Local Disk
4
Network Drive
5
Compact Disc
6
RAM Disk
  function DriveTypeStr(DriveType:integer): string;
  begin
    case DriveType of
      0 : Result:='Unknown';
      1 : Result:='No Root Directory';
      2 : Result:='Removable Disk';
      3 : Result:='Local Disk';
      4 : Result:='Network Drive';
      5 : Result:='CD/DVD Disc';
      6 : Result:='RAM Disk';
    end;
  end;

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_LogicalDisk','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Device ID    %s',[String(FWbemObject.DeviceID)]));
    Writeln(Format('DriveType    %s',[DriveTypeStr(FWbemObject.DriveType)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine what file system is in use on a drive?

Use the Win32_LogicalDisk class and the FileSystem property.

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_LogicalDisk','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Device ID    %s',[String(FWbemObject.DeviceID)]));
    if not VarIsNull(FWbemObject.FileSystem) then
      Writeln(Format('File System  %s',[String(FWbemObject.FileSystem)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine how much free space is available on a drive?

Use the Win32_LogicalDisk class and the FreeSpace property.

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_LogicalDisk','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Device ID   %s',[String(FWbemObject.DeviceID)]));
    if not VarIsNull(FWbemObject.FreeSpace) then
      Writeln(Format('Free Space  %d',[Int64(FWbemObject.FreeSpace)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the size of a drive?

Use the Win32_LogicalDisk class, and the Size property.

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_LogicalDisk','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Device ID   %s',[String(FWbemObject.DeviceID)]));
    if not VarIsNull(FWbemObject.Size) then
      Writeln(Format('Disk Size   %d',[Int64(FWbemObject.Size)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I find out what drives are mapped on a computer?

Use the Win32_MappedLogicalDisk class.

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_MappedLogicalDisk','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Device ID   %s',[String(FWbemObject.DeviceID)]));
    Writeln(Format('Name        %s',[String(FWbemObject.Name)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I defragment a hard disk?

Use the Win32_Volume class and the Defrag method.

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_Volume Where Name = "F:\\" ','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemObject.Defrag();
    FWbemObject:=Unassigned;
  end;
end;

How do I detect which drive letter is associated with a logical disk partition?

 

  1. Start with the Win32_DiskDrive class and query for instances of Win32_DiskPartition using the DeviceID property and the Win32_DiskDriveToDiskPartition association class. Now you have a collection of the partitions on the physical drive.
  2. Query for the Win32_LogicalDisk that represents the partition using the Win32_DiskPartition.DeviceID property and Win32_LogicalDiskToPartition association class.
  3. Get the drive letter from the Win32_LogicalDisk.DeviceID.

 

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator     : OLEVariant;
  FWMIService       : OLEVariant;
  wmiDiskDrives     : OLEVariant;
  wmiDiskPartitions : OLEVariant;
  wmiLogicalDisks   : OLEVariant;
  wmiDiskDrive      : OLEVariant;
  wmiDiskPartition  : OLEVariant;
  wmiLogicalDisk    : OLEVariant;
  oEnum             : IEnumvariant;
  oEnum2            : IEnumvariant;
  oEnum3            : IEnumvariant;
  iValue            : LongWord;
  DeviceID          : string;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  //Get the physical disk drive
  wmiDiskDrives := FWMIService.ExecQuery('SELECT Caption, DeviceID FROM Win32_DiskDrive','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(wmiDiskDrives._NewEnum) as IEnumVariant;
  while oEnum.Next(1, wmiDiskDrive, iValue) = 0 do
  begin
     //Use the disk drive device id to find associated partition
     DeviceID:=StringReplace(String(wmiDiskDrive.DeviceID),'\','\\',[rfReplaceAll]);
     wmiDiskPartitions := FWMIService.ExecQuery('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="'+DeviceID+'"} WHERE AssocClass = Win32_DiskDriveToDiskPartition','WQL',wbemFlagForwardOnly);
     oEnum2          := IUnknown(wmiDiskPartitions._NewEnum) as IEnumVariant;
     while oEnum2.Next(1, wmiDiskPartition, iValue) = 0 do
     begin
        wmiLogicalDisks := FWMIService.ExecQuery('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="'+String(wmiDiskPartition.DeviceID)+'"} WHERE AssocClass = Win32_LogicalDiskToPartition','WQL',wbemFlagForwardOnly);
        oEnum3          := IUnknown(wmiLogicalDisks._NewEnum) as IEnumVariant;
        while oEnum3.Next(1, wmiLogicalDisk, iValue) = 0 do
        begin
          Writeln(Format('Drive letter associated with disk drive  %s %s Partition %s is %s',[String(wmiDiskDrive.Caption),String(wmiDiskDrive.DeviceID),String(wmiDiskPartition.DeviceID),String(wmiLogicalDisk.DeviceID)]));
          wmiLogicalDisk:=Unassigned;
        end;
       wmiDiskPartition:=Unassigned;
     end;
    wmiDiskDrive:=Unassigned;
    Writeln;
  end;
end;

This post is based in the MSDN entry WMI Tasks: Disks and File Systems


Leave a comment

WMI Tasks using Delphi – Desktop Management

How do I determine if a remote computer has booted up in the Safe Mode with Networking state?

Use the Win32_ComputerSystem class and check the value of the BootupState property.

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 BootupState FROM Win32_ComputerSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('BootupState    %s',[String(FWbemObject.BootupState)]));// String
    FWbemObject:=Unassigned;
  end;
end;

How do I determine if a computer screensaver requires a password?

Use the Win32_Desktop class and check the value of the ScreenSaverSecure property.

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 ScreenSaverSecure FROM Win32_Desktop','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    if not VarIsNull(FWbemObject.ScreenSaverSecure) then
      Writeln(Format('ScreenSaverSecure  %s',[String(FWbemObject.ScreenSaverSecure)]));// Boolean
    FWbemObject:=Unassigned;
  end;
end;

How do I get the screen resolution of a remote computer?

Use the Win32_DesktopMonitor class and check the values of the properties ScreenHeight and ScreenWidth.

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 ScreenHeight,ScreenWidth FROM Win32_DesktopMonitor','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Resolution  %d x %d',[Integer(FWbemObject.ScreenWidth),Integer(FWbemObject.ScreenHeight)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I determine how long a computer has been running?

Use the Win32_OperatingSystem class and the LastBootUpTime property. Subtract that value from the current time to get the system uptime.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  FWbemDateObj  : OleVariant;
  Dt            : TDateTime;
begin;
  FWbemDateObj  := CreateOleObject('WbemScripting.SWbemDateTime');
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT LastBootUpTime FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemDateObj.Value:=FWbemObject.LastBootUpTime;
    Dt:=Now-FWbemDateObj.GetVarDate;
    Writeln(Format('UpTime %s',[FormatDateTime('hh:nn:ss',dt)]));
    FWbemObject:=Unassigned;
  end;
end;

How do I reboot or shut down a remote computer?

Use the Win32_OperatingSystem class and the Win32Shutdown method. You must include the RemoteShutdown privilege when connecting to WMI. For more information, see Executing Privileged Operations Using C++ and Executing Privileged Operations Using VBScript. Unlike the Shutdown method on Win32_OperatingSystem, the Win32Shutdown method allows you to set flags to control the shutdown behavior.-

function GetObject(const objectName: String): IDispatch;
var
  chEaten: Integer;
  BindCtx: IBindCtx;//for access to a bind context
  Moniker: IMoniker;//Enables you to use a moniker object
begin
  OleCheck(CreateBindCtx(0, bindCtx));
  OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));//Converts a string into a moniker that identifies the object named by the string
  OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));//Binds to the specified object
end;

procedure  Shutdown;
const
  wbemFlagForwardOnly = $00000020;
var
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FWMIService    := GetObject('winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\localhost\root\cimv2');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
     FWbemObject.Win32Shutdown(1);
end;

How do I determine what applications automatically run each time I start Windows?

Use the Win32_StartupCommand class.

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_StartupCommand','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Command     %s',[String(FWbemObject.Command)]));
    Writeln(Format('Description %s',[String(FWbemObject.Description)]));
    Writeln(Format('Location    %s',[String(FWbemObject.Location)]));
    Writeln(Format('Name        %s',[String(FWbemObject.Name)]));
    Writeln(Format('User        %s',[String(FWbemObject.User)]));
    if not VarIsNull(FWbemObject.SettingID) then
      Writeln(Format('SettingID   %s',[String(FWbemObject.SettingID)]));
    FWbemObject:=Unassigned;
  end;
end;

This post is based in the MSDN entry WMI Tasks: Desktop Management


Leave a comment

WMI Tasks using Delphi – Dates and Times

How do I convert WMI dates to standard dates and times?

Use the SWbemDateTime object to convert these to regular dates and times.

const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
  FWbemDateObj  : OleVariant;
  Dt            : TDateTime;
begin;
  FWbemDateObj  := CreateOleObject('WbemScripting.SWbemDateTime');

  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT InstallDate FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    FWbemDateObj.Value:=FWbemObject.InstallDate;
    Dt:=FWbemDateObj.GetVarDate;
    Writeln(Format('InstallDate %s',[FormatDateTime('dd mmm yyyy',dt)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the time currently configured on a computer?

Use the Win32_LocalTime class.

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_LocalTime','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Year          : %d',[Integer(FWbemObject.Year)]));
    Writeln(Format('Month         : %d',[Integer(FWbemObject.Month)]));
    Writeln(Format('Day           : %d',[Integer(FWbemObject.Day)]));
    Writeln(Format('Hour          : %d',[Integer(FWbemObject.Hour)]));
    Writeln(Format('Minute        : %d',[Integer(FWbemObject.Minute)]));
    Writeln(Format('Second        : %d',[Integer(FWbemObject.Second)]));

    Writeln(Format('Day Of Week   : %d',[Integer(FWbemObject.DayOfWeek)]));
    Writeln(Format('Quarter       : %d',[Integer(FWbemObject.Quarter)]));
    Writeln(Format('Week In Month : %d',[Integer(FWbemObject.WeekInMonth )]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

How do I determine the name of the time zone in which a computer is running?

Use the Win32_TimeZone class and check the value of the Description property.

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_TimeZone','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    Writeln(Format('Description   : %s',[String(FWbemObject.Description)]));
    Writeln(Format('Daylight Name : %s',[String(FWbemObject.DaylightName)]));
    Writeln(Format('Standard Name : %s',[String(FWbemObject.StandardName)]));
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

This post is based in the MSDN entry WMI Tasks: Dates and Times