sys-admin 1.3.1-mswin32 → 1.4.0-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +16 -0
- data/MANIFEST +15 -14
- data/README +54 -38
- data/examples/groups.rb +39 -0
- data/examples/users.rb +53 -0
- data/install.rb +22 -0
- data/lib/sys/admin.rb +712 -403
- data/sys-admin.gemspec +38 -0
- data/test/tc_admin.rb +14 -14
- data/test/tc_unix.rb +78 -0
- data/test/tc_windows.rb +312 -0
- metadata +17 -6
data/CHANGES
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
== 1.4.0 - 20-Jan-2007
|
2
|
+
* Added the following methods: add_local_user, config_local_user,
|
3
|
+
delete_local_user, add_global_group, config_global_group, and
|
4
|
+
delete_global_group. MS Windows only at the moment.
|
5
|
+
* Added corresponding tests.
|
6
|
+
* Added much more inline documentation.
|
7
|
+
* Major refactoring of the get_lastlog_info helper function in admin.h. This
|
8
|
+
fixed a major bug in some flavors of Linux where the Admin.users method
|
9
|
+
could go into an infinite loop. It also fixed some minor bugs where console
|
10
|
+
and host values were sometimes filled with junk characters.
|
11
|
+
* Added the User#change attribute, and a check for the pw_change struct member
|
12
|
+
in the extconf.rb file.
|
13
|
+
* The User#expire attribute is now handled as a Time object instead of an
|
14
|
+
integer.
|
15
|
+
* Renamed tc_win32.rb to tc_windows.rb
|
16
|
+
|
1
17
|
== 1.3.1 - 29-Jun-2005
|
2
18
|
* Fixed a bug where the inability to read the lastlog file caused an error.
|
3
19
|
From now on that error is ignored, and the lastlog attributes of the User
|
data/MANIFEST
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
README
|
1
|
+
* install.rb
|
2
|
+
* sys-admin.gemspec
|
3
|
+
* CHANGES
|
4
|
+
* MANIFEST
|
5
|
+
* README
|
7
6
|
|
8
|
-
examples/groups.rb
|
9
|
-
examples/users.rb
|
7
|
+
* examples/groups.rb
|
8
|
+
* examples/users.rb
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
* ext/admin.c
|
11
|
+
* ext/admin.h
|
12
|
+
* ext/extconf.rb
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
test/
|
14
|
+
* lib/sys/win32.rb
|
15
|
+
|
16
|
+
* test/tc_admin.rb
|
17
|
+
* test/tc_unix.rb
|
18
|
+
* test/tc_windows.rb
|
data/README
CHANGED
@@ -3,18 +3,18 @@
|
|
3
3
|
Etc module.
|
4
4
|
|
5
5
|
== Installation
|
6
|
-
===
|
7
|
-
|
8
|
-
|
6
|
+
=== Windows
|
7
|
+
ruby tc_admin.rb # optional (in the 'test' directory)
|
8
|
+
ruby install.rb
|
9
9
|
|
10
10
|
=== Unix
|
11
|
-
ruby extconf.rb
|
12
|
-
|
13
|
-
ruby
|
14
|
-
|
11
|
+
ruby extconf.rb (in the 'ext' directory)
|
12
|
+
make
|
13
|
+
ruby tc_admin.rb # optional (in the 'test' directory)
|
14
|
+
make install
|
15
15
|
|
16
16
|
== Synopsis
|
17
|
-
require
|
17
|
+
require 'sys/admin'
|
18
18
|
include Sys
|
19
19
|
|
20
20
|
# Yields a User object for each user
|
@@ -47,7 +47,7 @@ Admin.get_user(name, host=localhost)
|
|
47
47
|
Admin.get_user(uid, host=localhost, local=true)
|
48
48
|
Returns a User object based on +name+ or +uid+.
|
49
49
|
|
50
|
-
|
50
|
+
Windows only: you may specify a host from which information is retrieved.
|
51
51
|
The default is the local machine. You may also specify whether to
|
52
52
|
retrieve a local or global account. The default is local.
|
53
53
|
|
@@ -55,7 +55,7 @@ Admin.get_group(name, host=localhost, local=true)
|
|
55
55
|
Admin.get_group(gid, host=localhost, local=true)
|
56
56
|
Returns a Group object based on +name+ or +uid+.
|
57
57
|
|
58
|
-
|
58
|
+
Windows only: you may specify a host from which information is retrieved.
|
59
59
|
The default is the local machine. You can retrieve either a global or
|
60
60
|
local group, depending on the value of the +local+ argument.
|
61
61
|
|
@@ -64,7 +64,7 @@ Admin.groups(host=localhost, local=true){ |group| ... }
|
|
64
64
|
In block form, yields a Group object for each user on the system. In
|
65
65
|
non-block form, returns an Array of Group objects.
|
66
66
|
|
67
|
-
|
67
|
+
Windows only: you may specify a host from which information is retrieved.
|
68
68
|
The default is the local machine. You can retrieve either a global or
|
69
69
|
local group, depending on the value of the +local+ argument.
|
70
70
|
|
@@ -73,13 +73,13 @@ Admin.users(host=localhost, local=true){ |user| ... }
|
|
73
73
|
In block form, yields a User object for each user on the system. In
|
74
74
|
non-block form, returns an Array of User objects.
|
75
75
|
|
76
|
-
|
76
|
+
Windows only: you may specify a host from which information is retrieved.
|
77
77
|
The default is the local machine. You can retrieve either a global or
|
78
78
|
local group, depending on the value of the +local+ argument.
|
79
79
|
|
80
80
|
== User class
|
81
|
-
=== User (
|
82
|
-
|
81
|
+
=== User (Windows)
|
82
|
+
The User class has the following attributes on MS Windows systems:
|
83
83
|
|
84
84
|
* account_type
|
85
85
|
* caption
|
@@ -99,7 +99,7 @@ Admin.users(host=localhost, local=true){ |user| ... }
|
|
99
99
|
* password_required?
|
100
100
|
|
101
101
|
=== User (Unix)
|
102
|
-
|
102
|
+
The User class has the following attributes on Unix systems:
|
103
103
|
|
104
104
|
* name
|
105
105
|
* passwd
|
@@ -112,11 +112,12 @@ Admin.users(host=localhost, local=true){ |user| ... }
|
|
112
112
|
* age
|
113
113
|
* class
|
114
114
|
* comment
|
115
|
+
* change
|
115
116
|
* expire
|
116
117
|
|
117
118
|
== Group Classes
|
118
|
-
=== Group (
|
119
|
-
|
119
|
+
=== Group (Windows)
|
120
|
+
The Group class has the following attributes on MS Windows systems:
|
120
121
|
|
121
122
|
* caption
|
122
123
|
* description
|
@@ -129,46 +130,61 @@ Admin.users(host=localhost, local=true){ |user| ... }
|
|
129
130
|
* local?
|
130
131
|
|
131
132
|
=== Group (Unix)
|
132
|
-
|
133
|
+
The Group class has the following attributes on Unix systems:
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
135
|
+
* name
|
136
|
+
* gid
|
137
|
+
* members
|
138
|
+
* passwd
|
138
139
|
|
139
140
|
== Error Classes
|
140
141
|
AdminError < StandardError
|
141
142
|
Raised if anything goes wrong with any of the above methods.
|
142
143
|
|
143
144
|
== Developer's Notes
|
144
|
-
===
|
145
|
-
|
146
|
-
|
147
|
-
|
145
|
+
=== MS Windows
|
146
|
+
The Windows version now uses a win32ole + WMI approach to getting
|
147
|
+
information. This means that the WMI service must be running on the
|
148
|
+
target machine in order to work (which it is, by default).
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
150
|
+
Note that, by default, local user and group information is retrieved
|
151
|
+
instead of global. You probably do NOT want to iterate over global users
|
152
|
+
or groups because there can be quite a few on your domain.
|
153
|
+
|
154
|
+
=== UNIX
|
155
|
+
The underlying implementation is similar to core Ruby's Etc implementation.
|
156
|
+
But, in addition to the different interface, I use the re-entrant version
|
157
|
+
of the appropriate functions when available.
|
152
158
|
|
153
159
|
== Future Plans
|
154
|
-
|
155
|
-
|
156
|
-
* Admin.
|
157
|
-
* Admin.
|
158
|
-
* Admin.
|
160
|
+
Add the following methods for UNIX:
|
161
|
+
|
162
|
+
* Admin.add_local_user
|
163
|
+
* Admin.config_local_user
|
164
|
+
* Admin.delete_local_user
|
165
|
+
* Admin.add_global_user
|
166
|
+
* Admin.config_global_user
|
167
|
+
* Admin.delete_global_user
|
168
|
+
|
169
|
+
* Admin.add_local_group
|
170
|
+
* Admin.config_local_group
|
171
|
+
* Admin.delete_local_group
|
172
|
+
* Admin.add_global_group
|
173
|
+
* Admin.config_global_group
|
174
|
+
* Admin.delete_global_group
|
159
175
|
|
160
176
|
== Known Bugs
|
161
|
-
None that I'm aware of.
|
177
|
+
None that I'm aware of. If you find any, please log them on the project
|
162
178
|
page at http://www.rubyforge.org/projects/sysutils.
|
163
179
|
|
164
180
|
== License
|
165
181
|
Ruby's
|
166
182
|
|
167
183
|
== Copyright
|
168
|
-
(C) 2005, Daniel J. Berger
|
184
|
+
(C) 2005-2007, Daniel J. Berger
|
169
185
|
All Rights Reserved
|
170
186
|
|
171
187
|
== Author
|
172
188
|
Daniel J. Berger
|
173
|
-
djberg96
|
174
|
-
IRC nickname: imperator/mok/rubyhacker1
|
189
|
+
djberg96 at nospam at gmail dot com
|
190
|
+
IRC nickname: imperator/mok/rubyhacker1 (freenode)
|
data/examples/groups.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
###########################################################################
|
2
|
+
# groups.rb
|
3
|
+
#
|
4
|
+
# Sample script to demonstrate some of the various group methods. Alter
|
5
|
+
# as you see fit.
|
6
|
+
###########################################################################
|
7
|
+
base = File.basename(Dir.pwd)
|
8
|
+
|
9
|
+
if base == "examples" || base =~ /sys-admin.*/
|
10
|
+
require "ftools"
|
11
|
+
Dir.chdir("..") if base == "examples"
|
12
|
+
Dir.mkdir("sys") unless File.exists?("sys")
|
13
|
+
if RUBY_PLATFORM.match("mswin")
|
14
|
+
File.copy("lib/sys/admin.rb", "sys/admin.rb")
|
15
|
+
else
|
16
|
+
File.copy("admin.so","sys") if File.exists?("admin.so")
|
17
|
+
end
|
18
|
+
$LOAD_PATH.unshift(Dir.pwd)
|
19
|
+
end
|
20
|
+
|
21
|
+
require "pp"
|
22
|
+
require "sys/admin"
|
23
|
+
include Sys
|
24
|
+
|
25
|
+
if PLATFORM.match("mswin")
|
26
|
+
pp Admin.get_group("guests")
|
27
|
+
pp Admin.get_group(513)
|
28
|
+
else
|
29
|
+
pp Admin.get_group("adm")
|
30
|
+
pp Admin.get_group(7)
|
31
|
+
end
|
32
|
+
|
33
|
+
Admin.groups{ |g|
|
34
|
+
pp g
|
35
|
+
puts
|
36
|
+
}
|
37
|
+
|
38
|
+
# This should raise an error
|
39
|
+
Admin.get_group("fofofofof")
|
data/examples/users.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
###########################################################################
|
2
|
+
# users.rb
|
3
|
+
#
|
4
|
+
# Sample script to demonstrate some of the various user methods. Alter
|
5
|
+
# as you see fit.
|
6
|
+
###########################################################################
|
7
|
+
base = File.basename(Dir.pwd)
|
8
|
+
|
9
|
+
if base == "examples" || base =~ /sys-admin.*/
|
10
|
+
require "ftools"
|
11
|
+
Dir.chdir("..") if base == "examples"
|
12
|
+
Dir.mkdir("sys") unless File.exists?("sys")
|
13
|
+
if RUBY_PLATFORM.match("mswin")
|
14
|
+
File.copy("lib/sys/admin.rb", "sys/admin.rb")
|
15
|
+
else
|
16
|
+
File.copy("admin.so","sys") if File.exists?("admin.so")
|
17
|
+
end
|
18
|
+
$LOAD_PATH.unshift(Dir.pwd)
|
19
|
+
end
|
20
|
+
|
21
|
+
require "pp"
|
22
|
+
require "sys/admin"
|
23
|
+
include Sys
|
24
|
+
|
25
|
+
user = User.new do |u|
|
26
|
+
u.name = "Foo"
|
27
|
+
u.description = "Test account"
|
28
|
+
u.password = "changeme"
|
29
|
+
#u.lockout = false
|
30
|
+
u.disabled = true
|
31
|
+
#u.password_required = true
|
32
|
+
end
|
33
|
+
|
34
|
+
Admin.delete_user(u.name) rescue nil
|
35
|
+
Admin.add_user(user)
|
36
|
+
|
37
|
+
#pp Admin.get_user("Foo")
|
38
|
+
|
39
|
+
#Admin.delete_user("Foo")
|
40
|
+
|
41
|
+
=begin
|
42
|
+
user = Admin.get_login
|
43
|
+
|
44
|
+
puts "User: #{user}"
|
45
|
+
|
46
|
+
Admin.users{ |u|
|
47
|
+
pp u
|
48
|
+
puts
|
49
|
+
}
|
50
|
+
|
51
|
+
pp Admin.get_user(user)
|
52
|
+
pp Admin.get_user(501)
|
53
|
+
=end
|
data/install.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
##############################################
|
2
|
+
# install.rb
|
3
|
+
#
|
4
|
+
# Install script for Win32 systems only.
|
5
|
+
##############################################
|
6
|
+
unless File::ALT_SEPARATOR
|
7
|
+
STDERR.puts "Unix systems should use the extconf.rb file for installation."
|
8
|
+
STDERR.puts "Exiting. The sys-admin package was NOT installed."
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
require "rbconfig"
|
13
|
+
require "ftools"
|
14
|
+
include Config
|
15
|
+
|
16
|
+
sitedir = CONFIG['sitelibdir']
|
17
|
+
|
18
|
+
unless File.exist?("#{sitedir}/sys")
|
19
|
+
Dir.mkdir("#{sitedir}/sys")
|
20
|
+
end
|
21
|
+
|
22
|
+
File.copy("lib/sys/win32.rb", "#{sitedir}/sys/admin.rb", true)
|
data/lib/sys/admin.rb
CHANGED
@@ -1,403 +1,712 @@
|
|
1
|
-
require "win32ole"
|
2
|
-
require "Win32API"
|
3
|
-
require "socket"
|
4
|
-
|
5
|
-
module Sys
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
#
|
169
|
-
|
170
|
-
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
def
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
end
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
#
|
360
|
-
#
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
1
|
+
require "win32ole"
|
2
|
+
require "Win32API"
|
3
|
+
require "socket"
|
4
|
+
|
5
|
+
module Sys
|
6
|
+
# This is the error raised in the majority of cases if anything goes wrong
|
7
|
+
# with any of the Sys::Admin methods.
|
8
|
+
#
|
9
|
+
class AdminError < StandardError; end
|
10
|
+
|
11
|
+
class Group
|
12
|
+
# Short description of the object.
|
13
|
+
attr_accessor :caption
|
14
|
+
|
15
|
+
# Description of the group.
|
16
|
+
attr_accessor :description
|
17
|
+
|
18
|
+
# Name of the Windows domain to which the group account belongs.
|
19
|
+
attr_accessor :domain
|
20
|
+
|
21
|
+
# Date the group was added.
|
22
|
+
attr_accessor :install_date
|
23
|
+
|
24
|
+
# Name of the Windows group account on the Group#domain specified.
|
25
|
+
attr_accessor :name
|
26
|
+
|
27
|
+
# Security identifier for this group.
|
28
|
+
attr_accessor :sid
|
29
|
+
|
30
|
+
# Current status for the group, such as "ok", "error", etc.
|
31
|
+
attr_accessor :status
|
32
|
+
|
33
|
+
# The group ID.
|
34
|
+
attr_accessor :gid
|
35
|
+
|
36
|
+
# Sets whether or not the group is local (as opposed to global).
|
37
|
+
attr_writer :local
|
38
|
+
|
39
|
+
# Creates and returns a new Group object. This class encapsulates
|
40
|
+
# the information for a group account, whether it be global or local.
|
41
|
+
#
|
42
|
+
# Yields +self+ if a block is given.
|
43
|
+
#
|
44
|
+
def initialize
|
45
|
+
yield self if block_given?
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns whether or not the group is a local group.
|
49
|
+
#
|
50
|
+
def local?
|
51
|
+
@local
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the type of SID (Security Identifier) as a stringified value.
|
55
|
+
#
|
56
|
+
def sid_type
|
57
|
+
@sid_type
|
58
|
+
end
|
59
|
+
|
60
|
+
# Sets the SID (Security Identifier) type to +stype+, which can be
|
61
|
+
# one of the following constant values:
|
62
|
+
#
|
63
|
+
# * Admin::SidTypeUser
|
64
|
+
# * Admin::SidTypeGroup
|
65
|
+
# * Admin::SidTypeDomain
|
66
|
+
# * Admin::SidTypeAlias
|
67
|
+
# * Admin::SidTypeWellKnownGroup
|
68
|
+
# * Admin::SidTypeDeletedAccount
|
69
|
+
# * Admin::SidTypeInvalid
|
70
|
+
# * Admin::SidTypeUnknown
|
71
|
+
# * Admin::SidTypeComputer
|
72
|
+
#
|
73
|
+
def sid_type=(stype)
|
74
|
+
if stype.kind_of?(String)
|
75
|
+
@sid_type = stype.downcase
|
76
|
+
else
|
77
|
+
case stype
|
78
|
+
when Admin::SidTypeUser
|
79
|
+
@sid_type = "user"
|
80
|
+
when Admin::SidTypeGroup
|
81
|
+
@sid_type = "group"
|
82
|
+
when Admin::SidTypeDomain
|
83
|
+
@sid_type = "domain"
|
84
|
+
when Admin::SidTypeAlias
|
85
|
+
@sid_type = "alias"
|
86
|
+
when Admin::SidTypeWellKnownGroup
|
87
|
+
@sid_type = "well_known_group"
|
88
|
+
when Admin::SidTypeDeletedAccount
|
89
|
+
@sid_type = "deleted_account"
|
90
|
+
when Admin::SidTypeInvalid
|
91
|
+
@sid_type = "invalid"
|
92
|
+
when Admin::SidTypeUnknown
|
93
|
+
@sid_type = "unknown"
|
94
|
+
when Admin::SidTypeComputer
|
95
|
+
@sid_type = "computer"
|
96
|
+
else
|
97
|
+
@sid_type = "unknown"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
@sid_type
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class User
|
105
|
+
# An account for users whose primary account is in another domain.
|
106
|
+
TEMP_DUPLICATE = 0x0100
|
107
|
+
|
108
|
+
# Default account type that represents a typical user.
|
109
|
+
NORMAL = 0x0200
|
110
|
+
|
111
|
+
# A permit to trust account for a domain that trusts other domains.
|
112
|
+
INTERDOMAIN_TRUST = 0x0800
|
113
|
+
|
114
|
+
# An account for a Windows NT/2000 workstation or server that is a
|
115
|
+
# member of this domain.
|
116
|
+
WORKSTATION_TRUST = 0x1000
|
117
|
+
|
118
|
+
# A computer account for a backup domain controller that is a member
|
119
|
+
# of this domain.
|
120
|
+
SERVER_TRUST = 0x2000
|
121
|
+
|
122
|
+
# Domain and username of the account.
|
123
|
+
attr_accessor :caption
|
124
|
+
|
125
|
+
# Description of the account.
|
126
|
+
attr_accessor :description
|
127
|
+
|
128
|
+
# Name of the Windows domain to which a user account belongs.
|
129
|
+
attr_accessor :domain
|
130
|
+
|
131
|
+
# The user's password.
|
132
|
+
attr_accessor :password
|
133
|
+
|
134
|
+
# Full name of a local user.
|
135
|
+
attr_accessor :full_name
|
136
|
+
|
137
|
+
# Date the user account was created.
|
138
|
+
attr_accessor :install_date
|
139
|
+
|
140
|
+
# Name of the Windows user account on the domain that the User#domain
|
141
|
+
# property specifies.
|
142
|
+
attr_accessor :name
|
143
|
+
|
144
|
+
# The user's security identifier.
|
145
|
+
attr_accessor :sid
|
146
|
+
|
147
|
+
# Current status for the group, such as "ok", "error", etc.
|
148
|
+
attr_accessor :status
|
149
|
+
|
150
|
+
# Used to set whether or not the account is disabled.
|
151
|
+
attr_writer :disabled
|
152
|
+
|
153
|
+
# Sets whether or not the account is defined on the local computer.
|
154
|
+
attr_writer :local
|
155
|
+
|
156
|
+
# Sets whether or not the account is locked out of the OS.
|
157
|
+
attr_writer :lockout
|
158
|
+
|
159
|
+
# Sets whether or not the password for the account can be changed.
|
160
|
+
attr_writer :password_changeable
|
161
|
+
|
162
|
+
# Sets whether or not the password for the account expires.
|
163
|
+
attr_writer :password_expires
|
164
|
+
|
165
|
+
# Sets whether or not a password is required for the account.
|
166
|
+
attr_writer :password_required
|
167
|
+
|
168
|
+
# Returns the account type as a human readable string.
|
169
|
+
attr_reader :account_type
|
170
|
+
|
171
|
+
# Creates an returns a new User object. A User object encapsulates a
|
172
|
+
# user account on the operating system.
|
173
|
+
#
|
174
|
+
# Yields +self+ if a block is provided.
|
175
|
+
#
|
176
|
+
def initialize
|
177
|
+
yield self if block_given?
|
178
|
+
end
|
179
|
+
|
180
|
+
# Sets the account type for the account. Possible values are:
|
181
|
+
#
|
182
|
+
# * User::TEMP_DUPLICATE
|
183
|
+
# * User::NORMAL
|
184
|
+
# * User::INTERDOMAIN_TRUST
|
185
|
+
# * User::WORKSTATION_TRUST
|
186
|
+
# * User::SERVER_TRUST
|
187
|
+
#
|
188
|
+
def account_type=(type)
|
189
|
+
case type
|
190
|
+
when TEMP_DUPLICATE
|
191
|
+
@account_type = "duplicate"
|
192
|
+
when NORMAL
|
193
|
+
@account_type = "normal"
|
194
|
+
when INTERDOMAIN_TRUST
|
195
|
+
@account_type = "interdomain_trust"
|
196
|
+
when WORKSTATION_TRUST
|
197
|
+
@account_type = "workstation_trust"
|
198
|
+
when SERVER_TRUST
|
199
|
+
@account_type = "server_trust"
|
200
|
+
else
|
201
|
+
@account_type = "unknown"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Returns the SID type as a human readable string.
|
206
|
+
#
|
207
|
+
def sid_type
|
208
|
+
@sid_type
|
209
|
+
end
|
210
|
+
|
211
|
+
# Sets the SID (Security Identifier) type to +stype+, which can be
|
212
|
+
# one of the following constant values:
|
213
|
+
#
|
214
|
+
# * Admin::SidTypeUser
|
215
|
+
# * Admin::SidTypeGroup
|
216
|
+
# * Admin::SidTypeDomain
|
217
|
+
# * Admin::SidTypeAlias
|
218
|
+
# * Admin::SidTypeWellKnownGroup
|
219
|
+
# * Admin::SidTypeDeletedAccount
|
220
|
+
# * Admin::SidTypeInvalid
|
221
|
+
# * Admin::SidTypeUnknown
|
222
|
+
# * Admin::SidTypeComputer
|
223
|
+
#
|
224
|
+
def sid_type=(stype)
|
225
|
+
case stype
|
226
|
+
when Admin::SidTypeUser
|
227
|
+
@sid_type = "user"
|
228
|
+
when Admin::SidTypeGroup
|
229
|
+
@sid_type = "group"
|
230
|
+
when Admin::SidTypeDomain
|
231
|
+
@sid_type = "domain"
|
232
|
+
when Admin::SidTypeAlias
|
233
|
+
@sid_type = "alias"
|
234
|
+
when Admin::SidTypeWellKnownGroup
|
235
|
+
@sid_type = "well_known_group"
|
236
|
+
when Admin::SidTypeDeletedAccount
|
237
|
+
@sid_type = "deleted_account"
|
238
|
+
when Admin::SidTypeInvalid
|
239
|
+
@sid_type = "invalid"
|
240
|
+
when Admin::SidTypeUnknown
|
241
|
+
@sid_type = "unknown"
|
242
|
+
when Admin::SidTypeComputer
|
243
|
+
@sid_type = "computer"
|
244
|
+
else
|
245
|
+
@sid_type = "unknown"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Returns whether or not the account is disabled.
|
250
|
+
#
|
251
|
+
def disabled?
|
252
|
+
@disabled
|
253
|
+
end
|
254
|
+
|
255
|
+
# Returns whether or not the account is local.
|
256
|
+
#
|
257
|
+
def local?
|
258
|
+
@local
|
259
|
+
end
|
260
|
+
|
261
|
+
# Returns whether or not the account is locked out.
|
262
|
+
#
|
263
|
+
def lockout?
|
264
|
+
@lockout
|
265
|
+
end
|
266
|
+
|
267
|
+
# Returns whether or not the password for the account is changeable.
|
268
|
+
#
|
269
|
+
def password_changeable?
|
270
|
+
@password_changeable
|
271
|
+
end
|
272
|
+
|
273
|
+
# Returns whether or not the password for the account is changeable.
|
274
|
+
#
|
275
|
+
def password_expires?
|
276
|
+
@password_expires
|
277
|
+
end
|
278
|
+
|
279
|
+
# Returns whether or not the a password is required for the account.
|
280
|
+
#
|
281
|
+
def password_required?
|
282
|
+
@password_required
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
class Admin
|
287
|
+
VERSION = '1.4.0'
|
288
|
+
|
289
|
+
SidTypeUser = 1
|
290
|
+
SidTypeGroup = 2
|
291
|
+
SidTypeDomain = 3
|
292
|
+
SidTypeAlias = 4
|
293
|
+
SidTypeWellKnownGroup = 5
|
294
|
+
SidTypeDeletedAccount = 6
|
295
|
+
SidTypeInvalid = 7
|
296
|
+
SidTypeUnknown = 8
|
297
|
+
SidTypeComputer = 9
|
298
|
+
|
299
|
+
# Used by the get_login method
|
300
|
+
GetUserName = Win32API.new('advapi32', 'GetUserName', 'PP', 'L') # :nodoc:
|
301
|
+
|
302
|
+
# Configures the global +user+ on +domain+ using options.
|
303
|
+
#
|
304
|
+
# See http://tinyurl.com/3hjv9 for a list of valid options.
|
305
|
+
#
|
306
|
+
def self.config_global_user(user, options, domain)
|
307
|
+
begin
|
308
|
+
adsi = WIN32OLE.connect("WinNT://#{domain}/#{user},user")
|
309
|
+
options.each{ |option, value|
|
310
|
+
adsi.put(option.to_s, value)
|
311
|
+
}
|
312
|
+
adsi.setinfo
|
313
|
+
rescue WIN32OLERuntimeError => err
|
314
|
+
raise AdminError, err
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# Configures the local +user+ on +host+ using +options+. If no host
|
319
|
+
# is specified, the default is localhost.
|
320
|
+
#
|
321
|
+
# See http://tinyurl.com/3hjv9 for a list of valid options.
|
322
|
+
#
|
323
|
+
def self.config_local_user(user, options, host=Socket.gethostname)
|
324
|
+
begin
|
325
|
+
adsi = WIN32OLE.connect("WinNT://#{host}/#{user},user")
|
326
|
+
options.each{ |option, value|
|
327
|
+
adsi.put(option.to_s, value)
|
328
|
+
}
|
329
|
+
adsi.setinfo
|
330
|
+
rescue WIN32OLERuntimeError => err
|
331
|
+
raise AdminError, err
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Adds the global +user+ on +domain+
|
336
|
+
#
|
337
|
+
def self.add_global_user(user, domain)
|
338
|
+
begin
|
339
|
+
adsi = WIN32OLE.connect("WinNT://#{host},Computer")
|
340
|
+
user = adsi.create("user", user)
|
341
|
+
user.setinfo
|
342
|
+
rescue WIN32OLERuntimeError => err
|
343
|
+
raise AdminError, err
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# Adds the local +user+ on +host+, or the localhost if none is specified.
|
348
|
+
#
|
349
|
+
def self.add_local_user(user, host=Socket.gethostname)
|
350
|
+
begin
|
351
|
+
adsi = WIN32OLE.connect("WinNT://#{host},Computer")
|
352
|
+
user = adsi.create("user", user)
|
353
|
+
user.setinfo
|
354
|
+
rescue WIN32OLERuntimeError => err
|
355
|
+
raise AdminError, err
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Deletes the local +user+ from +host+, or localhost if no host specified.
|
360
|
+
#
|
361
|
+
def self.delete_local_user(user, host=Socket.gethostname)
|
362
|
+
begin
|
363
|
+
adsi = WIN32OLE.connect("WinNT://#{host},Computer")
|
364
|
+
adsi.delete("user", user)
|
365
|
+
rescue WIN32OLERuntimeError => err
|
366
|
+
raise AdminError, err
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# Deletes the global +user+ from +domain+.
|
371
|
+
#
|
372
|
+
def self.delete_global_user(user, domain)
|
373
|
+
begin
|
374
|
+
adsi = WIN32OLE.connect("WinNT://#{domain}")
|
375
|
+
adsi.delete("user", user)
|
376
|
+
rescue WIN32OLERuntimeError => err
|
377
|
+
raise AdminError, err
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
# Configures the global +group+ on +domain+ using +options+.
|
382
|
+
#
|
383
|
+
# See http://tinyurl.com/cjkzl for a list of valid options.
|
384
|
+
#
|
385
|
+
def self.config_global_group(group, options, domain)
|
386
|
+
begin
|
387
|
+
adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group")
|
388
|
+
options.each{ |option, value|
|
389
|
+
adsi.put(option.to_s, value)
|
390
|
+
}
|
391
|
+
adsi.setinfo
|
392
|
+
rescue WIN32OLERuntimeError => err
|
393
|
+
raise AdminError, err
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# Configures the local +group+ on +host+ using +options+. If no host
|
398
|
+
# is specified, the default is localhost.
|
399
|
+
#
|
400
|
+
# See http://tinyurl.com/cjkzl for a list of valid options.
|
401
|
+
#
|
402
|
+
def self.config_local_group(group, options, host=Socket.gethostname)
|
403
|
+
begin
|
404
|
+
adsi = WIN32OLE.connect("WinNT://#{host}/#{group},group")
|
405
|
+
options.each{ |option, value|
|
406
|
+
adsi.put(option.to_s, value)
|
407
|
+
}
|
408
|
+
adsi.setinfo
|
409
|
+
rescue WIN32OLERuntimeError => err
|
410
|
+
raise AdminError, err
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# Add global +group+ to +domain+.
|
415
|
+
#
|
416
|
+
def self.add_global_group(group, domain)
|
417
|
+
begin
|
418
|
+
adsi = WIN32OLE.connect("WinNT://#{domain},Computer")
|
419
|
+
obj = adsi.create("group", group)
|
420
|
+
obj.setinfo
|
421
|
+
rescue WIN32OLERuntimeError => err
|
422
|
+
raise AdminError, err
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
# Add local +group+ to +host+, or the localhost if no host is specified.
|
427
|
+
#
|
428
|
+
def self.add_local_group(group, host=Socket.gethostname)
|
429
|
+
begin
|
430
|
+
adsi = WIN32OLE.connect("WinNT://#{host},Computer")
|
431
|
+
obj = adsi.create("group", group)
|
432
|
+
obj.setinfo
|
433
|
+
rescue WIN32OLERuntimeError => err
|
434
|
+
raise AdminError, err
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
# Delete the global +group+ from +domain+.
|
439
|
+
#
|
440
|
+
def self.delete_global_group(groupid, domain)
|
441
|
+
begin
|
442
|
+
adsi = WIN32OLE.connect("WinNT://#{domain},Computer")
|
443
|
+
obj = adsi.delete("group", groupid)
|
444
|
+
rescue WIN32OLERuntimeError => err
|
445
|
+
raise AdminError, err
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
# Delete the local +group+ from +host+, or localhost if no host specified.
|
450
|
+
#
|
451
|
+
def self.delete_local_group(groupid, host=Socket.gethostname)
|
452
|
+
begin
|
453
|
+
adsi = WIN32OLE.connect("WinNT://#{host},Computer")
|
454
|
+
obj = adsi.delete("group", groupid)
|
455
|
+
rescue WIN32OLERuntimeError => err
|
456
|
+
raise AdminError, err
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
# Returns the user name (only) of the current login.
|
461
|
+
#
|
462
|
+
def self.get_login
|
463
|
+
buffer = 0.chr * 256
|
464
|
+
nsize = [buffer.size].pack("L")
|
465
|
+
|
466
|
+
if GetUserName.call(buffer, nsize) == 0
|
467
|
+
raise AdminError, 'GetUserName() call failed in get_login'
|
468
|
+
end
|
469
|
+
|
470
|
+
length = nsize.unpack("L")[0]
|
471
|
+
username = buffer[0 ... length].chop
|
472
|
+
username
|
473
|
+
end
|
474
|
+
|
475
|
+
# Returns a User object based on either +name+ or +uid+.
|
476
|
+
#
|
477
|
+
# call-seq:
|
478
|
+
# get_user(name, host=localhost)
|
479
|
+
# get_user(uid, host=localhost, local=true)
|
480
|
+
#
|
481
|
+
# You may specify a +host+ from which information is retrieved. The
|
482
|
+
# default is the local machine. You may also specify whether to
|
483
|
+
# retrieve a local or global account. The default is local.
|
484
|
+
#
|
485
|
+
def self.get_user(uid, host=Socket.gethostname, local=true)
|
486
|
+
host = Socket.gethostname if host.nil?
|
487
|
+
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
488
|
+
cs << "//#{host}/root/cimv2"
|
489
|
+
|
490
|
+
begin
|
491
|
+
wmi = WIN32OLE.connect(cs)
|
492
|
+
rescue WIN32OLERuntimeError => e
|
493
|
+
raise AdminError, e
|
494
|
+
end
|
495
|
+
|
496
|
+
query = "select * from win32_useraccount"
|
497
|
+
query << " where localaccount = true" if local
|
498
|
+
|
499
|
+
if uid.kind_of?(Fixnum)
|
500
|
+
if local
|
501
|
+
query << " and sid like '%-#{uid}'"
|
502
|
+
else
|
503
|
+
query << " where sid like '%-#{uid}'"
|
504
|
+
end
|
505
|
+
else
|
506
|
+
if local
|
507
|
+
query << " and name = '#{uid}'"
|
508
|
+
else
|
509
|
+
query << " where name = '#{uid}'"
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
wmi.execquery(query).each{ |user|
|
514
|
+
# Because our 'like' query isn't fulproof, let's parse
|
515
|
+
# the SID again to make sure
|
516
|
+
if uid.kind_of?(Fixnum)
|
517
|
+
if user.sid.split("-").last.to_i != uid
|
518
|
+
next
|
519
|
+
end
|
520
|
+
end
|
521
|
+
usr = User.new do |u|
|
522
|
+
u.account_type = user.accounttype
|
523
|
+
u.caption = user.caption
|
524
|
+
u.description = user.description
|
525
|
+
u.disabled = user.disabled
|
526
|
+
u.domain = user.domain
|
527
|
+
u.full_name = user.fullname
|
528
|
+
u.install_date = user.installdate
|
529
|
+
u.local = user.localaccount
|
530
|
+
u.lockout = user.lockout
|
531
|
+
u.name = user.name
|
532
|
+
u.password_changeable = user.passwordchangeable
|
533
|
+
u.password_expires = user.passwordexpires
|
534
|
+
u.password_required = user.passwordrequired
|
535
|
+
u.sid = user.sid
|
536
|
+
u.sid_type = user.sidtype
|
537
|
+
u.status = user.status
|
538
|
+
end
|
539
|
+
return usr
|
540
|
+
}
|
541
|
+
end
|
542
|
+
|
543
|
+
# In block form, yields a User object for each user on the system. In
|
544
|
+
# non-block form, returns an Array of User objects.
|
545
|
+
#
|
546
|
+
# call-seq:
|
547
|
+
# users(host=localhost, local=true)
|
548
|
+
# users(host=localhost, local=true){ |user| ... }
|
549
|
+
#
|
550
|
+
# You may specify a host from which information is retrieved. The
|
551
|
+
# default is the local machine. You can retrieve either a global or
|
552
|
+
# local group, depending on the value of the +local+ argument.
|
553
|
+
#
|
554
|
+
def self.users(host=Socket.gethostname, local=true)
|
555
|
+
host = Socket.gethostname if host.nil?
|
556
|
+
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
557
|
+
cs << "//#{host}/root/cimv2"
|
558
|
+
|
559
|
+
begin
|
560
|
+
wmi = WIN32OLE.connect(cs)
|
561
|
+
rescue WIN32OLERuntimeError => e
|
562
|
+
raise AdminError, e
|
563
|
+
end
|
564
|
+
|
565
|
+
query = "select * from win32_useraccount"
|
566
|
+
query << " where localaccount = true" if local
|
567
|
+
array = []
|
568
|
+
|
569
|
+
wmi.execquery(query).each{ |user|
|
570
|
+
usr = User.new do |u|
|
571
|
+
u.account_type = user.accounttype
|
572
|
+
u.caption = user.caption
|
573
|
+
u.description = user.description
|
574
|
+
u.disabled = user.disabled
|
575
|
+
u.domain = user.domain
|
576
|
+
u.full_name = user.fullname
|
577
|
+
u.install_date = user.installdate
|
578
|
+
u.local = user.localaccount
|
579
|
+
u.lockout = user.lockout
|
580
|
+
u.name = user.name
|
581
|
+
u.password_changeable = user.passwordchangeable
|
582
|
+
u.password_expires = user.passwordexpires
|
583
|
+
u.password_required = user.passwordrequired
|
584
|
+
u.sid = user.sid
|
585
|
+
u.sid_type = user.sidtype
|
586
|
+
u.status = user.status
|
587
|
+
end
|
588
|
+
|
589
|
+
if block_given?
|
590
|
+
yield usr
|
591
|
+
else
|
592
|
+
array.push(usr)
|
593
|
+
end
|
594
|
+
}
|
595
|
+
return array unless block_given?
|
596
|
+
end
|
597
|
+
|
598
|
+
# Returns a Group object based on either +name+ or +uid+.
|
599
|
+
#
|
600
|
+
# call-seq:
|
601
|
+
# get_group(name, host=localhost, local=true)
|
602
|
+
# get_group(gid, host=localhost, local=true)
|
603
|
+
#
|
604
|
+
# You may specify a host from which information is retrieved.
|
605
|
+
# The default is the local machine. You can retrieve either a global or
|
606
|
+
# local group, depending on the value of the +local+ argument.
|
607
|
+
#
|
608
|
+
def self.get_group(grp, host=Socket.gethostname, local=true)
|
609
|
+
host = Socket.gethostname if host.nil?
|
610
|
+
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
611
|
+
cs << "//#{host}/root/cimv2"
|
612
|
+
gid = nil
|
613
|
+
|
614
|
+
begin
|
615
|
+
wmi = WIN32OLE.connect(cs)
|
616
|
+
rescue WIN32OLERuntimeError => e
|
617
|
+
raise AdminError, e
|
618
|
+
end
|
619
|
+
|
620
|
+
query = "select * from win32_group"
|
621
|
+
query << " where localaccount = true" if local
|
622
|
+
|
623
|
+
if grp.kind_of?(Fixnum)
|
624
|
+
if local
|
625
|
+
query << " and sid like '%-#{grp}'"
|
626
|
+
else
|
627
|
+
query << " where sid like '%-#{grp}'"
|
628
|
+
end
|
629
|
+
else
|
630
|
+
if local
|
631
|
+
query << " and name = '#{grp}'"
|
632
|
+
else
|
633
|
+
query << " where name = '#{grp}'"
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
wmi.execquery(query).each{ |group|
|
638
|
+
gid = group.sid.split("-").last.to_i
|
639
|
+
|
640
|
+
# Because our 'like' query isn't fulproof, let's parse
|
641
|
+
# the SID again to make sure
|
642
|
+
if grp.kind_of?(Fixnum)
|
643
|
+
next if grp != gid
|
644
|
+
end
|
645
|
+
|
646
|
+
grp = Group.new do |g|
|
647
|
+
g.caption = group.caption
|
648
|
+
g.description = group.description
|
649
|
+
g.domain = group.domain
|
650
|
+
g.gid = gid
|
651
|
+
g.install_date = group.installdate
|
652
|
+
g.local = group.localaccount
|
653
|
+
g.name = group.name
|
654
|
+
g.sid = group.sid
|
655
|
+
g.sid_type = group.sidtype
|
656
|
+
g.status = group.status
|
657
|
+
end
|
658
|
+
return grp
|
659
|
+
}
|
660
|
+
# If we're here, it means it wasn't found.
|
661
|
+
raise AdminError, "no group found for '#{grp}'"
|
662
|
+
end
|
663
|
+
|
664
|
+
# In block form, yields a Group object for each user on the system. In
|
665
|
+
# non-block form, returns an Array of Group objects.
|
666
|
+
#
|
667
|
+
# call-seq:
|
668
|
+
# groups(host=localhost, local=true)
|
669
|
+
# groups(host=localhost, local=true){ |group| ... }
|
670
|
+
#
|
671
|
+
# You may specify a host from which information is retrieved.
|
672
|
+
# The default is the local machine. You can retrieve either a global or
|
673
|
+
# local group, depending on the value of the +local+ argument.
|
674
|
+
#
|
675
|
+
def self.groups(host=Socket.gethostname, local=true)
|
676
|
+
host = Socket.gethostname if host.nil?
|
677
|
+
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
678
|
+
cs << "//#{host}/root/cimv2"
|
679
|
+
|
680
|
+
begin
|
681
|
+
wmi = WIN32OLE.connect(cs)
|
682
|
+
rescue WIN32OLERuntimeError => e
|
683
|
+
raise AdminError, e
|
684
|
+
end
|
685
|
+
|
686
|
+
query = "select * from win32_group"
|
687
|
+
query << " where localaccount = true" if local
|
688
|
+
|
689
|
+
array = []
|
690
|
+
wmi.execquery(query).each{ |group|
|
691
|
+
grp = Group.new do |g|
|
692
|
+
g.caption = group.caption
|
693
|
+
g.description = group.description
|
694
|
+
g.domain = group.domain
|
695
|
+
g.gid = group.sid.split("-").last.to_i
|
696
|
+
g.install_date = group.installdate
|
697
|
+
g.local = group.localaccount
|
698
|
+
g.name = group.name
|
699
|
+
g.sid = group.sid
|
700
|
+
g.sid_type = group.sidtype
|
701
|
+
g.status = group.status
|
702
|
+
end
|
703
|
+
if block_given?
|
704
|
+
yield grp
|
705
|
+
else
|
706
|
+
array.push(grp)
|
707
|
+
end
|
708
|
+
}
|
709
|
+
return array unless block_given?
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|