class Puppet::Util::Windows::ADSI::User

Constants

ADS_USERFLAGS

Declare all of the available user flags on the system. Note that ADS_UF is read as ADS_UserFlag

https://docs.microsoft.com/en-us/windows/desktop/api/iads/ne-iads-ads_user_flag

and

https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro

for the flag values.

MAX_USERNAME_LENGTH

UNLEN from lmcons.h - stackoverflow.com/a/2155176

NameCanonical
NameCanonicalEx
NameDisplay
NameDnsDomain
NameFullyQualifiedDN
NameGivenName
NameSamCompatible
NameServicePrincipal
NameSurname
NameUniqueId
NameUnknown

docs.microsoft.com/en-us/windows/win32/api/secext/ne-secext-extended_name_format

NameUserPrincipal

Public Class Methods

create(name) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
312 def create(name)
313   # Windows error 1379: The specified local group already exists.
314   raise Puppet::Error.new(_("Cannot create user if group '%{name}' exists.") % { name: name }) if Puppet::Util::Windows::ADSI::Group.exists? name
315   new(name, Puppet::Util::Windows::ADSI.create(name, @object_class))
316 end
current_sam_compatible_user_name() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
541 def self.current_sam_compatible_user_name
542   current_user_name_with_format(NameSamCompatible)
543 end
current_user_name() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
490 def self.current_user_name
491   user_name = String.new
492   max_length = MAX_USERNAME_LENGTH + 1 # NULL terminated
493   FFI::MemoryPointer.new(max_length * 2) do |buffer| # wide string
494     FFI::MemoryPointer.new(:dword, 1) do |buffer_size|
495       buffer_size.write_dword(max_length) # length in TCHARs
496 
497       if GetUserNameW(buffer, buffer_size) == FFI::WIN32_FALSE
498         raise Puppet::Util::Windows::Error.new(_("Failed to get user name"))
499       end
500       # buffer_size includes trailing NULL
501       user_name = buffer.read_wide_string(buffer_size.read_dword - 1)
502     end
503   end
504 
505   user_name
506 end
current_user_name_with_format(format) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
522 def self.current_user_name_with_format(format)
523   user_name = String.new
524   max_length = 1024
525 
526   FFI::MemoryPointer.new(:lpwstr, max_length * 2 + 1) do |buffer|
527     FFI::MemoryPointer.new(:dword, 1) do |buffer_size|
528       buffer_size.write_dword(max_length + 1)
529 
530       if GetUserNameExW(format.to_i, buffer, buffer_size) == FFI::WIN32_FALSE
531         raise Puppet::Util::Windows::Error.new(_("Failed to get user name"), FFI.errno)
532       end
533 
534       user_name = buffer.read_wide_string(buffer_size.read_dword).chomp
535     end
536   end
537 
538   user_name
539 end
current_user_sid() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
545 def self.current_user_sid
546   Puppet::Util::Windows::SID.name_to_principal(current_user_name)
547 end
list_all() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
304 def list_all
305   Puppet::Util::Windows::ADSI.execquery('select name from win32_useraccount where localaccount = "TRUE"')
306 end
logon(name, password) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
308 def logon(name, password)
309   Puppet::Util::Windows::User.password_is?(name, password)
310 end

Public Instance Methods

add_flag(flag_name, value) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
323 def add_flag(flag_name, value)
324   flag = native_object.Get(flag_name) rescue 0
325 
326   native_object.Put(flag_name, flag | value)
327 
328   commit
329 end
add_group_sids(*sids) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
365 def add_group_sids(*sids)
366   group_names = sids.map { |s| s.domain_account }
367   add_to_groups(*group_names)
368 end
add_to_group(*group_names)
Alias for: add_to_groups
add_to_groups(*group_names) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
350 def add_to_groups(*group_names)
351   group_names.each do |group_name|
352     Puppet::Util::Windows::ADSI::Group.new(group_name).add_member_sids(sid)
353   end
354 end
Also aliased as: add_to_group
disabled?() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
468 def disabled?
469   userflag_set?(:ADS_UF_ACCOUNTDISABLE)
470 end
expired?() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
479 def expired?
480   expires = native_object.Get('AccountExpirationDate')
481   expires && expires < Time.now
482 rescue WIN32OLERuntimeError => e
483   # This OLE error code indicates the property can't be found in the cache
484   raise e unless e.message =~ /8000500D/m
485   false
486 end
group_sids() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
375 def group_sids
376   self.class.get_sids(native_object.Groups)
377 end
groups() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
341 def groups
342   # https://msdn.microsoft.com/en-us/library/aa746342.aspx
343   # WIN32OLE objects aren't enumerable, so no map
344   groups = []
345   # Setting WIN32OLE.codepage ensures values are returned as UTF-8
346   native_object.Groups.each {|g| groups << g.Name} rescue nil
347   groups
348 end
locked_out?() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
472 def locked_out?
473   # Note that the LOCKOUT flag is known to be inaccurate when using the
474   # LDAP IADsUser provider, but this class consistently uses the WinNT
475   # provider, which is expected to be accurate.
476   userflag_set?(:ADS_UF_LOCKOUT)
477 end
op_userflags(*flags, &block) click to toggle source

