sys-admin 1.5.4-x86-mingw32 → 1.5.5-x86-mingw32

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 CHANGED
@@ -1,3 +1,11 @@
1
+ == 1.5.5 - 5-Jul-2011
2
+ * Modified lastlog handling, and ignore getpwent_r and getgrent_r, on AIX.
3
+ Thanks go to Rick Ohnemus for the spot and patches.
4
+ * Explicitly set spec.cpu on Windows to 'universal' in the gem creation task.
5
+ * Fixed a bug in the User.get_login and User.get_group methods where the query
6
+ being generated was incorrect if no options were passed. Thanks go to
7
+ Matthew Brown for the spot.
8
+
1
9
  == 1.5.4 - 7-Oct-2010
2
10
  * Prefer the getlastlogx() function over lastlog() where supported.
3
11
 
data/Rakefile CHANGED
@@ -2,21 +2,19 @@ require 'rake'
2
2
  require 'rake/clean'
3
3
  require 'rake/testtask'
4
4
  require 'rbconfig'
5
+ include Config
5
6
 
6
- WINDOWS = Config::CONFIG['host_os'] =~ /msdos|mswin|win32|mingw|cygwin/i
7
+ WINDOWS = CONFIG['host_os'] =~ /msdos|mswin|win32|mingw|cygwin|windows/i
7
8
 
8
- desc "Clean the build files for the sys-admin source for UNIX systems"
9
- task :clean do
10
- Dir['*.gem'].each{ |f| File.delete(f) } # Remove any .gem files
11
- unless WINDOWS
12
- Dir.chdir('ext') do
13
- rm_rf('conftest.dSYM') if File.exists?('conftest.dSYM') # OS X
14
- build_file = 'admin.' + Config::CONFIG['DLEXT']
15
- sh 'make distclean' if File.exists?(build_file)
16
- File.delete("sys/#{build_file}") if File.exists?("sys/#{build_file}")
17
- end
18
- end
19
- end
9
+ CLEAN.include(
10
+ '**/*.gem', # Gem files
11
+ '**/*.rbc', # Rubinius
12
+ '**/*.o', # C object file
13
+ '**/*.log', # Ruby extension build log
14
+ '**/Makefile', # C Makefile
15
+ '**/conftest.dSYM', # OS X build directory
16
+ "**/*.#{CONFIG['DLEXT']}" # C shared object
17
+ )
20
18
 
21
19
  desc "Build the sys-admin library on UNIX systems (but don't install it)"
22
20
  task :build => [:clean] do
@@ -37,6 +35,7 @@ namespace :gem do
37
35
 
38
36
  if WINDOWS
39
37
  spec.platform = Gem::Platform::CURRENT
38
+ spec.platform.cpu = 'universal'
40
39
  spec.files = spec.files.reject{ |f| f.include?('ext') }
41
40
  spec.add_dependency('win32-security', '>= 0.1.2')
42
41
  else
data/lib/sys/admin.rb CHANGED
@@ -4,977 +4,985 @@ require 'win32/registry'
4
4
  require 'socket'
5
5
 
6
6
  module Sys
7
- class Group
8
- # Short description of the object.
9
- attr_accessor :caption
10
-
11
- # Description of the group.
12
- attr_accessor :description
13
-
14
- # Name of the Windows domain to which the group account belongs.
15
- attr_accessor :domain
16
-
17
- # Date the group was added.
18
- attr_accessor :install_date
19
-
20
- # Name of the Windows group account on the Group#domain specified.
21
- attr_accessor :name
22
-
23
- # Security identifier for this group.
24
- attr_accessor :sid
25
-
26
- # Current status for the group, such as "ok", "error", etc.
27
- attr_accessor :status
28
-
29
- # The group ID.
30
- attr_accessor :gid
31
-
32
- # Sets whether or not the group is local (as opposed to global).
33
- attr_writer :local
34
-
35
- # An array of members for that group. May contain SID's.
36
- attr_accessor :members
37
-
38
- # Creates and returns a new Group object. This class encapsulates
39
- # the information for a group account, whether it be global or local.
40
- #
41
- # Yields +self+ if a block is given.
42
- #
43
- def initialize
44
- yield self if block_given?
45
- end
7
+ class Group
8
+ # Short description of the object.
9
+ attr_accessor :caption
10
+
11
+ # Description of the group.
12
+ attr_accessor :description
13
+
14
+ # Name of the Windows domain to which the group account belongs.
15
+ attr_accessor :domain
16
+
17
+ # Date the group was added.
18
+ attr_accessor :install_date
19
+
20
+ # Name of the Windows group account on the Group#domain specified.
21
+ attr_accessor :name
22
+
23
+ # Security identifier for this group.
24
+ attr_accessor :sid
25
+
26
+ # Current status for the group, such as "ok", "error", etc.
27
+ attr_accessor :status
28
+
29
+ # The group ID.
30
+ attr_accessor :gid
31
+
32
+ # Sets whether or not the group is local (as opposed to global).
33
+ attr_writer :local
34
+
35
+ # An array of members for that group. May contain SID's.
36
+ attr_accessor :members
37
+
38
+ # Creates and returns a new Group object. This class encapsulates
39
+ # the information for a group account, whether it be global or local.
40
+ #
41
+ # Yields +self+ if a block is given.
42
+ #
43
+ def initialize
44
+ yield self if block_given?
45
+ end
46
+
47
+ # Returns whether or not the group is a local group.
48
+ #
49
+ def local?
50
+ @local
51
+ end
52
+
53
+ # Returns the type of SID (Security Identifier) as a stringified value.
54
+ #
55
+ def sid_type
56
+ @sid_type
57
+ end
46
58
 
47
- # Returns whether or not the group is a local group.
48
- #
49
- def local?
50
- @local
51
- end
52
-
53
- # Returns the type of SID (Security Identifier) as a stringified value.
54
- #
55
- def sid_type
56
- @sid_type
57
- end
58
-
59
- # Sets the SID (Security Identifier) type to +stype+, which can be
60
- # one of the following constant values:
61
- #
62
- # * Admin::SidTypeUser
63
- # * Admin::SidTypeGroup
64
- # * Admin::SidTypeDomain
65
- # * Admin::SidTypeAlias
66
- # * Admin::SidTypeWellKnownGroup
67
- # * Admin::SidTypeDeletedAccount
68
- # * Admin::SidTypeInvalid
69
- # * Admin::SidTypeUnknown
70
- # * Admin::SidTypeComputer
71
- #
72
- def sid_type=(stype)
73
- if stype.kind_of?(String)
74
- @sid_type = stype.downcase
75
- else
76
- case stype
77
- when Admin::SidTypeUser
78
- @sid_type = "user"
79
- when Admin::SidTypeGroup
80
- @sid_type = "group"
81
- when Admin::SidTypeDomain
82
- @sid_type = "domain"
83
- when Admin::SidTypeAlias
84
- @sid_type = "alias"
85
- when Admin::SidTypeWellKnownGroup
86
- @sid_type = "well_known_group"
87
- when Admin::SidTypeDeletedAccount
88
- @sid_type = "deleted_account"
89
- when Admin::SidTypeInvalid
90
- @sid_type = "invalid"
91
- when Admin::SidTypeUnknown
92
- @sid_type = "unknown"
93
- when Admin::SidTypeComputer
94
- @sid_type = "computer"
95
- else
96
- @sid_type = "unknown"
97
- end
59
+ # Sets the SID (Security Identifier) type to +stype+, which can be
60
+ # one of the following constant values:
61
+ #
62
+ # * Admin::SidTypeUser
63
+ # * Admin::SidTypeGroup
64
+ # * Admin::SidTypeDomain
65
+ # * Admin::SidTypeAlias
66
+ # * Admin::SidTypeWellKnownGroup
67
+ # * Admin::SidTypeDeletedAccount
68
+ # * Admin::SidTypeInvalid
69
+ # * Admin::SidTypeUnknown
70
+ # * Admin::SidTypeComputer
71
+ #
72
+ def sid_type=(stype)
73
+ if stype.kind_of?(String)
74
+ @sid_type = stype.downcase
75
+ else
76
+ case stype
77
+ when Admin::SidTypeUser
78
+ @sid_type = "user"
79
+ when Admin::SidTypeGroup
80
+ @sid_type = "group"
81
+ when Admin::SidTypeDomain
82
+ @sid_type = "domain"
83
+ when Admin::SidTypeAlias
84
+ @sid_type = "alias"
85
+ when Admin::SidTypeWellKnownGroup
86
+ @sid_type = "well_known_group"
87
+ when Admin::SidTypeDeletedAccount
88
+ @sid_type = "deleted_account"
89
+ when Admin::SidTypeInvalid
90
+ @sid_type = "invalid"
91
+ when Admin::SidTypeUnknown
92
+ @sid_type = "unknown"
93
+ when Admin::SidTypeComputer
94
+ @sid_type = "computer"
95
+ else
96
+ @sid_type = "unknown"
98
97
  end
