[C# and WMI] : Programm run to slow

N

nico

Hello

I have write this program that retrieve all directory and subdirectory
recursively of a given directory given in parameter.
For each directory, the script find all user permission for the current
directory and add the username, permission and directory name into MySQL.


The code works fine, but too slow.

He need aproximate 1 hour to scan 200 directory.

How to optimize this code please ?

I know I can improve it but I code with C# just for some days.

1 * Time: 08:59
2 *
3 * To change this template use Tools | Options | Coding | Edit Standard
Headers.
4 */
5
6 using System;
7 using System.IO;
8 using System.Data;
9 using System.Data.SqlClient;
10 using System.Data.Common;
11 using System.Management;
12 using System.Collections;
13 using ByteFX;
14 using ByteFX.Data.MySqlClient;
15 using System.Diagnostics;
16 using System.ComponentModel;
17
18 namespace System.Management
19
20 {
21 class wmi_scan_dossier
22 {
23 private string _nom_pc;
24 private MySqlConnection _id_con_mysql;
25 private System.Management.ManagementScope _oMs;
26
27 private MySqlConnection id_con_mysql
28 {
29 get
30 {
31 return _id_con_mysql;
32 }
33 set
34 {
35 _id_con_mysql = value;
36 }
37 }
38
39 private System.Management.ManagementScope oMs
40 {
41 get
42 {
43 return _oMs;
44 }
45 set
46 {
47 oMs = value;
48 }
49 }
50
51 void connect_mysql()
52 {
53 string ConnectionString = ConnectionString = "Database=toto;Data
Source=localhost;User Id=root;Password=XXX";
54 MySqlConnection _id_con_mysql = new MySqlConnection(ConnectionString);
55 _id_con_mysql.Open();
56 this.id_con_mysql = _id_con_mysql;
57 }
58
59 void mysql_query(string sql)
60 {
61 //this.connect_mysql();
62 MySqlCommand query_ajoute_dossier = new MySqlCommand(sql,
this.id_con_mysql);
63 query_ajoute_dossier.ExecuteNonQuery();
64 }
65
66 void mysql_deconnect()
67 {
68 this.id_con_mysql.Close();
69 }
70
71 public string trouve_nom_pc()
72 {
73 ConnectionOptions oConn = new ConnectionOptions();
74 //oConn.Username = "stist"; // je specifie le login local (pas
obligatoire si le programme est executer sur la machine local
75 //oConn.Password = "stage2004"; // je specifie le mot de passe local (pas
obligatoire si le programme est executer sur la machine local
76
77 //System.Management.ManagementScope oMs = new
System.Management.ManagementScope("\\\\MachineX", oConn);
78 //System.Management.ManagementScope oMs = new
System.Management.ManagementScope("\\\\MachineX");
79
80 //j appel la liste des dossiers d un repertoire de base donnee
81 System.Management.ObjectQuery oQueryPc = new
System.Management.ObjectQuery("SELECT Name from Win32_ComputerSystem");
82
83 //j execute la requete
84 ManagementObjectSearcher oSearcherPc = new
ManagementObjectSearcher(this.connect_wmi(),oQueryPc);
85
86 //je recupere le nom de l ordinateur avec la methode Get
87 ManagementObjectCollection oReturnCollectionPc = oSearcherPc.Get();
88
89 foreach(ManagementObject oReturnPc in oReturnCollectionPc)
90 {
91 _nom_pc = oReturnPc["name"].ToString();
92 }
93 return _nom_pc;
94 }
95
96 public System.Management.ManagementScope connect_wmi()
97 {
98 // fonction retournant l identifiant de connexion a WMI
99 this._oMs = new System.Management.ManagementScope("\\\\MachineX");
100 return this.oMs;
101 }
102
103 public static void Main(string[] args)
104 {
105 string nom_rep_mysql, sql_ajoute_dossier, sql_ajoute_acces, sql_pc;
106
107 wmi_scan_dossier un_scan = new wmi_scan_dossier();
108
109 ArrayList verif_login = new ArrayList(); // je declare un liste de
tableau dynamique qui contiendra la liste des utilisateurs uniques ayant des
droits sur les répertoires traités pour éviter les doublons
110 bool etre_doublon = false;
111
112 //Connection credentials to the remote computer - not needed if the
logged in account has access
113 ConnectionOptions oConn = new ConnectionOptions();
114
115 //j appel la liste des dossiers d un repertoire de base donnee
116 System.Management.ObjectQuery oQueryPc = new
System.Management.ObjectQuery("SELECT Name from Win32_ComputerSystem");
117
118 //j execute la requete
119 ManagementObjectSearcher oSearcherPc = new
ManagementObjectSearcher(un_scan.connect_wmi(),oQueryPc);
120
121 //je recupere le nom de l ordinateur avec la methode Get
122 ManagementObjectCollection oReturnCollectionPc = oSearcherPc.Get();
123
124 int j = args.Length;
125
126 if(j == 0)
127 {
128 Console.WriteLine ("Saisissez un paramètre pour utiliser le logiciel");
129 Console.WriteLine ("Exemple de synthaxe : test_ok.exe \"c:\\Apache\"
\"C:\\Documents and Settings\"");
130 Console.WriteLine ("Cette appel aura pour effet de scanner l'ensemble
des sous dossiers des répertoires c:\\Apache ET C:\\Documents and
Settings");
131
132 }
133 else
134 {
135 Console.WriteLine ("Début du scan du dossier ... patience ");
136 for(int compteur = 0; compteur < j ; compteur ++)
137 {
138 string nom_dossier = args[compteur].ToString();
139 nom_dossier = nom_dossier.Replace ("\\","\\\\");
140 //j appel la liste des dossiers d un repertoire de base donné en
parametre
141 string wql_dossier = "Select Name from Win32_Directory WHERE Name LIKE
'" + nom_dossier + "%'";
142 System.Management.WqlObjectQuery oQuery = new
System.Management.WqlObjectQuery(wql_dossier);
143
144 //j execute la requete
145 ManagementObjectSearcher oSearcher = new
ManagementObjectSearcher(un_scan.connect_wmi(),oQuery);
146
147 oSearcher.Options.ReturnImmediately = true;
148 oSearcher.Options.Rewindable = false;
149 oSearcher.Options.DirectRead = true;
150
151 //je recupere le resultat avec la methode Get
152 ManagementObjectCollection oReturnCollection = oSearcher.Get();
153
154 un_scan.connect_mysql();
155
156 //loop through found drives and write out info
157 foreach( ManagementObject oReturn in oReturnCollection )
158 {
159 string nom_rep = oReturn["Name"].ToString();
160 string verif_nom_rep = nom_rep.Replace("'","\\'"); // je remplace le
caractere ' qui fait planter la requete WMI par \'
161
162 if (nom_rep == verif_nom_rep) // si les 2 variables sont identiques c
est que le nom du repertoire ne contient pas le caractere '
163 {
164 nom_rep_mysql = nom_rep.Replace("\\","\\\\");
165 sql_ajoute_dossier = "REPLACE INTO repertoire VALUES ('" + nom_rep_mysql
+ "')";
166 un_scan.mysql_query(sql_ajoute_dossier);
167
168 ManagementObject LogicalFileSecuritySetting = new ManagementObject( new
ManagementPath( "ROOT\\CIMV2:Win32_LogicalFileSecuritySetting.Path='" +
nom_rep + "'"));
169 ManagementBaseObject inParams = null;
170 bool EnablePrivileges =
LogicalFileSecuritySetting.Scope.Options.EnablePrivileges;
171 LogicalFileSecuritySetting.Scope.Options.EnablePrivileges = true;
172 ManagementBaseObject outParams =
LogicalFileSecuritySetting.InvokeMethod("GetSecurityDescriptor", inParams,
null);
173 ManagementBaseObject Descriptor =
((ManagementBaseObject)(outParams.Properties["Descriptor"].Value));
174 LogicalFileSecuritySetting.Scope.Options.EnablePrivileges =
EnablePrivileges;
175
176 ManagementBaseObject[] DACLObject = ( ( ManagementBaseObject[] )(
Descriptor.Properties["DACL"].Value ) );
177
178 System.Collections.Stack stk = new System.Collections.Stack();
179
180 for(int i = 0; i < DACLObject.Length; i++)
181 {
182 ManagementBaseObject ACE=DACLObject[ i ];
183
184 stk.Push( ACE );
185
186 // si cette acces n a pas encore ete verifiee, je lajoute dans le
fichier et da ns mon arrayList
187 sql_ajoute_acces = "REPLACE INTO acces VALUES ('" + (nom_rep_mysql + "',
'" + ( (ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value + "', '" +
DACLObject.Properties["AccessMask"].Value + "', '" +
un_scan.trouve_nom_pc() + "', CURRENT_TIMESTAMP())"); // j ecrit le nom du
repertoire courant, le login et l'AccessMask dans le fichier
188 un_scan.mysql_query(sql_ajoute_acces);
189
190 etre_doublon = false;
191
192 foreach (string login in verif_login)
193 {
194 if (login == (string)(un_scan.trouve_nom_pc() + "|" +
((ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value) + "|" +
un_scan.trouve_nom_pc())
195 {
196 etre_doublon = true;
197 }
198 }
199
200 verif_login.Add (un_scan.trouve_nom_pc() + "|" + ((ManagementBaseObject)
DACLObject[ i ].Properties["Trustee"].Value).Properties["Name"].Value);
201
202 if (!etre_doublon)
203 {
204 sql_pc = "REPLACE pc VALUES ('" + un_scan.trouve_nom_pc() + "', '" +
(( (ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value + "')"); // j
ajoute le nom de l utilisateur dans la table utilisateur
205 un_scan.mysql_query(sql_pc);
206 }
207 }
208 }
209 }
210 }
211 un_scan.mysql_deconnect();
212 Console.WriteLine ("Analyse des dossiers terminées");
213 }
214 }
215 }
216 }
 
N

Nick Malik

why are you using WMI? That's got to be the slowest way to get a directory
listing.
For the current machine, use the DirectoryInfo class with the name of the
local directory you need to scan.

If you have network access to a machine, you can use the same method
remotely as you can locally. Just use \\servername\c$\directory as the
format for the string to pass to DirectoryInfo.

--- Nick

nico said:
Hello

I have write this program that retrieve all directory and subdirectory
recursively of a given directory given in parameter.
For each directory, the script find all user permission for the current
directory and add the username, permission and directory name into MySQL.


The code works fine, but too slow.

He need aproximate 1 hour to scan 200 directory.

How to optimize this code please ?

I know I can improve it but I code with C# just for some days.

1 * Time: 08:59
2 *
3 * To change this template use Tools | Options | Coding | Edit Standard
Headers.
4 */
5
6 using System;
7 using System.IO;
8 using System.Data;
9 using System.Data.SqlClient;
10 using System.Data.Common;
11 using System.Management;
12 using System.Collections;
13 using ByteFX;
14 using ByteFX.Data.MySqlClient;
15 using System.Diagnostics;
16 using System.ComponentModel;
17
18 namespace System.Management
19
20 {
21 class wmi_scan_dossier
22 {
23 private string _nom_pc;
24 private MySqlConnection _id_con_mysql;
25 private System.Management.ManagementScope _oMs;
26
27 private MySqlConnection id_con_mysql
28 {
29 get
30 {
31 return _id_con_mysql;
32 }
33 set
34 {
35 _id_con_mysql = value;
36 }
37 }
38
39 private System.Management.ManagementScope oMs
40 {
41 get
42 {
43 return _oMs;
44 }
45 set
46 {
47 oMs = value;
48 }
49 }
50
51 void connect_mysql()
52 {
53 string ConnectionString = ConnectionString = "Database=toto;Data
Source=localhost;User Id=root;Password=XXX";
54 MySqlConnection _id_con_mysql = new MySqlConnection(ConnectionString);
55 _id_con_mysql.Open();
56 this.id_con_mysql = _id_con_mysql;
57 }
58
59 void mysql_query(string sql)
60 {
61 //this.connect_mysql();
62 MySqlCommand query_ajoute_dossier = new MySqlCommand(sql,
this.id_con_mysql);
63 query_ajoute_dossier.ExecuteNonQuery();
64 }
65
66 void mysql_deconnect()
67 {
68 this.id_con_mysql.Close();
69 }
70
71 public string trouve_nom_pc()
72 {
73 ConnectionOptions oConn = new ConnectionOptions();
74 //oConn.Username = "stist"; // je specifie le login local (pas
obligatoire si le programme est executer sur la machine local
75 //oConn.Password = "stage2004"; // je specifie le mot de passe local (pas
obligatoire si le programme est executer sur la machine local
76
77 //System.Management.ManagementScope oMs = new
System.Management.ManagementScope("\\\\MachineX", oConn);
78 //System.Management.ManagementScope oMs = new
System.Management.ManagementScope("\\\\MachineX");
79
80 //j appel la liste des dossiers d un repertoire de base donnee
81 System.Management.ObjectQuery oQueryPc = new
System.Management.ObjectQuery("SELECT Name from Win32_ComputerSystem");
82
83 //j execute la requete
84 ManagementObjectSearcher oSearcherPc = new
ManagementObjectSearcher(this.connect_wmi(),oQueryPc);
85
86 //je recupere le nom de l ordinateur avec la methode Get
87 ManagementObjectCollection oReturnCollectionPc = oSearcherPc.Get();
88
89 foreach(ManagementObject oReturnPc in oReturnCollectionPc)
90 {
91 _nom_pc = oReturnPc["name"].ToString();
92 }
93 return _nom_pc;
94 }
95
96 public System.Management.ManagementScope connect_wmi()
97 {
98 // fonction retournant l identifiant de connexion a WMI
99 this._oMs = new System.Management.ManagementScope("\\\\MachineX");
100 return this.oMs;
101 }
102
103 public static void Main(string[] args)
104 {
105 string nom_rep_mysql, sql_ajoute_dossier, sql_ajoute_acces, sql_pc;
106
107 wmi_scan_dossier un_scan = new wmi_scan_dossier();
108
109 ArrayList verif_login = new ArrayList(); // je declare un liste de
tableau dynamique qui contiendra la liste des utilisateurs uniques ayant des
droits sur les répertoires traités pour éviter les doublons
110 bool etre_doublon = false;
111
112 //Connection credentials to the remote computer - not needed if the
logged in account has access
113 ConnectionOptions oConn = new ConnectionOptions();
114
115 //j appel la liste des dossiers d un repertoire de base donnee
116 System.Management.ObjectQuery oQueryPc = new
System.Management.ObjectQuery("SELECT Name from Win32_ComputerSystem");
117
118 //j execute la requete
119 ManagementObjectSearcher oSearcherPc = new
ManagementObjectSearcher(un_scan.connect_wmi(),oQueryPc);
120
121 //je recupere le nom de l ordinateur avec la methode Get
122 ManagementObjectCollection oReturnCollectionPc = oSearcherPc.Get();
123
124 int j = args.Length;
125
126 if(j == 0)
127 {
128 Console.WriteLine ("Saisissez un paramètre pour utiliser le logiciel");
129 Console.WriteLine ("Exemple de synthaxe : test_ok.exe \"c:\\Apache\"
\"C:\\Documents and Settings\"");
130 Console.WriteLine ("Cette appel aura pour effet de scanner l'ensemble
des sous dossiers des répertoires c:\\Apache ET C:\\Documents and
Settings");
131
132 }
133 else
134 {
135 Console.WriteLine ("Début du scan du dossier ... patience ");
136 for(int compteur = 0; compteur < j ; compteur ++)
137 {
138 string nom_dossier = args[compteur].ToString();
139 nom_dossier = nom_dossier.Replace ("\\","\\\\");
140 //j appel la liste des dossiers d un repertoire de base donné en
parametre
141 string wql_dossier = "Select Name from Win32_Directory WHERE Name LIKE
'" + nom_dossier + "%'";
142 System.Management.WqlObjectQuery oQuery = new
System.Management.WqlObjectQuery(wql_dossier);
143
144 //j execute la requete
145 ManagementObjectSearcher oSearcher = new
ManagementObjectSearcher(un_scan.connect_wmi(),oQuery);
146
147 oSearcher.Options.ReturnImmediately = true;
148 oSearcher.Options.Rewindable = false;
149 oSearcher.Options.DirectRead = true;
150
151 //je recupere le resultat avec la methode Get
152 ManagementObjectCollection oReturnCollection = oSearcher.Get();
153
154 un_scan.connect_mysql();
155
156 //loop through found drives and write out info
157 foreach( ManagementObject oReturn in oReturnCollection )
158 {
159 string nom_rep = oReturn["Name"].ToString();
160 string verif_nom_rep = nom_rep.Replace("'","\\'"); // je remplace le
caractere ' qui fait planter la requete WMI par \'
161
162 if (nom_rep == verif_nom_rep) // si les 2 variables sont identiques c
est que le nom du repertoire ne contient pas le caractere '
163 {
164 nom_rep_mysql = nom_rep.Replace("\\","\\\\");
165 sql_ajoute_dossier = "REPLACE INTO repertoire VALUES ('" + nom_rep_mysql
+ "')";
166 un_scan.mysql_query(sql_ajoute_dossier);
167
168 ManagementObject LogicalFileSecuritySetting = new ManagementObject( new
ManagementPath( "ROOT\\CIMV2:Win32_LogicalFileSecuritySetting.Path='" +
nom_rep + "'"));
169 ManagementBaseObject inParams = null;
170 bool EnablePrivileges =
LogicalFileSecuritySetting.Scope.Options.EnablePrivileges;
171 LogicalFileSecuritySetting.Scope.Options.EnablePrivileges = true;
172 ManagementBaseObject outParams =
LogicalFileSecuritySetting.InvokeMethod("GetSecurityDescriptor", inParams,
null);
173 ManagementBaseObject Descriptor =
((ManagementBaseObject)(outParams.Properties["Descriptor"].Value));
174 LogicalFileSecuritySetting.Scope.Options.EnablePrivileges =
EnablePrivileges;
175
176 ManagementBaseObject[] DACLObject = ( ( ManagementBaseObject[] )(
Descriptor.Properties["DACL"].Value ) );
177
178 System.Collections.Stack stk = new System.Collections.Stack();
179
180 for(int i = 0; i < DACLObject.Length; i++)
181 {
182 ManagementBaseObject ACE=DACLObject[ i ];
183
184 stk.Push( ACE );
185
186 // si cette acces n a pas encore ete verifiee, je lajoute dans le
fichier et da ns mon arrayList
187 sql_ajoute_acces = "REPLACE INTO acces VALUES ('" + (nom_rep_mysql + "',
'" + ( (ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value + "', '" +
DACLObject.Properties["AccessMask"].Value + "', '" +
un_scan.trouve_nom_pc() + "', CURRENT_TIMESTAMP())"); // j ecrit le nom du
repertoire courant, le login et l'AccessMask dans le fichier
188 un_scan.mysql_query(sql_ajoute_acces);
189
190 etre_doublon = false;
191
192 foreach (string login in verif_login)
193 {
194 if (login == (string)(un_scan.trouve_nom_pc() + "|" +
((ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value) + "|" +
un_scan.trouve_nom_pc())
195 {
196 etre_doublon = true;
197 }
198 }
199
200 verif_login.Add (un_scan.trouve_nom_pc() + "|" + ((ManagementBaseObject)
DACLObject[ i ].Properties["Trustee"].Value).Properties["Name"].Value);
201
202 if (!etre_doublon)
203 {
204 sql_pc = "REPLACE pc VALUES ('" + un_scan.trouve_nom_pc() + "', '" +
(( (ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value + "')"); // j
ajoute le nom de l utilisateur dans la table utilisateur
205 un_scan.mysql_query(sql_pc);
206 }
207 }
208 }
209 }
210 }
211 un_scan.mysql_deconnect();
212 Console.WriteLine ("Analyse des dossiers terminées");
213 }
214 }
215 }
216 }
 
N

nico

Nick Malik said:
why are you using WMI? That's got to be the slowest way to get a directory
listing.
For the current machine, use the DirectoryInfo class with the name of the
local directory you need to scan.

If you have network access to a machine, you can use the same method
remotely as you can locally. Just use \\servername\c$\directory as the
format for the string to pass to DirectoryInfo.

--- Nick

Ok thanks but if I scan all directory recursively, I will have too connect
to WMI X time where X is the number of directory that I need to scan.

By using a WQL QUERY I need to connect only one time to WMI and brownse the
array of object.
 
N

Nick Malik

I perhaps was not clear.

The DirectoryInfo class does not use WMI. It is fast. I can scan thousands
of files and directories in a few seconds.

I will repeat my first question, in a different form:
I do not understand what business reason you have for using WMI?
Please explain so I can help you find a better solution.

--- Nick
 
N

nico

Nick Malik said:
I perhaps was not clear.

The DirectoryInfo class does not use WMI. It is fast. I can scan thousands
of files and directories in a few seconds.

I will repeat my first question, in a different form:
I do not understand what business reason you have for using WMI?
Please explain so I can help you find a better solution.

--- Nick

I need WMI because I need to retrieve all permission for all local user for
all directory on my computer and write the AccessMask and Username and
Directory into a MySQL database.
 
O

Oliver

The DirectoryInfo class does not use WMI. It is fast. I can scan thousands
of files and directories in a few seconds.

actually in my experience it is not fast.

my task was to write code to search for files on disk - and email the
contents using SMTP - I wrote this first in Perl (using fork to
'multithread' the emailing bit).

I then re-wrote in C# because I thought the multithreading code but
would be cleaner using threads than fork - it was, but I found the
that searching for the files on disk was *much* slower in C#.

Actually I used the Directory class instead of DirectoryInfo - which
should be the faster choice in my scenario.

anyone know the *fastest* way to do a recursive file search in C# ?
Oliver.
 
N

Nick Malik

This is very useful information Oliver. I thank you.

Compared to WMI, Directory and DirectoryInfo are both about 100 times
faster.

WMI is the slowest possible method for gaining access to this information,
and that is the course of this thread.

--- N
 
N

Nick Malik

I do not understand what business reason you have for using WMI?
I need WMI because I need to retrieve all permission for all local user for
all directory on my computer and write the AccessMask and Username and
Directory into a MySQL database.

No, you do not need WMI to do that.

There are at least three and perhaps four ways to get the information that
you want. Each way has its advantages and disadvantages. The method you
chose, WMI, has the disadvantage of being very very slow.

I'm trying to get you to consider a different way.

(Analogy: You are driving on a crowded city street, where there is a major
highway one mile a way that will take you where you want to go... I'm trying
to get you to look for the signs to the highway).

See DirectoryInfo at:
http://msdn.microsoft.com/library/d...ml/frlrfsystemiodirectoryinfomemberstopic.asp

See Directory at:
http://msdn.microsoft.com/library/d...ref/html/frlrfsystemiodirectoryclasstopic.asp

To get the ACL of a directory or file, use the following object:
http://www.codeproject.com/dotnet/ntsecuritynet.asp

Hope this helps,
--- N
 
W

Willy Denoyette [MVP]

Your query is wrong, you need to include the drive as search criteria,
otherwise you will scan ALL logical drives attached to the system including
the mapped network shares (No wonder it is slow :) this can take hours when
a lot of drives are mapped).

Change your query into:
Select Name from Win32_Directory WHERE drive='c:' and Name LIKE '.....'


Willy.


nico said:
Hello

I have write this program that retrieve all directory and subdirectory
recursively of a given directory given in parameter.
For each directory, the script find all user permission for the current
directory and add the username, permission and directory name into MySQL.


The code works fine, but too slow.

He need aproximate 1 hour to scan 200 directory.

How to optimize this code please ?

I know I can improve it but I code with C# just for some days.

1 * Time: 08:59
2 *
3 * To change this template use Tools | Options | Coding | Edit Standard
Headers.
4 */
5
6 using System;
7 using System.IO;
8 using System.Data;
9 using System.Data.SqlClient;
10 using System.Data.Common;
11 using System.Management;
12 using System.Collections;
13 using ByteFX;
14 using ByteFX.Data.MySqlClient;
15 using System.Diagnostics;
16 using System.ComponentModel;
17
18 namespace System.Management
19
20 {
21 class wmi_scan_dossier
22 {
23 private string _nom_pc;
24 private MySqlConnection _id_con_mysql;
25 private System.Management.ManagementScope _oMs;
26
27 private MySqlConnection id_con_mysql
28 {
29 get
30 {
31 return _id_con_mysql;
32 }
33 set
34 {
35 _id_con_mysql = value;
36 }
37 }
38
39 private System.Management.ManagementScope oMs
40 {
41 get
42 {
43 return _oMs;
44 }
45 set
46 {
47 oMs = value;
48 }
49 }
50
51 void connect_mysql()
52 {
53 string ConnectionString = ConnectionString = "Database=toto;Data
Source=localhost;User Id=root;Password=XXX";
54 MySqlConnection _id_con_mysql = new MySqlConnection(ConnectionString);
55 _id_con_mysql.Open();
56 this.id_con_mysql = _id_con_mysql;
57 }
58
59 void mysql_query(string sql)
60 {
61 //this.connect_mysql();
62 MySqlCommand query_ajoute_dossier = new MySqlCommand(sql,
this.id_con_mysql);
63 query_ajoute_dossier.ExecuteNonQuery();
64 }
65
66 void mysql_deconnect()
67 {
68 this.id_con_mysql.Close();
69 }
70
71 public string trouve_nom_pc()
72 {
73 ConnectionOptions oConn = new ConnectionOptions();
74 //oConn.Username = "stist"; // je specifie le login local (pas
obligatoire si le programme est executer sur la machine local
75 //oConn.Password = "stage2004"; // je specifie le mot de passe local
(pas
obligatoire si le programme est executer sur la machine local
76
77 //System.Management.ManagementScope oMs = new
System.Management.ManagementScope("\\\\MachineX", oConn);
78 //System.Management.ManagementScope oMs = new
System.Management.ManagementScope("\\\\MachineX");
79
80 //j appel la liste des dossiers d un repertoire de base donnee
81 System.Management.ObjectQuery oQueryPc = new
System.Management.ObjectQuery("SELECT Name from Win32_ComputerSystem");
82
83 //j execute la requete
84 ManagementObjectSearcher oSearcherPc = new
ManagementObjectSearcher(this.connect_wmi(),oQueryPc);
85
86 //je recupere le nom de l ordinateur avec la methode Get
87 ManagementObjectCollection oReturnCollectionPc = oSearcherPc.Get();
88
89 foreach(ManagementObject oReturnPc in oReturnCollectionPc)
90 {
91 _nom_pc = oReturnPc["name"].ToString();
92 }
93 return _nom_pc;
94 }
95
96 public System.Management.ManagementScope connect_wmi()
97 {
98 // fonction retournant l identifiant de connexion a WMI
99 this._oMs = new System.Management.ManagementScope("\\\\MachineX");
100 return this.oMs;
101 }
102
103 public static void Main(string[] args)
104 {
105 string nom_rep_mysql, sql_ajoute_dossier, sql_ajoute_acces, sql_pc;
106
107 wmi_scan_dossier un_scan = new wmi_scan_dossier();
108
109 ArrayList verif_login = new ArrayList(); // je declare un liste de
tableau dynamique qui contiendra la liste des utilisateurs uniques ayant
des
droits sur les répertoires traités pour éviter les doublons
110 bool etre_doublon = false;
111
112 //Connection credentials to the remote computer - not needed if the
logged in account has access
113 ConnectionOptions oConn = new ConnectionOptions();
114
115 //j appel la liste des dossiers d un repertoire de base donnee
116 System.Management.ObjectQuery oQueryPc = new
System.Management.ObjectQuery("SELECT Name from Win32_ComputerSystem");
117
118 //j execute la requete
119 ManagementObjectSearcher oSearcherPc = new
ManagementObjectSearcher(un_scan.connect_wmi(),oQueryPc);
120
121 //je recupere le nom de l ordinateur avec la methode Get
122 ManagementObjectCollection oReturnCollectionPc = oSearcherPc.Get();
123
124 int j = args.Length;
125
126 if(j == 0)
127 {
128 Console.WriteLine ("Saisissez un paramètre pour utiliser le
logiciel");
129 Console.WriteLine ("Exemple de synthaxe : test_ok.exe \"c:\\Apache\"
\"C:\\Documents and Settings\"");
130 Console.WriteLine ("Cette appel aura pour effet de scanner l'ensemble
des sous dossiers des répertoires c:\\Apache ET C:\\Documents and
Settings");
131
132 }
133 else
134 {
135 Console.WriteLine ("Début du scan du dossier ... patience ");
136 for(int compteur = 0; compteur < j ; compteur ++)
137 {
138 string nom_dossier = args[compteur].ToString();
139 nom_dossier = nom_dossier.Replace ("\\","\\\\");
140 //j appel la liste des dossiers d un repertoire de base donné en
parametre
141 string wql_dossier = "Select Name from Win32_Directory WHERE Name LIKE
'" + nom_dossier + "%'";
142 System.Management.WqlObjectQuery oQuery = new
System.Management.WqlObjectQuery(wql_dossier);
143
144 //j execute la requete
145 ManagementObjectSearcher oSearcher = new
ManagementObjectSearcher(un_scan.connect_wmi(),oQuery);
146
147 oSearcher.Options.ReturnImmediately = true;
148 oSearcher.Options.Rewindable = false;
149 oSearcher.Options.DirectRead = true;
150
151 //je recupere le resultat avec la methode Get
152 ManagementObjectCollection oReturnCollection = oSearcher.Get();
153
154 un_scan.connect_mysql();
155
156 //loop through found drives and write out info
157 foreach( ManagementObject oReturn in oReturnCollection )
158 {
159 string nom_rep = oReturn["Name"].ToString();
160 string verif_nom_rep = nom_rep.Replace("'","\\'"); // je remplace le
caractere ' qui fait planter la requete WMI par \'
161
162 if (nom_rep == verif_nom_rep) // si les 2 variables sont identiques c
est que le nom du repertoire ne contient pas le caractere '
163 {
164 nom_rep_mysql = nom_rep.Replace("\\","\\\\");
165 sql_ajoute_dossier = "REPLACE INTO repertoire VALUES ('" +
nom_rep_mysql
+ "')";
166 un_scan.mysql_query(sql_ajoute_dossier);
167
168 ManagementObject LogicalFileSecuritySetting = new ManagementObject(
new
ManagementPath( "ROOT\\CIMV2:Win32_LogicalFileSecuritySetting.Path='" +
nom_rep + "'"));
169 ManagementBaseObject inParams = null;
170 bool EnablePrivileges =
LogicalFileSecuritySetting.Scope.Options.EnablePrivileges;
171 LogicalFileSecuritySetting.Scope.Options.EnablePrivileges = true;
172 ManagementBaseObject outParams =
LogicalFileSecuritySetting.InvokeMethod("GetSecurityDescriptor", inParams,
null);
173 ManagementBaseObject Descriptor =
((ManagementBaseObject)(outParams.Properties["Descriptor"].Value));
174 LogicalFileSecuritySetting.Scope.Options.EnablePrivileges =
EnablePrivileges;
175
176 ManagementBaseObject[] DACLObject = ( ( ManagementBaseObject[] )(
Descriptor.Properties["DACL"].Value ) );
177
178 System.Collections.Stack stk = new System.Collections.Stack();
179
180 for(int i = 0; i < DACLObject.Length; i++)
181 {
182 ManagementBaseObject ACE=DACLObject[ i ];
183
184 stk.Push( ACE );
185
186 // si cette acces n a pas encore ete verifiee, je lajoute dans le
fichier et da ns mon arrayList
187 sql_ajoute_acces = "REPLACE INTO acces VALUES ('" + (nom_rep_mysql +
"',
'" + ( (ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value + "', '" +
DACLObject.Properties["AccessMask"].Value + "', '" +
un_scan.trouve_nom_pc() + "', CURRENT_TIMESTAMP())"); // j ecrit le nom du
repertoire courant, le login et l'AccessMask dans le fichier
188 un_scan.mysql_query(sql_ajoute_acces);
189
190 etre_doublon = false;
191
192 foreach (string login in verif_login)
193 {
194 if (login == (string)(un_scan.trouve_nom_pc() + "|" +
((ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value) + "|" +
un_scan.trouve_nom_pc())
195 {
196 etre_doublon = true;
197 }
198 }
199
200 verif_login.Add (un_scan.trouve_nom_pc() + "|" +
((ManagementBaseObject)
DACLObject[ i ].Properties["Trustee"].Value).Properties["Name"].Value);
201
202 if (!etre_doublon)
203 {
204 sql_pc = "REPLACE pc VALUES ('" + un_scan.trouve_nom_pc() + "', '" +
(( (ManagementBaseObject) DACLObject[
i ].Properties["Trustee"].Value).Properties["Name"].Value + "')"); // j
ajoute le nom de l utilisateur dans la table utilisateur
205 un_scan.mysql_query(sql_pc);
206 }
207 }
208 }
209 }
210 }
211 un_scan.mysql_deconnect();
212 Console.WriteLine ("Analyse des dossiers terminées");
213 }
214 }
215 }
216 }
 
W

Willy Denoyette [MVP]

Nick Malik said:
This is very useful information Oliver. I thank you.

Compared to WMI, Directory and DirectoryInfo are both about 100 times
faster.

WMI is the slowest possible method for gaining access to this information,
and that is the course of this thread.

--- N
Hmmm.... Why using WMI?
Simply because this is the most simple way to do without resorting to
unmanaged code.
DirectoryInfo has not the features offered by the WIn32_Directory (tough not
used here), nor give it back the NTFS security info.

Sure WMI WIn32_Directory is slower than DirectoryInfo but not 100 times as
you incorrectly state, but only 10 times.

F.I scanning c:\program files (1598 subdirs) on a fast 7200RPM local drive
takes:
0.22 sec. using DirectoryInfo
1.12 sec. using WMI
This is only 5 times slower.

However over a network (and that's exactly what OP is doing)
6.0 sec. using DirectoryInfo
0.72 sec the second run (effect of server side caching)
7.2 sec. using WMI
2.2 sec the second run (effect of server side caching)
Here it's only 3 times slower.

Now it's up to you to decide it's fast enough, but there's more, the caller
needs access permission to whole directory tree using DirectoryInfo using an
UNC path, so he needs to run with admin privileges on the remote server,
this while WMI only needs to impersonate the caller's credentials supplied
in code.
And last but not least, OP needs NTFS security info (but hell I don't know
why he ever needs to store this in a DB) from the scanned dirs, something
that can easily be done (but you should never do whatever technology you
use) using ... right WMI.

And this http://www.codeproject.com/dotnet/ntsecuritynet.asp can only be
used for local drives.

Willy.
 
N

Nick Malik

Hello Willy,

Your information is enlightening, and I regret my exaggeration about the
cost of using WMI.

However, I do wonder, given that I asked the question at least three times,
why the original poster didn't take the time to tell me that they were
accessing the data over the network?

Oh, that's right, because the original poster NEVER SAID THAT.

Of course, my French is not very good, so when reading his or her code, I
was not able to understand the comments and variable names... perhaps this
information was buried in the code somewhere, and perhaps your French is
better than mine.

You have offered a good reason to WMI to scan a remote drive, and in the
rare case when that would be useful, I will recall this discussion.
However, I still assert that the OP never said that he or she was scanning a
remote drive. I asked, as clearly as I could, why they were using WMI, and
the reason was always "because it is there."

So, please, realize that I was trying to be helpful. I've read many posts
where the questioner had heard about some technique and had used it without
knowing that another technique was more common, or faster, or whatever, etc.
Those posts are quite common, as you must know. For me to ask the OP if
this is the case is not out of line.

It was not a slam on WMI. At least, it wasn't meant to be.

Thanks,
--- Nick Malik
 
W

Willy Denoyette [MVP]

Hi Nick,

No offense, you are right OP never said the scenario was C/S, you really
need to look at the code (not the comments) to see this.
And to me it's a bad design (don't store NTFS security attributes in a DB)
and a wrong implementation (run this on the server and not from a client).

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top