Common helper for set_userflags and unset_userflags.

@api private

    # File lib/puppet/util/windows/adsi.rb
448 def op_userflags(*flags, &block)
449   # Avoid an unnecessary set + commit operation.
450   return if flags.empty?
451 
452   unrecognized_flags = flags.reject { |flag| ADS_USERFLAGS.keys.include?(flag) }
453   unless unrecognized_flags.empty?
454     raise ArgumentError, _("Unrecognized ADS UserFlags: %{unrecognized_flags}") % { unrecognized_flags: unrecognized_flags.join(', ') }
455   end
456 
457   self['UserFlags'] = flags.inject(self['UserFlags'], &block)
458 end
password=(password) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
331 def password=(password)
332   if !password.nil?
333     native_object.SetPassword(password)
334     commit
335   end
336 
337   fADS_UF_DONT_EXPIRE_PASSWD = 0x10000
338   add_flag("UserFlags", fADS_UF_DONT_EXPIRE_PASSWD)
339 end
password_is?(password) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
319 def password_is?(password)
320   self.class.logon(name, password)
321 end
remove_from_group(*group_names)
Alias for: remove_from_groups
remove_from_groups(*group_names) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
357 def remove_from_groups(*group_names)
358   group_names.each do |group_name|
359     Puppet::Util::Windows::ADSI::Group.new(group_name).remove_member_sids(sid)
360   end
361 end
Also aliased as: remove_from_group
remove_group_sids(*sids) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
370 def remove_group_sids(*sids)
371   group_names = sids.map { |s| s.domain_account }
372   remove_from_groups(*group_names)
373 end
set_groups(desired_groups, minimum = true) click to toggle source

TODO: This code's pretty similar to set_members in the Group class. Would be nice to refactor them into the ADSIObject class at some point. This was not done originally because these use different methods to do stuff that are also aliased to other methods, so the shared code isn't exactly a 1:1 mapping.

    # File lib/puppet/util/windows/adsi.rb
383 def set_groups(desired_groups, minimum = true)
384   return if desired_groups.nil?
385 
386   desired_groups = desired_groups.split(',').map(&:strip)
387 
388   current_hash = Hash[ self.group_sids.map { |sid| [sid.sid, sid] } ]
389   desired_hash = self.class.name_sid_hash(desired_groups)
390 
391   # First we add the user to all the groups it should be in but isn't
392   if !desired_groups.empty?
393     groups_to_add = (desired_hash.keys - current_hash.keys).map { |sid| desired_hash[sid] }
394     add_group_sids(*groups_to_add)
395   end
396 
397   # Then we remove the user from all groups it is in but shouldn't be, if
398   # that's been requested
399   if !minimum
400     if desired_hash.empty?
401       groups_to_remove = current_hash.values
402     else
403       groups_to_remove = (current_hash.keys - desired_hash.keys).map { |sid| current_hash[sid] }
404     end
405 
406     remove_group_sids(*groups_to_remove)
407   end
408 end
set_userflags(*flags) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
460 def set_userflags(*flags)
461   op_userflags(*flags) { |userflags, flag| userflags | ADS_USERFLAGS[flag] }
462 end
unset_userflags(*flags) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
464 def unset_userflags(*flags)
465   op_userflags(*flags) { |userflags, flag| userflags & ~ADS_USERFLAGS[flag] }
466 end
userflag_set?(flag) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
440 def userflag_set?(flag)
441   flag_value = ADS_USERFLAGS[flag] || 0
442   ! (self['UserFlags'] & flag_value).zero?
443 end