99
- @sid_type
100
- end
101
- end
98
+ end
99
+ @sid_type
100
+ end
101
+ end
102
102
 
103
- class User
104
- # An account for users whose primary account is in another domain.
105
- TEMP_DUPLICATE = 0x0100
106
-
107
- # Default account type that represents a typical user.
108
- NORMAL = 0x0200
109
-
110
- # A permit to trust account for a domain that trusts other domains.
111
- INTERDOMAIN_TRUST = 0x0800
103
+ class User
104
+ # An account for users whose primary account is in another domain.
105
+ TEMP_DUPLICATE = 0x0100
106
+
107
+ # Default account type that represents a typical user.
108
+ NORMAL = 0x0200
109
+
110
+ # A permit to trust account for a domain that trusts other domains.
111
+ INTERDOMAIN_TRUST = 0x0800
112
+
113
+ # An account for a Windows NT/2000 workstation or server that is a
114
+ # member of this domain.
115
+ WORKSTATION_TRUST = 0x1000
116
+
117
+ # A computer account for a backup domain controller that is a member
118
+ # of this domain.
119
+ SERVER_TRUST = 0x2000
120
+
121
+ # Domain and username of the account.
122
+ attr_accessor :caption
123
+
124
+ # Description of the account.
125
+ attr_accessor :description
126
+
127
+ # Name of the Windows domain to which a user account belongs.
128
+ attr_accessor :domain
129
+
130
+ # The user's password.
131
+ attr_accessor :password
132
+
133
+ # Full name of a local user.
134
+ attr_accessor :full_name
135
+
136
+ # An array of groups to which the user belongs.
137
+ attr_accessor :groups
138
+
139
+ # Date the user account was created.
140
+ attr_accessor :install_date
141
+
142
+ # Name of the Windows user account on the domain that the User#domain
143
+ # property specifies.
144
+ attr_accessor :name
145
+
146
+ # The user's security identifier.
147
+ attr_accessor :sid
148
+
149
+ # Current status for the user, such as "ok", "error", etc.
150
+ attr_accessor :status
151
+
152
+ # The user's id (RID).
153
+ attr_accessor :uid
154
+
155
+ # The user's home directory
156
+ attr_accessor :dir
157
+
158
+ # Used to set whether or not the account is disabled.
159
+ attr_writer :disabled
160
+
161
+ # Sets whether or not the account is defined on the local computer.
162
+ attr_writer :local
163
+
164
+ # Sets whether or not the account is locked out of the OS.
165
+ attr_writer :lockout
166
+
167
+ # Sets whether or not the password for the account can be changed.
168
+ attr_writer :password_changeable
169
+
170
+ # Sets whether or not the password for the account expires.
171
+ attr_writer :password_expires
172
+
173
+ # Sets whether or not a password is required for the account.
174
+ attr_writer :password_required
175
+
176
+ # Returns the account type as a human readable string.
177
+ attr_reader :account_type
112
178
 
113
- # An account for a Windows NT/2000 workstation or server that is a
114
- # member of this domain.
115
- WORKSTATION_TRUST = 0x1000
179
+ # Creates an returns a new User object. A User object encapsulates a
180
+ # user account on the operating system.
181
+ #
182
+ # Yields +self+ if a block is provided.
183
+ #
184
+ def initialize
185
+ yield self if block_given?
186
+ end
116
187
 
117
- # A computer account for a backup domain controller that is a member
118
- # of this domain.
119
- SERVER_TRUST = 0x2000
120
-
121
- # Domain and username of the account.
122
- attr_accessor :caption
123
-
124
- # Description of the account.
125
- attr_accessor :description
126
-
127
- # Name of the Windows domain to which a user account belongs.
128
- attr_accessor :domain
129
-
130
- # The user's password.
131
- attr_accessor :password
132
-
133
- # Full name of a local user.
134
- attr_accessor :full_name
135
-
136
- # An array of groups to which the user belongs.
137
- attr_accessor :groups
138
-
139
- # Date the user account was created.
140
- attr_accessor :install_date
141
-
142
- # Name of the Windows user account on the domain that the User#domain
143
- # property specifies.
144
- attr_accessor :name
145
-
146
- # The user's security identifier.
147
- attr_accessor :sid
148
-
149
- # Current status for the user, such as "ok", "error", etc.
150
- attr_accessor :status
151
-
152
- # The user's id (RID).
153
- attr_accessor :uid
154
-
155
- # The user's home directory
156
- attr_accessor :dir
157
-
158
- # Used to set whether or not the account is disabled.
159
- attr_writer :disabled
160
-
161
- # Sets whether or not the account is defined on the local computer.
162
- attr_writer :local
163
-
164
- # Sets whether or not the account is locked out of the OS.
165
- attr_writer :lockout
166
-
167
- # Sets whether or not the password for the account can be changed.
168
- attr_writer :password_changeable
169
-
170
- # Sets whether or not the password for the account expires.
171
- attr_writer :password_expires
172
-
173
- # Sets whether or not a password is required for the account.
174
- attr_writer :password_required
175
-
176
- # Returns the account type as a human readable string.
177
- attr_reader :account_type
178
-
179
- # Creates an returns a new User object. A User object encapsulates a
180
- # user account on the operating system.
181
- #
182
- # Yields +self+ if a block is provided.
183
- #
184
- def initialize
185
- yield self if block_given?
186
- end
187
-
188
- # Sets the account type for the account. Possible values are:
189
- #
190
- # * User::TEMP_DUPLICATE
191
- # * User::NORMAL
192
- # * User::INTERDOMAIN_TRUST
193
- # * User::WORKSTATION_TRUST
194
- # * User::SERVER_TRUST
195
- #
196
- def account_type=(type)
197
- case type
198
- when TEMP_DUPLICATE
199
- @account_type = 'duplicate'
200
- when NORMAL
201
- @account_type = 'normal'
202
- when INTERDOMAIN_TRUST
203
- @account_type = 'interdomain_trust'
204
- when WORKSTATION_TRUST
205
- @account_type = 'workstation_trust'
206
- when SERVER_TRUST
207
- @account_type = 'server_trust'
208
- else
209
- @account_type = 'unknown'
210
- end
188
+ # Sets the account type for the account. Possible values are:
189
+ #
190
+ # * User::TEMP_DUPLICATE
191
+ # * User::NORMAL
192
+ # * User::INTERDOMAIN_TRUST
193
+ # * User::WORKSTATION_TRUST
194
+ # * User::SERVER_TRUST
195
+ #
196
+ def account_type=(type)
197
+ case type
198
+ when TEMP_DUPLICATE
199
+ @account_type = 'duplicate'
200
+ when NORMAL
201
+ @account_type = 'normal'
202
+ when INTERDOMAIN_TRUST
203
+ @account_type = 'interdomain_trust'
204
+ when WORKSTATION_TRUST
205
+ @account_type = 'workstation_trust'
206
+ when SERVER_TRUST
207
+ @account_type = 'server_trust'
208
+ else
209
+ @account_type = 'unknown'
211
210
  end
211
+ end
212
212
 
213
- # Returns the SID type as a human readable string.
214
- #
215
- def sid_type
216
- @sid_type
217
- end
213
+ # Returns the SID type as a human readable string.
214
+ #
215
+ def sid_type
216
+ @sid_type
217
+ end
218
218
 
