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

Public Instance Methods

add_flag(flag_name, value) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
322 def add_flag(flag_name, value)
323   flag = native_object.Get(flag_name) rescue 0
324 
325   native_object.Put(flag_name, flag | value)
326 
327   commit
328 end
add_group_sids(*sids) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
364 def add_group_sids(*sids)
365   group_names = sids.map { |s| s.domain_account }
366   add_to_groups(*group_names)
367 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
349 def add_to_groups(*group_names)
350   group_names.each do |group_name|
351     Puppet::Util::Windows::ADSI::Group.new(group_name).add_member_sids(sid)
352   end
353 end
Also aliased as: add_to_group
disabled?() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
467 def disabled?
468   userflag_set?(:ADS_UF_ACCOUNTDISABLE)
469 end
expired?() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
478 def expired?
479   expires = native_object.Get('AccountExpirationDate')
480   expires && expires < Time.now
481 rescue WIN32OLERuntimeError => e
482   # This OLE error code indicates the property can't be found in the cache
483   raise e unless e.message =~ /8000500D/m
484   false
485 end
group_sids() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
374 def group_sids
375   self.class.get_sids(native_object.Groups)
376 end
groups() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
340 def groups
341   # https://msdn.microsoft.com/en-us/library/aa746342.aspx
342   # WIN32OLE objects aren't enumerable, so no map
343   groups = []
344   # Setting WIN32OLE.codepage ensures values are returned as UTF-8
345   native_object.Groups.each {|g| groups << g.Name} rescue nil
346   groups
347 end
locked_out?() click to toggle source
    # File lib/puppet/util/windows/adsi.rb
471 def locked_out?
472   # Note that the LOCKOUT flag is known to be inaccurate when using the
473   # LDAP IADsUser provider, but this class consistently uses the WinNT
474   # provider, which is expected to be accurate.
475   userflag_set?(:ADS_UF_LOCKOUT)
476 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
447 def op_userflags(*flags, &block)
448   # Avoid an unnecessary set + commit operation.
449   return if flags.empty?
450 
451   unrecognized_flags = flags.reject { |flag| ADS_USERFLAGS.keys.include?(flag) }
452   unless unrecognized_flags.empty?
453     raise ArgumentError, _("Unrecognized ADS UserFlags: %{unrecognized_flags}") % { unrecognized_flags: unrecognized_flags.join(', ') }
454   end
455 
456   self['UserFlags'] = flags.inject(self['UserFlags'], &block)
457 end
password=(password) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
330 def password=(password)
331   if !password.nil?
332     native_object.SetPassword(password)
333     commit
334   end
335 
336   fADS_UF_DONT_EXPIRE_PASSWD = 0x10000
337   add_flag("UserFlags", fADS_UF_DONT_EXPIRE_PASSWD)
338 end
password_is?(password) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
318 def password_is?(password)
319   self.class.logon(name, password)
320 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
356 def remove_from_groups(*group_names)
357   group_names.each do |group_name|
358     Puppet::Util::Windows::ADSI::Group.new(group_name).remove_member_sids(sid)
359   end
360 end
Also aliased as: remove_from_group
remove_group_sids(*sids) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
369 def remove_group_sids(*sids)
370   group_names = sids.map { |s| s.domain_account }
371   remove_from_groups(*group_names)
372 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
382 def set_groups(desired_groups, minimum = true)
383   return if desired_groups.nil?
384 
385   desired_groups = desired_groups.split(',').map(&:strip)
386 
387   current_hash = Hash[ self.group_sids.map { |sid| [sid.sid, sid] } ]
388   desired_hash = self.class.name_sid_hash(desired_groups)
389 
390   # First we add the user to all the groups it should be in but isn't
391   if !desired_groups.empty?
392     groups_to_add = (desired_hash.keys - current_hash.keys).map { |sid| desired_hash[sid] }
393     add_group_sids(*groups_to_add)
394   end
395 
396   # Then we remove the user from all groups it is in but shouldn't be, if
397   # that's been requested
398   if !minimum
399     if desired_hash.empty?
400       groups_to_remove = current_hash.values
401     else
402       groups_to_remove = (current_hash.keys - desired_hash.keys).map { |sid| current_hash[sid] }
403     end
404 
405     remove_group_sids(*groups_to_remove)
406   end
407 end
set_userflags(*flags) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
459 def set_userflags(*flags)
460   op_userflags(*flags) { |userflags, flag| userflags | ADS_USERFLAGS[flag] }
461 end
unset_userflags(*flags) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
463 def unset_userflags(*flags)
464   op_userflags(*flags) { |userflags, flag| userflags & ~ADS_USERFLAGS[flag] }
465 end
userflag_set?(flag) click to toggle source
    # File lib/puppet/util/windows/adsi.rb
439 def userflag_set?(flag)
440   flag_value = ADS_USERFLAGS[flag] || 0
441   ! (self['UserFlags'] & flag_value).zero?
442 end