Some days ago a question in stackoverflow.com was made, about how list the contents of a folder of a remote machine. I answer that question using a WMI approach mentioning the CIM_DataFile and CIM_Directory WMI Classes, these classes can be used to retrieve information about files, folders and perform many task like copy, rename, delete and compress. So today I will show you how you can use these classes form Delphi.
First you must know which in order to access any file or folder in a remote machine need not be a shared resource, only just must enable the WMI remote access in the machine to access, check these articles for more details about how enable the remote wmi access.
- Connecting to WMI on a Remote Computer
- Connecting Between Different Operating Systems
- Connecting Through Windows Firewall
After of enabling the WMI remote access in the client machine you are ready to access the files and folders.
Before to begin
Now some tips which can help you to deal both classes
- When you make a WMI query against these classes always you must use filters (Where conditions) to restrict the result of these WMI classes.
- Always you must use the
Drivefield as condition, due to two reasons, first these classes will scan all directories on any available storage device. So this task can take some time. and second to diffentiate for example a folder called Windows located in the Drive C: and in the Drive D:. - The Wmi interprets the
\(Backslash) character as a reserved symbol so you need to escape that character to avoid problems with the WQL sentence. - You can use these classes to find files or folders which match with a criteria, but remember if you not specify the Path property the WMI will scan the entire drive. so try to avoid sentences like
FWMIService.ExecQuery(Format('SELECT * FROM CIM_DataFile Where Drive="%s" AND Extension="%s"',['C:','jpg']),'WQL',wbemFlagForwardOnly);//this will return all the jpg files in the C Drive
Note :
The code showed in this article uses Late binding to access the WMI, if you want use another way to access the WMI from delphi (like direct COM access or importing th e Microsoft scripting library) take a look to the Delphi WMI Code creator.
Listing Folder and Files
//list the files and folders of a specified Path (non recursive)
procedure ListFolderContent(Const WbemComputer,WbemUser,WbemPassword,Path:string);
const
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
WmiPath : string;
Drive : string;
begin;
//Extract the drive from the Path
Drive :=ExtractFileDrive(Path);
//add a back slash to the end of the folder
WmiPath :=IncludeTrailingPathDelimiter(Copy(Path,3,Length(Path)));
//escape the folder name
WmiPath :=StringReplace(WmiPath,'\','\\',[rfReplaceAll]);
Writeln('Connecting');
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
//establish the connection
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
Writeln('Files');
//get the files
FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_DataFile Where Drive="%s" AND Path="%s"',[Drive,WmiPath]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
Writeln(Format('%s',[FWbemObject.Name]));// String
FWbemObject:=Unassigned;
end;
Writeln('Folders');
//get the folders
FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM CIM_Directory Where Drive="%s" AND Path="%s"',[Drive,WmiPath]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
Writeln(Format('%s',[FWbemObject.Name]));// String
FWbemObject:=Unassigned;
end;
end;
How to use
begin
try
CoInitialize(nil);
try
//ListFolderContent('.','','','C:\data'); //get the content of the folder Data in he local machine
ListFolderContent('remotemachine','user_name','password','C:\Data');
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
Get info about a particular file or folder
This code will list the type, size, creation date, attributes, etc. of any file which you pass as parameter
procedure GetCIM_DataFileInfo(const FileName:string);
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(FileName,'\','\\',[rfReplaceAll])]));
Writeln(Format('AccessMask %s',[FWbemObject.AccessMask]));// Uint32
Writeln(Format('Archive %s',[FWbemObject.Archive]));// Boolean
Writeln(Format('Caption %s',[FWbemObject.Caption]));// String
Writeln(Format('Compressed %s',[FWbemObject.Compressed]));// Boolean
Writeln(Format('CompressionMethod %s',[FWbemObject.CompressionMethod]));// String
Writeln(Format('CreationClassName %s',[FWbemObject.CreationClassName]));// String
Writeln(Format('CreationDate %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.CreationDate))]));// Datetime
Writeln(Format('CSCreationClassName %s',[FWbemObject.CSCreationClassName]));// String
Writeln(Format('CSName %s',[FWbemObject.CSName]));// String
Writeln(Format('Description %s',[FWbemObject.Description]));// String
Writeln(Format('Drive %s',[FWbemObject.Drive]));// String
Writeln(Format('EightDotThreeFileName %s',[FWbemObject.EightDotThreeFileName]));// String
Writeln(Format('Encrypted %s',[FWbemObject.Encrypted]));// Boolean
Writeln(Format('EncryptionMethod %s',[FWbemObject.EncryptionMethod]));// String
Writeln(Format('Extension %s',[FWbemObject.Extension]));// String
Writeln(Format('FileName %s',[FWbemObject.FileName]));// String
Writeln(Format('FileSize %s',[FWbemObject.FileSize]));// Uint64
Writeln(Format('FileType %s',[FWbemObject.FileType]));// String
Writeln(Format('FSCreationClassName %s',[FWbemObject.FSCreationClassName]));// String
Writeln(Format('FSName %s',[FWbemObject.FSName]));// String
Writeln(Format('Hidden %s',[FWbemObject.Hidden]));// Boolean
Writeln(Format('InstallDate %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.InstallDate))]));// Datetime
Writeln(Format('InUseCount %s',[FWbemObject.InUseCount]));// Uint64
Writeln(Format('LastAccessed %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.LastAccessed))]));// Datetime
Writeln(Format('LastModified %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.LastModified))]));// Datetime
Writeln(Format('Manufacturer %s',[FWbemObject.Manufacturer]));// String
Writeln(Format('Name %s',[FWbemObject.Name]));// String
Writeln(Format('Path %s',[FWbemObject.Path]));// String
Writeln(Format('Readable %s',[FWbemObject.Readable]));// Boolean
Writeln(Format('Status %s',[FWbemObject.Status]));// String
Writeln(Format('System %s',[FWbemObject.System]));// Boolean
Writeln(Format('Version %s',[FWbemObject.Version]));// String
Writeln(Format('Writeable %s',[FWbemObject.Writeable]));// Boolean
Writeln('');
end;
In the above code you note two things, first I’m using the SWbemServices.Get method instead SWbemServices.ExecQuery this is because the Get function retrieve a single instance of the wmi object path passed as parameter (the wmi object path is a string that uniquely identifies a instances of a class). The second
which you must note is the WbemTimeToDateTime function, this is a helper function to convert the returned WMI datetime values in UTC format to TDateTime.
This is the code of that function, for more info check the documentation about the WbemScripting.SWbemDateTime object.
function WbemTimeToDateTime(const V : OleVariant): TDateTime;
var
Dt : OleVariant;
begin
Result:=0;
if VarIsNull(V) then exit;
Dt:=CreateOleObject('WbemScripting.SWbemDateTime');
Dt.Value := V;
Result:=Dt.GetVarDate;
end;
This code will list the size, creation date, atributes, etc. of any folder which you pass as parameter
procedure GetCIM_DirectoryInfo(const FolderName:string);
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(FolderName,'\','\\',[rfReplaceAll])]));
Writeln(Format('AccessMask %s',[FWbemObject.AccessMask]));// Uint32
Writeln(Format('Archive %s',[FWbemObject.Archive]));// Boolean
Writeln(Format('Caption %s',[FWbemObject.Caption]));// String
Writeln(Format('Compressed %s',[FWbemObject.Compressed]));// Boolean
Writeln(Format('CompressionMethod %s',[FWbemObject.CompressionMethod]));// String
Writeln(Format('CreationClassName %s',[FWbemObject.CreationClassName]));// String
Writeln(Format('CreationDate %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.CreationDate))]));// Datetime
Writeln(Format('CSCreationClassName %s',[FWbemObject.CSCreationClassName]));// String
Writeln(Format('CSName %s',[FWbemObject.CSName]));// String
Writeln(Format('Description %s',[FWbemObject.Description]));// String
Writeln(Format('Drive %s',[FWbemObject.Drive]));// String
Writeln(Format('EightDotThreeFileName %s',[FWbemObject.EightDotThreeFileName]));// String
Writeln(Format('Encrypted %s',[FWbemObject.Encrypted]));// Boolean
Writeln(Format('EncryptionMethod %s',[FWbemObject.EncryptionMethod]));// String
Writeln(Format('Extension %s',[FWbemObject.Extension]));// String
Writeln(Format('FileName %s',[FWbemObject.FileName]));// String
Writeln(Format('FileSize %s',[FWbemObject.FileSize]));// Uint64
Writeln(Format('FileType %s',[FWbemObject.FileType]));// String
Writeln(Format('FSCreationClassName %s',[FWbemObject.FSCreationClassName]));// String
Writeln(Format('FSName %s',[FWbemObject.FSName]));// String
Writeln(Format('Hidden %s',[FWbemObject.Hidden]));// Boolean
Writeln(Format('InstallDate %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.InstallDate))]));// Datetime
Writeln(Format('InUseCount %s',[FWbemObject.InUseCount]));// Uint64
Writeln(Format('LastAccessed %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.LastAccessed))]));// Datetime
Writeln(Format('LastModified %s',[FormatDateTime('dd/mm/yyyy hh:nn:ss',WbemTimeToDateTime(FWbemObject.LastModified))]));// Datetime
Writeln(Format('Name %s',[FWbemObject.Name]));// String
Writeln(Format('Path %s',[FWbemObject.Path]));// String
Writeln(Format('Readable %s',[FWbemObject.Readable]));// Boolean
Writeln(Format('Status %s',[FWbemObject.Status]));// String
Writeln(Format('System %s',[FWbemObject.System]));// Boolean
Writeln(Format('Writeable %s',[FWbemObject.Writeable]));// Boolean
Writeln('');
end;
Compress a File or Folder using the NTFS compression
function CompressFile(const FileName:string):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(FileName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.Compress();
end;
function CompressFolder(const FolderName:string;Recursive:Boolean):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
StopFileName : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(FolderName,'\','\\',[rfReplaceAll])]));
if Recursive then
Result:=FWbemObject.CompressEx(StopFileName, Null, Recursive)
else
Result:=FWbemObject.Compress();
end;
UnCompress a File or Folder using the NTFS compression
function UnCompressFile(const FileName:string):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(FileName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.UnCompress();
end;
function UnCompressFolder(const FolderName:string;Recursive:Boolean):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
StopFileName : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(FolderName,'\','\\',[rfReplaceAll])]));
if Recursive then
Result:=FWbemObject.UnCompressEx(StopFileName, Variants.Null, Recursive)
else
Result:=FWbemObject.UnCompress();
end;
Copy a single File or Folder
function CopyFile(const SourceFileName,DestFileName:string):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(SourceFileName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.Copy(DestFileName);
end;
function CopyFolder(const SourceFolder,DestFolder:string;Recursive:Boolean):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
StopFileName : OleVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(SourceFolder,'\','\\',[rfReplaceAll])]));
if Recursive then
Result:=FWbemObject.CopyEx(DestFolder,StopFileName, Variants.Null, Recursive)
else
Result:=FWbemObject.Copy(DestFolder);
end;
Delete a File or Folder
function DeleteFile(const FileName:string):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(FileName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.Delete();
end;
//remove all the contents of the folder recursivily
function DeleteFolder(const FolderName:string):integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(FolderName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.Delete();
end;
Rename a File or Folder
function RenameFile(const OldName, NewName: string): Integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(OldName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.Rename(NewName);
end;
function RenameFolder(const OldName, NewName: string): Integer;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_Directory.Name="%s"',[StringReplace(OldName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.Rename(NewName);
end;
Getting the permissions over a CIM_DataFile or CIM_Directory object
In order to get whether the caller has the permissions on the CIM_DataFile or CIM_Directory object you must use the GetEffectivePermission function with these flags
| Value (Dec/Hex) | Meaning |
|---|---|
|
Grants the right to read data from the file. For a directory, this value grants the right to list the contents of the directory. |
|
Grants the right to write data to the file. For a directory, this value grants the right to create a file in the directory. |
|
Grants the right to append data to the file. For a directory, this value grants the right to create a subdirectory. |
|
Grants the right to read extended attributes. |
|
Grants the right to write extended attributes. |
|
Grants the right to execute a file. For a directory, the directory can be traversed. |
|
Grants the right to delete a directory and all the files it contains, even if the files are read-only. |
|
Grants the right to read file attributes. |
|
Grants the right to change file attributes. |
|
Grants delete access. |
|
Grants read access to the security descriptor and owner. |
|
Grants write access to the discretionary ACL. |
|
Assigns the write owner. |
|
Synchronizes access and allows a process to wait for an object to enter the signaled state. |
function GetEffectivePermission(const FileName:string;Flags:integer):Boolean;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObject : OLEVariant;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('CIM_DataFile.Name="%s"',[StringReplace(FileName,'\','\\',[rfReplaceAll])]));
Result:=FWbemObject.GetEffectivePermission(Flags);
end;
And use like this
GetEffectivePermission('C:\FooFolder\Foo_Filename.ext',FILE_READ_DATA or FILE_READ_ATTRIBUTES);
Getting the Status of a task
The functions Compress, UnCompress, Copy, Rename and Delete return a Result code which can be translated to a message using this function
function GetResultMessage(ResultCode:Integer) : string;
begin
case ResultCode of
0 : Result:='Success';
2 : Result:='Access denied';
8 : Result:='Unspecified failure';
9 : Result:='Invalid object';
10 : Result:='Object already exists';
11 : Result:='File system not NTFS';
12 : Result:='Platform not Windows NT or Windows 2000';
13 : Result:='Drive not the same';
14 : Result:='Directory not empty';
15 : Result:='Sharing violation';
16 : Result:='Invalid start file';
17 : Result:='Privilege not held';
21 : Result:='Invalid parameter'
else
Result := 'Unknown';
end;
end;
Demo Application
Check this demo application which can list all the files and folders in a remote or local machine only using the WMI
checkout the full source code on Github.