219
- # Sets the SID (Security Identifier) type to +stype+, which can be
220
- # one of the following constant values:
221
- #
222
- # * Admin::SidTypeUser
223
- # * Admin::SidTypeGroup
224
- # * Admin::SidTypeDomain
225
- # * Admin::SidTypeAlias
226
- # * Admin::SidTypeWellKnownGroup
227
- # * Admin::SidTypeDeletedAccount
228
- # * Admin::SidTypeInvalid
229
- # * Admin::SidTypeUnknown
230
- # * Admin::SidTypeComputer
231
- #
232
- def sid_type=(stype)
233
- case stype
234
- when Admin::SidTypeUser
235
- @sid_type = 'user'
236
- when Admin::SidTypeGroup
237
- @sid_type = 'group'
238
- when Admin::SidTypeDomain
239
- @sid_type = 'domain'
240
- when Admin::SidTypeAlias
241
- @sid_type = 'alias'
242
- when Admin::SidTypeWellKnownGroup
243
- @sid_type = 'well_known_group'
244
- when Admin::SidTypeDeletedAccount
245
- @sid_type = 'deleted_account'
246
- when Admin::SidTypeInvalid
247
- @sid_type = 'invalid'
248
- when Admin::SidTypeUnknown
249
- @sid_type = 'unknown'
250
- when Admin::SidTypeComputer
251
- @sid_type = 'computer'
252
- else
253
- @sid_type = 'unknown'
254
- end
255
- end
256
-
257
- # Returns whether or not the account is disabled.
258
- #
259
- def disabled?
260
- @disabled
219
+ # Sets the SID (Security Identifier) type to +stype+, which can be
220
+ # one of the following constant values:
221
+ #
222
+ # * Admin::SidTypeUser
223
+ # * Admin::SidTypeGroup
224
+ # * Admin::SidTypeDomain
225
+ # * Admin::SidTypeAlias
226
+ # * Admin::SidTypeWellKnownGroup
227
+ # * Admin::SidTypeDeletedAccount
228
+ # * Admin::SidTypeInvalid
229
+ # * Admin::SidTypeUnknown
230
+ # * Admin::SidTypeComputer
231
+ #
232
+ def sid_type=(stype)
233
+ case stype
234
+ when Admin::SidTypeUser
235
+ @sid_type = 'user'
236
+ when Admin::SidTypeGroup
237
+ @sid_type = 'group'
238
+ when Admin::SidTypeDomain
239
+ @sid_type = 'domain'
240
+ when Admin::SidTypeAlias
241
+ @sid_type = 'alias'
242
+ when Admin::SidTypeWellKnownGroup
243
+ @sid_type = 'well_known_group'
244
+ when Admin::SidTypeDeletedAccount
245
+ @sid_type = 'deleted_account'
246
+ when Admin::SidTypeInvalid
247
+ @sid_type = 'invalid'
248
+ when Admin::SidTypeUnknown
249
+ @sid_type = 'unknown'
250
+ when Admin::SidTypeComputer
251
+ @sid_type = 'computer'
252
+ else
253
+ @sid_type = 'unknown'
261
254
  end
255
+ end
262
256
 
263
- # Returns whether or not the account is local.
264
- #
265
- def local?
266
- @local
267
- end
268
-
269
- # Returns whether or not the account is locked out.
270
- #
271
- def lockout?
272
- @lockout
273
- end
257
+ # Returns whether or not the account is disabled.
258
+ #
259
+ def disabled?
260
+ @disabled
261
+ end
262
+
263
+ # Returns whether or not the account is local.
264
+ #
265
+ def local?
266
+ @local
267
+ end
268
+
269
+ # Returns whether or not the account is locked out.
270
+ #
271
+ def lockout?
272
+ @lockout
273
+ end
274
274
 
275
- # Returns whether or not the password for the account is changeable.
276
- #
277
- def password_changeable?
278
- @password_changeable
279
- end
280
-
281
- # Returns whether or not the password for the account is changeable.
282
- #
283
- def password_expires?
284
- @password_expires
275
+ # Returns whether or not the password for the account is changeable.
276
+ #
277
+ def password_changeable?
278
+ @password_changeable
279
+ end
280
+
281
+ # Returns whether or not the password for the account is changeable.
282
+ #
283
+ def password_expires?
284
+ @password_expires
285
+ end
286
+
287
+ # Returns whether or not the a password is required for the account.
288
+ #
289
+ def password_required?
290
+ @password_required
291
+ end
292
+ end
293
+
294
+ class Admin
295
+ # The version of the sys-admin library
296
+ VERSION = '1.5.5'
297
+
298
+ # This is the error raised in the majority of cases if anything goes wrong
299
+ # with any of the Sys::Admin methods.
300
+ #
301
+ class Error < StandardError; end
302
+
303
+ SidTypeUser = 1
304
+ SidTypeGroup = 2
305
+ SidTypeDomain = 3
306
+ SidTypeAlias = 4
307
+ SidTypeWellKnownGroup = 5
308
+ SidTypeDeletedAccount = 6
309
+ SidTypeInvalid = 7
310
+ SidTypeUnknown = 8
311
+ SidTypeComputer = 9
312
+
313
+ private
314
+
315
+ HKEY = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"
316
+
317
+ # Retrieves the user's home directory. For local accounts query the
318
+ # registry. For domain accounts use ADSI and use the HomeDirectory.
319
+ #
320
+ def self.get_home_dir(user, local = false, domain = nil)
321
+ if local
322
+ sec = Win32::Security::SID.open(user)
323
+ key = HKEY + sec.to_s
324
+ dir = nil
325
+
326
+ begin
327
+ Win32::Registry::HKEY_LOCAL_MACHINE.open(key) do |reg|
328
+ dir = reg['ProfileImagePath']
329
+ end
330
+ rescue Win32::Registry::Error
331
+ # Not every local user has a home directory
332
+ end
333
+ else
334
+ domain ||= Socket.gethostname
335
+ adsi = WIN32OLE.connect("WinNT://#{domain}/#{user},user")
336
+ dir = adsi.get('HomeDirectory')
285
337
  end
338
+
339
+ dir
340
+ end
341
+
342
+ # A private method that lower cases all keys, and converts them
343
+ # all to symbols.
344
+ #
345
+ def self.munge_options(opts)
346
+ rhash = {}
347
+
348
+ opts.each{ |k, v|
349
+ k = k.to_s.downcase.to_sym
350
+ rhash[k] = v
351
+ }
352
+
353
+ rhash
354
+ end
355
+
356
+ # An internal, private method for getting a list of groups for
357
+ # a particular user.
358
+ #
359
+ def self.get_groups(domain, user)
360
+ array = []
361
+ adsi = WIN32OLE.connect("WinNT://#{domain}/#{user}")
362
+ adsi.groups.each{ |g| array << g.name }
363
+ array
364
+ end
365
+
366
+ # An internal, private method for getting a list of members for
367
+ # any particular group.
368
+ #
369
+ def self.get_members(domain, group)
370
+ array = []
371
+ adsi = WIN32OLE.connect("WinNT://#{domain}/#{group}")
372
+ adsi.members.each{ |g| array << g.name }
373
+ array
374
+ end
286
375
 
287
- # Returns whether or not the a password is required for the account.
288
- #
289
- def password_required?
290
- @password_required
291
- end
292
- end
293
-
294
- class Admin
295
- # The version of the sys-admin library
296
- VERSION = '1.5.4'
297
-
298
- # This is the error raised in the majority of cases if anything goes wrong
299
- # with any of the Sys::Admin methods.
300
- #
301
- class Error < StandardError; end
302
-
303
- SidTypeUser = 1
304
- SidTypeGroup = 2
305
- SidTypeDomain = 3
306
- SidTypeAlias = 4
307
- SidTypeWellKnownGroup = 5
308
- SidTypeDeletedAccount = 6
309
- SidTypeInvalid = 7
310
- SidTypeUnknown = 8
311
- SidTypeComputer = 9
312
-
313
- private
314
-
315
- HKEY = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"
316
-
317
- # Retrieves the user's home directory. For local accounts query the
318
- # registry. For domain accounts use ADSI and use the HomeDirectory.
319
- #
320
- def self.get_home_dir(user, local = false, domain = nil)
321
- if local
322
- sec = Win32::Security::SID.open(user)
323
- key = HKEY + sec.to_s
324
- dir = nil
325
-
326
- begin
327
- Win32::Registry::HKEY_LOCAL_MACHINE.open(key) do |reg|
328
- dir = reg['ProfileImagePath']
329
- end
330
- rescue Win32::Registry::Error
331
- # Not every local user has a home directory
332
- end
333
- else
334
- domain ||= Socket.gethostname
335
- adsi = WIN32OLE.connect("WinNT://#{domain}/#{user},user")
336
- dir = adsi.get('HomeDirectory')
337
- end
338
-
339
- dir
376
+ # Used by the get_login method
377
+ GetUserName = Win32::API.new('GetUserName', 'PP', 'L', 'advapi32') # :nodoc:
378
+
379
+ public
380
+
381
+ # Creates the given +user+. If no domain option is specified,
382
+ # then it defaults to your local host, i.e. a local account is
383
+ # created.
384
+ #
385
+ # Any options provided are treated as IADsUser interface methods
386
+ # and are called before SetInfo is finally called.
387
+ #
388
+ # Examples:
389
+ #
390
+ # # Create a local user with no options
391
+ # Sys::Admin.add_user(:name => 'asmith')
392
+ #
393
+ # # Create a local user with options
394
+ # Sys::Admin.add_user(
395
+ # :name => 'asmith',
396
+ # :description => 'Really cool guy',
397
+ # :password => 'abc123'
398
+ # )
399
+ #
400
+ # # Create a user on a specific domain
401
+ # Sys::Admin.add_user(
402
+ # :name => 'asmith',
403
+ # :domain => 'XX',
404
+ # :fullname => 'Al Smith'
405
+ # )
406
+ #--
407
+ # Most options are passed to the 'put' method. However, we handle the
408
+ # password specially since it's a separate method, and some environments
409
+ # require that it be set up front.
410
+ #
411
+ def self.add_user(options = {})
412
+ options = munge_options(options)
413
+
414
+ name = options.delete(:name) or raise ArgumentError, 'No user given'
415
+ domain = options[:domain]
416
+
417
+ if domain.nil?
418
+ domain = Socket.gethostname
419
+ moniker = "WinNT://#{domain},Computer"
420
+ else
421
+ moniker = "WinNT://#{domain}"
340
422
  end
341
423
 
342
- # A private method that lower cases all keys, and converts them
343
- # all to symbols.
344
- #
345
- def self.munge_options(opts)
346
- rhash = {}
347
-
348
- opts.each{ |k, v|
349
- k = k.to_s.downcase.to_sym
350
- rhash[k] = v
351
- }
352
-
353
- rhash
424
+ begin
425
+ adsi = WIN32OLE.connect(moniker)
426
+ user = adsi.create('user', name)
427
+ options.each{ |option, value|
428
+ if option.to_s == 'password'
429
+ user.setpassword(value)
430
+ else
431
+ user.put(option.to_s, value)
432
+ end
433
+ }
434
+ user.setinfo
435
+ rescue WIN32OLERuntimeError => err
436
+ raise Error, err
354
437
  end
355
-
356
- # An internal, private method for getting a list of groups for
357
- # a particular user.
358
- #
359
- def self.get_groups(domain, user)
360
- array = []
361
- adsi = WIN32OLE.connect("WinNT://#{domain}/#{user}")
362
- adsi.groups.each{ |g| array << g.name }
363
- array
438
+ end
439
+
440
+ # Configures the +user+ using +options+. If no domain option is
441
+ # specified then your local host is used, i.e. you are configuring
442
+ # a local user account.
443
+ #
444
+ # See http://tinyurl.com/3hjv9 for a list of valid options.
445
+ #
446
+ # In the case of a password change, pass a two element array as the
447
+ # old value and new value.
448
+ #
449
+ # Examples:
450
+ #
451
+ # # Configure a local user
452
+ # Sys::Admin.configure_user(
453
+ # :name => 'djberge',
454
+ # :description => 'Awesome'
455
+ # )
456
+ #
457
+ # # Change the password
458
+ # Sys::Admin.configure_user(
459
+ # :name => 'asmith',
460
+ # :password => [old_pass, new_pass]
461
+ # )
462
+ #
463
+ # # Configure a user on a specific domain
464
+ # Sys::Admin.configure_user(
465
+ # :name => 'jsmrz',
466
+ # :domain => 'XX',
467
+ # :firstname => 'Jo'
468
+ # )
469
+ #
470
+ def self.configure_user(options = {})
471
+ options = munge_options(options)
472
+
473
+ name = options.delete(:name) or raise ArgumentError, 'No name given'
474
+ domain = options[:domain] || Socket.gethostname
475
+
476
+ begin
477
+ adsi = WIN32OLE.connect("WinNT://#{domain}/#{name},user")
478
+ options.each{ |option, value|
479
+ if option.to_s == 'password'
480
+ adsi.changepassword(value[0], value[1])
481
+ else
482
+ adsi.put(option.to_s, value)
483
+ end
484
+ }
485
+ adsi.setinfo
486
+ rescue WIN32OLERuntimeError => err
487
+ raise Error, err
364
488
  end
365
-
366
- # An internal, private method for getting a list of members for
367
- # any particular group.
368
- #
369
- def self.get_members(domain, group)
370
- array = []
371
- adsi = WIN32OLE.connect("WinNT://#{domain}/#{group}")
372
- adsi.members.each{ |g| array << g.name }
373
- array
489
+ end
490
+
491
+ # Deletes the given +user+ on +domain+. If no domain is specified,
492
+ # then it defaults to your local host, i.e. a local account is
493
+ # deleted.
494
+ #
495
+ def self.delete_user(user, domain = nil)
496
+ if domain.nil?
497
+ domain = Socket.gethostname
498
+ moniker = "WinNT://#{domain},Computer"
499
+ else
500
+ moniker = "WinNT://#{domain}"
374
501
  end
375
-
376
- # Used by the get_login method
377
- GetUserName = Win32::API.new('GetUserName', 'PP', 'L', 'advapi32') # :nodoc:
378
-
379
- public
380
-
381
- # Creates the given +user+. If no domain option is specified,
382
- # then it defaults to your local host, i.e. a local account is
383
- # created.
384
- #
385
- # Any options provided are treated as IADsUser interface methods
386
- # and are called before SetInfo is finally called.
387
- #
388
- # Examples:
389
- #
390
- # # Create a local user with no options
391
- # Sys::Admin.add_user(:name => 'asmith')
392
- #
393
- # # Create a local user with options
394
- # Sys::Admin.add_user(
395
- # :name => 'asmith',
396
- # :description => 'Really cool guy',
397
- # :password => 'abc123'
398
- # )
399
- #
400
- # # Create a user on a specific domain
401
- # Sys::Admin.add_user(
402
- # :name => 'asmith',
403
- # :domain => 'XX',
404
- # :fullname => 'Al Smith'
405
- # )
406
- #--
407
- # Most options are passed to the 'put' method. However, we handle the
408
- # password specially since it's a separate method, and some environments
409
- # require that it be set up front.
410
- #
411
- def self.add_user(options = {})
412
- options = munge_options(options)
413
-
414
- name = options.delete(:name) or raise ArgumentError, 'No user given'
415
- domain = options[:domain]
416
-
417
- if domain.nil?
418
- domain = Socket.gethostname
419
- moniker = "WinNT://#{domain},Computer"
420
- else
421
- moniker = "WinNT://#{domain}"
422
- end
423
502
 
424
- begin
425
- adsi = WIN32OLE.connect(moniker)
426
- user = adsi.create('user', name)
427
- options.each{ |option, value|
428
- if option.to_s == 'password'
429
- user.setpassword(value)
430
- else
431
- user.put(option.to_s, value)
432
- end
433
- }
434
- user.setinfo
435
- rescue WIN32OLERuntimeError => err
436
- raise Error, err
437
- end
503
+ begin
504
+ adsi = WIN32OLE.connect(moniker)
505
+ adsi.delete('user', user)
506
+ rescue WIN32OLERuntimeError => err
507
+ raise Error, err
438
508
  end
439
-
440
- # Configures the +user+ using +options+. If no domain option is
441
- # specified then your local host is used, i.e. you are configuring
442
- # a local user account.
443
- #
444
- # See http://tinyurl.com/3hjv9 for a list of valid options.
445
- #
446
- # In the case of a password change, pass a two element array as the
447
- # old value and new value.
448
- #
449
- # Examples:
450
- #
451
- # # Configure a local user
452
- # Sys::Admin.configure_user(
453
- # :name => 'djberge',
454
- # :description => 'Awesome'
455
- # )
456
- #
457
- # # Change the password
458
- # Sys::Admin.configure_user(
459
- # :name => 'asmith',
460
- # :password => [old_pass, new_pass]
461
- # )
462
- #
463
- # # Configure a user on a specific domain
464
- # Sys::Admin.configure_user(
465
- # :name => 'jsmrz',
466
- # :domain => 'XX',
467
- # :firstname => 'Jo'
468
- # )
469
- #
470
- def self.configure_user(options = {})
471
- options = munge_options(options)
472
-
473
- name = options.delete(:name) or raise ArgumentError, 'No name given'
474
- domain = options[:domain] || Socket.gethostname
475
-
476
- begin
477
- adsi = WIN32OLE.connect("WinNT://#{domain}/#{name},user")
478
- options.each{ |option, value|
479
- if option.to_s == 'password'
480
- adsi.changepassword(value[0], value[1])
481
- else
482
- adsi.put(option.to_s, value)
483
- end
484
- }
485
- adsi.setinfo
486
- rescue WIN32OLERuntimeError => err
487
- raise Error, err
488
- end
509
+ end
510
+
511
+ # Create a new +group+ using +options+. If no domain option is specified
512
+ # then a local group is created instead.
513
+ #
514
+ # Examples:
515
+ #
516
+ # # Create a local group with no options
517
+ # Sys::Admin.add_group(:name => 'Dudes')
518
+ #
519
+ # # Create a local group with options
520
+ # Sys::Admin.add_group(:name => 'Dudes', :description => 'Boys')
521
+ #
522
+ # # Create a group on a specific domain
523
+ # Sys::Admin.add_group(
524
+ # :name => 'Ladies',
525
+ # :domain => 'XYZ',
526
+ # :description => 'Girls'
527
+ # )
528
+ #
529
+ def self.add_group(options = {})
530
+ options = munge_options(options)
531
+
532
+ group = options.delete(:name) or raise ArgumentError, 'No name given'
533
+ domain = options[:domain]
534
+
535
+ if domain.nil?
536
+ domain = Socket.gethostname
537
+ moniker = "WinNT://#{domain},Computer"
538
+ else
539
+ moniker = "WinNT://#{domain}"
489
540
  end
490
541
 
491
- # Deletes the given +user+ on +domain+. If no domain is specified,
492
- # then it defaults to your local host, i.e. a local account is
493
- # deleted.
494
- #
495
- def self.delete_user(user, domain = nil)
496
- if domain.nil?
497
- domain = Socket.gethostname
498
- moniker = "WinNT://#{domain},Computer"
499
- else
500
- moniker = "WinNT://#{domain}"
501
- end
502
-
503
- begin
504
- adsi = WIN32OLE.connect(moniker)
505
- adsi.delete('user', user)
506
- rescue WIN32OLERuntimeError => err
507
- raise Error, err
508
- end
542
+ begin
543
+ adsi = WIN32OLE.connect(moniker)
544
+ group = adsi.create('group', group)
545
+ group.setinfo
546
+ configure_group(options) unless options.empty?
547
+ rescue WIN32OLERuntimeError => err
548
+ raise Error, err
509
549
  end
510
-
511
- # Create a new +group+ using +options+. If no domain option is specified
512
- # then a local group is created instead.
513
- #
514
- # Examples:
515
- #
516
- # # Create a local group with no options
517
- # Sys::Admin.add_group(:name => 'Dudes')
518
- #
519
- # # Create a local group with options
520
- # Sys::Admin.add_group(:name => 'Dudes', :description => 'Boys')
521
- #
522
- # # Create a group on a specific domain
523
- # Sys::Admin.add_group(
524
- # :name => 'Ladies',
525
- # :domain => 'XYZ',
526
- # :description => 'Girls'
527
- # )
528
- #
529
- def self.add_group(options = {})
530
- options = munge_options(options)
531
-
532
- group = options.delete(:name) or raise ArgumentError, 'No name given'
533
- domain = options[:domain]
534
-
535
- if domain.nil?
536
- domain = Socket.gethostname
537
- moniker = "WinNT://#{domain},Computer"
538
- else
539
- moniker = "WinNT://#{domain}"
540
- end
541
-
542
- begin
543
- adsi = WIN32OLE.connect(moniker)
544
- group = adsi.create('group', group)
545
- group.setinfo
546
- configure_group(options) unless options.empty?
547
- rescue WIN32OLERuntimeError => err
548
- raise Error, err
549
- end
550
+ end
551
+
552
+ # Configures the +group+ using +options+. If no domain option is
553
+ # specified then your local host is used, i.e. you are configuring
554
+ # a local group.
555
+ #
556
+ # See http://tinyurl.com/cjkzl for a list of valid options.
557
+ #
558
+ # Examples:
559
+ #
560
+ # # Configure a local group.
561
+ # Sys::Admin.configure_group(:name => 'Abba', :description => 'Swedish')
562
+ #
563
+ # # Configure a group on a specific domain.
564
+ # Sys::Admin.configure_group(
565
+ # :name => 'Web Team',
566
+ # :domain => 'Foo',
567
+ # :description => 'Web programming cowboys'
568
+ # )
569
+ #
570
+ def self.configure_group(options = {})
571
+ options = munge_options(options)
572
+
573
+ group = options.delete(:name) or raise ArgumentError, 'No name given'
574
+ domain = options[:domain] || Socket.gethostname
575
+
576
+ begin
577
+ adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group")
578
+ options.each{ |option, value| adsi.put(option.to_s, value) }
579
+ adsi.setinfo
580
+ rescue WIN32OLERuntimeError => err
581
+ raise Error, err
550
582
  end
551
-
552
- # Configures the +group+ using +options+. If no domain option is
553
- # specified then your local host is used, i.e. you are configuring
554
- # a local group.
555
- #
556
- # See http://tinyurl.com/cjkzl for a list of valid options.
557
- #
558
- # Examples:
559
- #
560
- # # Configure a local group.
561
- # Sys::Admin.configure_group(:name => 'Abba', :description => 'Swedish')
562
- #
563
- # # Configure a group on a specific domain.
564
- # Sys::Admin.configure_group(
565
- # :name => 'Web Team',
566
- # :domain => 'Foo',
567
- # :description => 'Web programming cowboys'
568
- # )
569
- #
570
- def self.configure_group(options = {})
571
- options = munge_options(options)
572
-
573
- group = options.delete(:name) or raise ArgumentError, 'No name given'
574
- domain = options[:domain] || Socket.gethostname
575
-
576
- begin
577
- adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group")
578
- options.each{ |option, value| adsi.put(option.to_s, value) }
579
- adsi.setinfo
580
- rescue WIN32OLERuntimeError => err
581
- raise Error, err
582
- end
583
+ end
584
+
585
+ # Delete the +group+ from +domain+. If no domain is specified, then
586
+ # you are deleting a local group.
587
+ #
588
+ def self.delete_group(group, domain = nil)
589
+ if domain.nil?
590
+ domain = Socket.gethostname
591
+ moniker = "WinNT://#{domain},Computer"
592
+ else
593
+ moniker = "WinNT://#{domain}"
583
594
  end
584
595
 
585
- # Delete the +group+ from +domain+. If no domain is specified, then
586
- # you are deleting a local group.
587
- #
588
- def self.delete_group(group, domain = nil)
589
- if domain.nil?
590
- domain = Socket.gethostname
591
- moniker = "WinNT://#{domain},Computer"
592
- else
593
- moniker = "WinNT://#{domain}"
594
- end
595
-
596
- begin
597
- adsi = WIN32OLE.connect(moniker)
598
- obj = adsi.delete('group', group)
599
- rescue WIN32OLERuntimeError => err
600
- raise Error, err
601
- end
596
+ begin
597
+ adsi = WIN32OLE.connect(moniker)
598
+ obj = adsi.delete('group', group)
599
+ rescue WIN32OLERuntimeError => err
600
+ raise Error, err
602
601
  end
602
+ end
603
603
 
604
- # Returns the user name (only) of the current login.
605
- #
606
- def self.get_login
607
- buffer = 0.chr * 256
608
- nsize = [buffer.size].pack("L")
609
-
610
- if GetUserName.call(buffer, nsize) == 0
611
- raise Error, 'GetUserName() call failed in get_login'
612
- end
613
-
614
- length = nsize.unpack('L')[0]
615
- username = buffer[0 ... length].chop
616
- username
604
+ # Returns the user name (only) of the current login.
605
+ #
606
+ def self.get_login
607
+ buffer = 0.chr * 256
608
+ nsize = [buffer.size].pack("L")
609
+
610
+ if GetUserName.call(buffer, nsize) == 0
611
+ raise Error, 'GetUserName() call failed in get_login'
617
612
  end
618
613
 
619
- # Returns a User object based on either +name+ or +uid+.
620
- #
621
- # call-seq:
622
- # Sys::Admin.get_user(name, options = {})
623
- # Sys::Admin.get_user(uid, options = {})
624
- #
625
- # Looks for +usr+ information based on the options you specify, where
626
- # the +usr+ argument can be either a user name or a RID.
627
- #
628
- # If a 'host' option is specified, information is retrieved from that
629
- # host. Otherwise, the local host is used.
630
- #
631
- # All other options are converted to WQL statements against the
632
- # Win32_UserAccount WMI object. See http://tinyurl.com/by9nvn for a
633
- # list of possible options.
634
- #
635
- # Examples:
636
- #
637
- # # Get a user by name
638
- # Admin.get_user('djberge')
639
- #
640
- # # Get a user by uid
641
- # Admin.get_user(100)
642
- #
643
- # # Get a user on a specific domain
644
- # Admin.get_user('djberge', :domain => 'TEST')
645
- #--
646
- # The reason for keeping the +usr+ variable as a separate argument
647
- # instead of rolling it into the options hash was to keep a unified
648
- # API between the Windows and UNIX versions.
649
- #
650
- def self.get_user(usr, options = {})
651
- options = munge_options(options)
652
-
653
- host = options.delete(:host) || Socket.gethostname
654
- cs = "winmgmts:{impersonationLevel=impersonate}!"
655
- cs << "//#{host}/root/cimv2"
656
-
657
- begin
658
- wmi = WIN32OLE.connect(cs)
659
- rescue WIN32OLERuntimeError => err
660
- raise Error, err
661
- end
662
-
663
- query = "select * from win32_useraccount"
664
-
665
- i = 0
666
-
667
- options.each{ |opt, val|
668
- if i == 0
669
- query << " where #{opt} = '#{val}'"
670
- i += 1
671
- else
672
- query << " and #{opt} = '#{val}'"
673
- end
674
- }
675
-
676
- if usr.kind_of?(Fixnum)
677
- query << " and sid like '%-#{usr}'"
678
- else
679
- query << " and name = '#{usr}'"
680
- end
681
-
682
- domain = options[:domain] || host
683
-
684
- wmi.execquery(query).each{ |user|
685
- uid = user.sid.split('-').last.to_i
686
-
687
- # Because our 'like' query isn't fulproof, let's parse
688
- # the SID again to make sure
689
- if usr.kind_of?(Fixnum)
690
- next if usr != uid
691
- end
692
-
693
- user_object = User.new do |u|
694
- u.account_type = user.accounttype
695
- u.caption = user.caption
696
- u.description = user.description
697
- u.disabled = user.disabled
698
- u.domain = user.domain
699
- u.full_name = user.fullname
700
- u.install_date = user.installdate
701
- u.local = user.localaccount
702
- u.lockout = user.lockout
703
- u.name = user.name
704
- u.password_changeable = user.passwordchangeable
705
- u.password_expires = user.passwordexpires
706
- u.password_required = user.passwordrequired
707
- u.sid = user.sid
708
- u.sid_type = user.sidtype
709
- u.status = user.status
710
- u.uid = uid
711
- u.groups = get_groups(domain, user.name)
712
- u.dir = get_home_dir(user.name, options[:localaccount], domain)
713
- end
714
-
715
- return user_object
716
- }
717
-
718
- # If we're here, it means it wasn't found.
719
- raise Error, "no user found for '#{usr}'"
614
+ length = nsize.unpack('L')[0]
615
+ username = buffer[0 ... length].chop
616
+ username
617
+ end
618
+
619
+ # Returns a User object based on either +name+ or +uid+.
620
+ #
621
+ # call-seq:
622
+ # Sys::Admin.get_user(name, options = {})
623
+ # Sys::Admin.get_user(uid, options = {})
624
+ #
625
+ # Looks for +usr+ information based on the options you specify, where
626
+ # the +usr+ argument can be either a user name or a RID.
627
+ #
628
+ # If a 'host' option is specified, information is retrieved from that
629
+ # host. Otherwise, the local host is used.
630
+ #
631
+ # All other options are converted to WQL statements against the
632
+ # Win32_UserAccount WMI object. See http://tinyurl.com/by9nvn for a
633
+ # list of possible options.
634
+ #
635
+ # Examples:
636
+ #
637
+ # # Get a user by name
638
+ # Admin.get_user('djberge')
639
+ #
640
+ # # Get a user by uid
641
+ # Admin.get_user(100)
642
+ #
643
+ # # Get a user on a specific domain
644
+ # Admin.get_user('djberge', :domain => 'TEST')
645
+ #--
646
+ # The reason for keeping the +usr+ variable as a separate argument
647
+ # instead of rolling it into the options hash was to keep a unified
648
+ # API between the Windows and UNIX versions.
649
+ #
650
+ def self.get_user(usr, options = {})
651
+ options = munge_options(options)
652
+
653
+ host = options.delete(:host) || Socket.gethostname
654
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
655
+ cs << "//#{host}/root/cimv2"
656
+
657
+ begin
658
+ wmi = WIN32OLE.connect(cs)
659
+ rescue WIN32OLERuntimeError => err
660
+ raise Error, err
661
+ end
662
+
663
+ query = "select * from win32_useraccount"
664
+
665
+ i = 0
666
+
667
+ options.each{ |opt, val|
668
+ if i == 0
669
+ query << " where #{opt} = '#{val}'"
670
+ i += 1
671
+ else
672
+ query << " and #{opt} = '#{val}'"
673
+ end
674
+ }
675
+
676
+ if usr.kind_of?(Fixnum)
677
+ query << " and sid like '%-#{usr}'"
678
+ else
679
+ if i > 0
680
+ query << " and name = '#{usr}'"
681
+ else
682
+ query << " where name = '#{usr}'"
683
+ end
720
684
  end
685
+
686
+ domain = options[:domain] || host
687
+
688
+ wmi.execquery(query).each{ |user|
689
+ uid = user.sid.split('-').last.to_i
690
+
691
+ # Because our 'like' query isn't fulproof, let's parse
692
+ # the SID again to make sure
693
+ if usr.kind_of?(Fixnum)
694
+ next if usr != uid
695
+ end
696
+
697
+ user_object = User.new do |u|
698
+ u.account_type = user.accounttype
699
+ u.caption = user.caption
700
+ u.description = user.description
701
+ u.disabled = user.disabled
702
+ u.domain = user.domain
703
+ u.full_name = user.fullname
704
+ u.install_date = user.installdate
705
+ u.local = user.localaccount
706
+ u.lockout = user.lockout
707
+ u.name = user.name
708
+ u.password_changeable = user.passwordchangeable
709
+ u.password_expires = user.passwordexpires
710
+ u.password_required = user.passwordrequired
711
+ u.sid = user.sid
712
+ u.sid_type = user.sidtype
713
+ u.status = user.status
714
+ u.uid = uid
715
+ u.groups = get_groups(domain, user.name)
716
+ u.dir = get_home_dir(user.name, options[:localaccount], domain)
717
+ end
718
+
719
+ return user_object
720
+ }
721
+
722
+ # If we're here, it means it wasn't found.
723
+ raise Error, "no user found for '#{usr}'"
724
+ end
721
725
 
722
- # In block form, yields a User object for each user on the system. In
723
- # non-block form, returns an Array of User objects.
724
- #
725
- # call-seq:
726
- # Sys::Admin.users(options = {})
727
- # Sys::Admin.users(options = {}){ |user| ... }
728
- #
729
- # You may specify a host from which information is retrieved. The
730
- # default is the local host.
731
- #
732
- # All other arguments are passed as WQL query parameters against
733
- # the Win32_UserAccont WMI object.
734
- #
735
- # Examples:
736
- #
737
- # # Get all local account users
738
- # Sys::Admin.users(:localaccount => true)
739
- #
740
- # # Get all user accounts on a specific domain
741
- # Sys::Admin.users(:domain => 'FOO')
742
- #
743
- # # Get a single user from a domain
744
- # Sys::Admin.users(:name => 'djberge', :domain => 'FOO')
745
- #
746
- def self.users(options = {})
747
- options = munge_options(options)
748
-
749
- host = options.delete(:host) || Socket.gethostname
750
- cs = "winmgmts:{impersonationLevel=impersonate}!"
751
- cs << "//#{host}/root/cimv2"
752
-
753
- begin
754
- wmi = WIN32OLE.connect(cs)
755
- rescue WIN32OLERuntimeError => e
756
- raise Error, e
757
- end
758
-
759
- query = "select * from win32_useraccount"
760
-
761
- i = 0
762
-
763
- options.each{ |opt, val|
764
- if i == 0
765
- query << " where #{opt} = '#{val}'"
766
- i += 1
767
- else
768
- query << " and #{opt} = '#{val}'"
769
- end
770
- }
771
-
772
- array = []
773
- domain = options[:domain] || host
774
-
775
- wmi.execquery(query).each{ |user|
776
- uid = user.sid.split('-').last.to_i
777
-
778
- usr = User.new do |u|
779
- u.account_type = user.accounttype
780
- u.caption = user.caption
781
- u.description = user.description
782
- u.disabled = user.disabled
783
- u.domain = user.domain
784
- u.full_name = user.fullname
785
- u.install_date = user.installdate
786
- u.local = user.localaccount
787
- u.lockout = user.lockout
788
- u.name = user.name
789
- u.password_changeable = user.passwordchangeable
790
- u.password_expires = user.passwordexpires
791
- u.password_required = user.passwordrequired
792
- u.sid = user.sid
793
- u.sid_type = user.sidtype
794
- u.status = user.status
795
- u.groups = get_groups(domain, user.name)
796
- u.uid = uid
797
- u.dir = get_home_dir(user.name, options[:localaccount], host)
798
- end
799
-
800
- if block_given?
801
- yield usr
802
- else
803
- array.push(usr)
804
- end
805
- }
806
-
807
- return array unless block_given?
726
+ # In block form, yields a User object for each user on the system. In
727
+ # non-block form, returns an Array of User objects.
728
+ #
729
+ # call-seq:
730
+ # Sys::Admin.users(options = {})
731
+ # Sys::Admin.users(options = {}){ |user| ... }
732
+ #
733
+ # You may specify a host from which information is retrieved. The
734
+ # default is the local host.
735
+ #
736
+ # All other arguments are passed as WQL query parameters against
737
+ # the Win32_UserAccont WMI object.
738
+ #
739
+ # Examples:
740
+ #
741
+ # # Get all local account users
742
+ # Sys::Admin.users(:localaccount => true)
743
+ #
744
+ # # Get all user accounts on a specific domain
745
+ # Sys::Admin.users(:domain => 'FOO')
746
+ #
747
+ # # Get a single user from a domain
748
+ # Sys::Admin.users(:name => 'djberge', :domain => 'FOO')
749
+ #
750
+ def self.users(options = {})
751
+ options = munge_options(options)
752
+
753
+ host = options.delete(:host) || Socket.gethostname
754
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
755
+ cs << "//#{host}/root/cimv2"
756
+
757
+ begin
758
+ wmi = WIN32OLE.connect(cs)
759
+ rescue WIN32OLERuntimeError => e
760
+ raise Error, e
808
761
  end
762
+
763
+ query = "select * from win32_useraccount"
764
+
765
+ i = 0
766
+
767
+ options.each{ |opt, val|
768
+ if i == 0
769
+ query << " where #{opt} = '#{val}'"
770
+ i += 1
771
+ else
772
+ query << " and #{opt} = '#{val}'"
773
+ end
774
+ }
775
+
776
+ array = []
777
+ domain = options[:domain] || host
778
+
779
+ wmi.execquery(query).each{ |user|
780
+ uid = user.sid.split('-').last.to_i
781
+
782
+ usr = User.new do |u|
783
+ u.account_type = user.accounttype
784
+ u.caption = user.caption
785
+ u.description = user.description
786
+ u.disabled = user.disabled
787
+ u.domain = user.domain
788
+ u.full_name = user.fullname
789
+ u.install_date = user.installdate
790
+ u.local = user.localaccount
791
+ u.lockout = user.lockout
792
+ u.name = user.name
793
+ u.password_changeable = user.passwordchangeable
794
+ u.password_expires = user.passwordexpires
795
+ u.password_required = user.passwordrequired
796
+ u.sid = user.sid
797
+ u.sid_type = user.sidtype
798
+ u.status = user.status
799
+ u.groups = get_groups(domain, user.name)
800
+ u.uid = uid
801
+ u.dir = get_home_dir(user.name, options[:localaccount], host)
802
+ end
803
+
804
+ if block_given?
805
+ yield usr
806
+ else
807
+ array.push(usr)
808
+ end
809
+ }
810
+
811
+ return array unless block_given?
812
+ end
809
813
 
810
- # Returns a Group object based on either +name+ or +gid+.
811
- #
812
- # call-seq:
813
- # Sys::Admin.get_group(name, options = {})
814
- # Sys::Admin.get_group(gid, options = {})
815
- #
816
- # If a numeric value is sent as the first parameter, it is treated
817
- # as a RID and is checked against the SID for a match.
818
- #
819
- # You may specify a host as an option from which information is
820
- # retrieved. The default is the local host.
821
- #
822
- # All other options are passed as WQL parameters to the Win32_Group
823
- # WMI object. See http://tinyurl.com/bngc8s for a list of possible
824
- # options.
825
- #
826
- # Examples:
827
- #
828
- # # Find a group by name
829
- # Sys::Admin.get_group('Web Team')
830
- #
831
- # # Find a group by id
832
- # Sys::Admin.get_group(31667)
833
- #
834
- # # Find a group on a specific domain
835
- # Sys::Admin.get_group('Web Team', :domain => 'FOO')
836
- #
837
- def self.get_group(grp, options = {})
838
- options = munge_options(options)
839
-
840
- host = options.delete(:host) || Socket.gethostname
841
- cs = "winmgmts:{impersonationLevel=impersonate}!"
842
- cs << "//#{host}/root/cimv2"
843
-
844
- begin
845
- wmi = WIN32OLE.connect(cs)
846
- rescue WIN32OLERuntimeError => err
847
- raise Error, err
848
- end
849
-
850
- query = "select * from win32_group"
851
-
852
- i = 0
853
-
854
- options.each{ |opt, val|
855
- if i == 0
856
- query << " where #{opt} = '#{val}'"
857
- i += 1
858
- else
859
- query << " and #{opt} = '#{val}'"
860
- end
861
- }
862
-
863
- if grp.kind_of?(Fixnum)
864
- query << " and sid like '%-#{grp}'"
865
- else
866
- query << " and name = '#{grp}'"
867
- end
868
-
869
- domain = options[:domain] || host
870
-
871
- wmi.execquery(query).each{ |group|
872
- gid = group.sid.split("-").last.to_i
873
-
874
- # Because our 'like' query isn't fulproof, let's parse
875
- # the SID again to make sure
876
- if grp.kind_of?(Fixnum)
877
- next if grp != gid
878
- end
879
-
880
- group_object = Group.new do |g|
881
- g.caption = group.caption
882
- g.description = group.description
883
- g.domain = group.domain
884
- g.gid = gid
885
- g.install_date = group.installdate
886
- g.local = group.localaccount
887
- g.name = group.name
888
- g.sid = group.sid
889
- g.sid_type = group.sidtype
890
- g.status = group.status
891
- g.members = get_members(domain, group.name)
892
- end
893
-
894
- return group_object
895
- }
896
-
897
- # If we're here, it means it wasn't found.
898
- raise Error, "no group found for '#{grp}'"
814
+ # Returns a Group object based on either +name+ or +gid+.
815
+ #
816
+ # call-seq:
817
+ # Sys::Admin.get_group(name, options = {})
818
+ # Sys::Admin.get_group(gid, options = {})
819
+ #
820
+ # If a numeric value is sent as the first parameter, it is treated
821
+ # as a RID and is checked against the SID for a match.
822
+ #
823
+ # You may specify a host as an option from which information is
824
+ # retrieved. The default is the local host.
825
+ #
826
+ # All other options are passed as WQL parameters to the Win32_Group
827
+ # WMI object. See http://tinyurl.com/bngc8s for a list of possible
828
+ # options.
829
+ #
830
+ # Examples:
831
+ #
832
+ # # Find a group by name
833
+ # Sys::Admin.get_group('Web Team')
834
+ #
835
+ # # Find a group by id
836
+ # Sys::Admin.get_group(31667)
837
+ #
838
+ # # Find a group on a specific domain
839
+ # Sys::Admin.get_group('Web Team', :domain => 'FOO')
840
+ #
841
+ def self.get_group(grp, options = {})
842
+ options = munge_options(options)
843
+
844
+ host = options.delete(:host) || Socket.gethostname
845
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
846
+ cs << "//#{host}/root/cimv2"
847
+
848
+ begin
849
+ wmi = WIN32OLE.connect(cs)
850
+ rescue WIN32OLERuntimeError => err
851
+ raise Error, err
852
+ end
853
+
854
+ query = "select * from win32_group"
855
+
856
+ i = 0
857
+
858
+ options.each{ |opt, val|
859
+ if i == 0
860
+ query << " where #{opt} = '#{val}'"
861
+ i += 1
862
+ else
863
+ query << " and #{opt} = '#{val}'"
864
+ end
865
+ }
866
+
867
+ if grp.kind_of?(Fixnum)
868
+ query << " and sid like '%-#{grp}'"
869
+ else
870
+ if i > 0
871
+ query << " and name = '#{grp}'"
872
+ else
873
+ query << " where name = '#{grp}'"
874
+ end
899
875
  end
876
+
877
+ domain = options[:domain] || host
878
+
879
+ wmi.execquery(query).each{ |group|
880
+ gid = group.sid.split("-").last.to_i
881
+
882
+ # Because our 'like' query isn't fulproof, let's parse
883
+ # the SID again to make sure
884
+ if grp.kind_of?(Fixnum)
885
+ next if grp != gid
886
+ end
887
+
888
+ group_object = Group.new do |g|
889
+ g.caption = group.caption
890
+ g.description = group.description
891
+ g.domain = group.domain
892
+ g.gid = gid
893
+ g.install_date = group.installdate
894
+ g.local = group.localaccount
895
+ g.name = group.name
896
+ g.sid = group.sid
897
+ g.sid_type = group.sidtype
898
+ g.status = group.status
899
+ g.members = get_members(domain, group.name)
900
+ end
901
+
902
+ return group_object
903
+ }
904
+
905
+ # If we're here, it means it wasn't found.
906
+ raise Error, "no group found for '#{grp}'"
907
+ end
900
908
 
901
- # In block form, yields a Group object for each user on the system. In
902
- # non-block form, returns an Array of Group objects.
903
- #
904
- # call-seq:
905
- # groups(options = {})
906
- # groups(options = {}){ |group| ... }
907
- #
908
- # You may specify a host option from which information is retrieved.
909
- # The default is the local host.
910
- #
911
- # All other options are passed as WQL parameters to the Win32_Group
912
- # WMI object. See http://tinyurl.com/bngc8s for a list of possible
913
- # options.
914
- #
915
- # Examples:
916
- #
917
- # # Get local group information
918
- # Sys::Admin.groups(:localaccount => true)
919
- #
920
- # # Get all groups on a specific domain
921
- # Sys::Admin.groups(:domain => 'FOO')
922
- #
923
- # # Get a specific group on a domain
924
- # Sys::Admin.groups(:name => 'Some Group', :domain => 'FOO')
925
- #
926
- def self.groups(options = {})
927
- options = munge_options(options)
928
-
929
- host = options.delete(:host) || Socket.gethostname
930
- cs = "winmgmts:{impersonationLevel=impersonate}!"
931
- cs << "//#{host}/root/cimv2"
932
-
933
- begin
934
- wmi = WIN32OLE.connect(cs)
935
- rescue WIN32OLERuntimeError => err
936
- raise Error, err
937
- end
938
-
939
- query = "select * from win32_group"
940
-
941
- i = 0
942
-
943
- options.each{ |opt, val|
944
- if i == 0
945
- query << " where #{opt} = '#{val}'"
946
- i += 1
947
- else
948
- query << " and #{opt} = '#{val}'"
949
- end
950
- }
951
-
952
- array = []
953
- domain = options[:domain] || host
954
-
955
- wmi.execquery(query).each{ |group|
956
- grp = Group.new do |g|
957
- g.caption = group.caption
958
- g.description = group.description
959
- g.domain = group.domain
960
- g.gid = group.sid.split("-").last.to_i
961
- g.install_date = group.installdate
962
- g.local = group.localaccount
963
- g.name = group.name
964
- g.sid = group.sid
965
- g.sid_type = group.sidtype
966
- g.status = group.status
967
- g.members = get_members(domain, group.name)
968
- end
969
-
970
- if block_given?
971
- yield grp
972
- else
973
- array.push(grp)
974
- end
975
- }
976
-
977
- return array unless block_given?
909
+ # In block form, yields a Group object for each user on the system. In
910
+ # non-block form, returns an Array of Group objects.
911
+ #
912
+ # call-seq:
913
+ # groups(options = {})
914
+ # groups(options = {}){ |group| ... }
915
+ #
916
+ # You may specify a host option from which information is retrieved.
917
+ # The default is the local host.
918
+ #
919
+ # All other options are passed as WQL parameters to the Win32_Group
920
+ # WMI object. See http://tinyurl.com/bngc8s for a list of possible
921
+ # options.
922
+ #
923
+ # Examples:
924
+ #
925
+ # # Get local group information
926
+ # Sys::Admin.groups(:localaccount => true)
927
+ #
928
+ # # Get all groups on a specific domain
929
+ # Sys::Admin.groups(:domain => 'FOO')
930
+ #
931
+ # # Get a specific group on a domain
932
+ # Sys::Admin.groups(:name => 'Some Group', :domain => 'FOO')
933
+ #
934
+ def self.groups(options = {})
935
+ options = munge_options(options)
936
+
937
+ host = options.delete(:host) || Socket.gethostname
938
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
939
+ cs << "//#{host}/root/cimv2"
940
+
941
+ begin
942
+ wmi = WIN32OLE.connect(cs)
943
+ rescue WIN32OLERuntimeError => err
944
+ raise Error, err
978
945
  end
979
- end
946
+
947
+ query = "select * from win32_group"
948
+
949
+ i = 0
950
+
951
+ options.each{ |opt, val|
952
+ if i == 0
953
+ query << " where #{opt} = '#{val}'"
954
+ i += 1
955
+ else
956
+ query << " and #{opt} = '#{val}'"
957
+ end
958
+ }
959
+
960
+ array = []
961
+ domain = options[:domain] || host
962
+
963
+ wmi.execquery(query).each{ |group|
964
+ grp = Group.new do |g|
965
+ g.caption = group.caption
966
+ g.description = group.description
967
+ g.domain = group.domain
968
+ g.gid = group.sid.split("-").last.to_i
969
+ g.install_date = group.installdate
970
+ g.local = group.localaccount
971
+ g.name = group.name
972
+ g.sid = group.sid
973
+ g.sid_type = group.sidtype
974
+ g.status = group.status
975
+ g.members = get_members(domain, group.name)
976
+ end
977
+
978
+ if block_given?
979
+ yield grp
980
+ else
981
+ array.push(grp)
982
+ end
983
+ }
984
+
985
+ return array unless block_given?
986
+ end
987
+ end
980
988
  end