Server IP : 85.214.239.14 / Your IP : 3.129.210.35 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/microsoft/ad/plugins/modules/ |
Upload File : |
#!powershell # Copyright: (c) 2022, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #AnsibleRequires -CSharpUtil Ansible.Basic #AnsibleRequires -PowerShell Ansible.ModuleUtils.AddType $spec = @{ options = @{ domain_password = @{ type = 'str'; no_log = $true } domain_server = @{ type = 'str' } domain_username = @{ type = 'str' } filter = @{ type = 'str' } identity = @{ type = 'str' } include_deleted = @{ type = 'bool'; default = $false } ldap_filter = @{ type = 'str' } properties = @{ type = 'list'; elements = 'str' } search_base = @{ type = 'str' } search_scope = @{ type = 'str'; choices = @('base', 'one_level', 'subtree') } } supports_check_mode = $true mutually_exclusive = @( @('filter', 'identity', 'ldap_filter'), @('identity', 'search_base'), @('identity', 'search_scope') ) required_one_of = @( , @('filter', 'identity', 'ldap_filter') ) required_together = @(, @('domain_username', 'domain_password')) } $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) $module.Result.objects = @() # Always ensure this is returned even in a failure. $domainServer = $module.Params.domain_server $domainPassword = $module.Params.domain_password $domainUsername = $module.Params.domain_username $filter = $module.Params.filter $identity = $module.Params.identity $includeDeleted = $module.Params.include_deleted $ldapFilter = $module.Params.ldap_filter $properties = $module.Params.properties $searchBase = $module.Params.search_base $searchScope = $module.Params.search_scope $credential = $null if ($domainUsername) { $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @( $domainUsername, (ConvertTo-SecureString -AsPlainText -Force -String $domainPassword) ) } Add-CSharpType -AnsibleModule $module -References @' using System; namespace Ansible.WinDomainObjectInfo { [Flags] public enum GroupType : uint { GROUP_TYPE_BUILTIN_LOCAL_GROUP = 0x00000001, GROUP_TYPE_ACCOUNT_GROUP = 0x00000002, GROUP_TYPE_RESOURCE_GROUP = 0x00000004, GROUP_TYPE_UNIVERSAL_GROUP = 0x00000008, GROUP_TYPE_APP_BASIC_GROUP = 0x00000010, GROUP_TYPE_APP_QUERY_GROUP = 0x00000020, GROUP_TYPE_SECURITY_ENABLED = 0x80000000, } [Flags] public enum UserAccountControl : int { ADS_UF_SCRIPT = 0x00000001, ADS_UF_ACCOUNTDISABLE = 0x00000002, ADS_UF_HOMEDIR_REQUIRED = 0x00000008, ADS_UF_LOCKOUT = 0x00000010, ADS_UF_PASSWD_NOTREQD = 0x00000020, ADS_UF_PASSWD_CANT_CHANGE = 0x00000040, ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x00000080, ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0x00000100, ADS_UF_NORMAL_ACCOUNT = 0x00000200, ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 0x00000800, ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x00001000, ADS_UF_SERVER_TRUST_ACCOUNT = 0x00002000, ADS_UF_DONT_EXPIRE_PASSWD = 0x00010000, ADS_UF_MNS_LOGON_ACCOUNT = 0x00020000, ADS_UF_SMARTCARD_REQUIRED = 0x00040000, ADS_UF_TRUSTED_FOR_DELEGATION = 0x00080000, ADS_UF_NOT_DELEGATED = 0x00100000, ADS_UF_USE_DES_KEY_ONLY = 0x00200000, ADS_UF_DONT_REQUIRE_PREAUTH = 0x00400000, ADS_UF_PASSWORD_EXPIRED = 0x00800000, ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x01000000, } [Flags] public enum SupportedEncryptionTypes : int { None = 0x00, DES_CBC_CRC = 0x01, DES_CBC_MD5 = 0x02, RC4_HMAC = 0x04, AES128_CTS_HMAC_SHA1_96 = 0x08, AES256_CTS_HMAC_SHA1_96 = 0x10, } public enum sAMAccountType : int { SAM_DOMAIN_OBJECT = 0x00000000, SAM_GROUP_OBJECT = 0x10000000, SAM_NON_SECURITY_GROUP_OBJECT = 0x10000001, SAM_ALIAS_OBJECT = 0x20000000, SAM_NON_SECURITY_ALIAS_OBJECT = 0x20000001, SAM_USER_OBJECT = 0x30000000, SAM_NORMAL_USER_ACCOUNT = 0x30000000, SAM_MACHINE_ACCOUNT = 0x30000001, SAM_TRUST_ACCOUNT = 0x30000002, SAM_APP_BASIC_GROUP = 0x40000000, SAM_APP_QUERY_GROUP = 0x40000001, SAM_ACCOUNT_TYPE_MAX = 0x7fffffff, } } '@ Function ConvertTo-OutputValue { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [AllowNull()] [Object] $InputObject ) if ($InputObject -is [System.Security.Principal.SecurityIdentifier]) { # Syntax: SID - Only serialize the SID as a string and not the other metadata properties. $sidInfo = @{ Sid = $InputObject.Value } # Try and map the SID to the account name, this may fail if the SID is invalid or not mappable. try { $sidInfo.Name = $InputObject.Translate([System.Security.Principal.NTAccount]).Value } catch [System.Security.Principal.IdentityNotMappedException] { $sidInfo.Name = $null } $sidInfo } elseif ($InputObject -is [Byte[]]) { # Syntax: Octet String - By default will serialize as a list of decimal values per byte, instead return a # Base64 string as Ansible can easily parse that. [System.Convert]::ToBase64String($InputObject) } elseif ($InputObject -is [DateTime]) { # Syntax: UTC Coded Time - .NET DateTimes serialized as in the form "Date(FILETIME)" which isn't easily # parsable by Ansible, instead return as an ISO 8601 string in the UTC timezone. [TimeZoneInfo]::ConvertTimeToUtc($InputObject).ToString("o") } elseif ($InputObject -is [System.Security.AccessControl.ObjectSecurity]) { # Complex object which isn't easily serializable. Instead we should just return the SDDL string. If a user # needs to parse this then they really need to reprocess the SDDL string and process their results on another # win_shell task. $InputObject.GetSecurityDescriptorSddlForm(([System.Security.AccessControl.AccessControlSections]::All)) } else { # Syntax: (All Others) - The default serialization handling of other syntaxes are fine, don't do anything. $InputObject } } <# Calling Get-ADObject that returns multiple objects with -Properties * will only return the properties that were set on the first found object. To counter this problem we will first call Get-ADObject to list all the objects that match the filter specified then get the properties on each object. #> $commonParams = @{ IncludeDeletedObjects = $includeDeleted } if ($credential) { $commonParams.Credential = $credential } if ($domainServer) { $commonParams.Server = $domainServer } # First get the IDs for all the AD objects that match the filter specified. $getParams = @{ Properties = @('DistinguishedName', 'ObjectGUID') } if ($filter) { $getParams.Filter = $filter } elseif ($identity) { $getParams.Identity = $identity } elseif ($ldapFilter) { $getParams.LDAPFilter = $ldapFilter } # Explicit check on $null as an empty string is different from not being set. if ($null -ne $searchBase) { $getParams.SearchBase = $searchbase } if ($searchScope) { $getParams.SearchScope = switch ($searchScope) { base { 'Base' } one_level { 'OneLevel' } subtree { 'Subtree' } } } try { # We run this in a custom PowerShell pipeline so that users of this module can't use any of the variables defined # above in their filter. While the cmdlet won't execute sub expressions we don't want anyone implicitly relying on # a defined variable in this module in case we ever change the name or remove it. $ps = [PowerShell]::Create() $null = $ps.AddCommand('Get-ADObject').AddParameters($commonParams).AddParameters($getParams) $null = $ps.AddCommand('Select-Object').AddParameter('Property', @('DistinguishedName', 'ObjectGUID')) $foundGuids = @($ps.Invoke()) } catch { # Because we ran in a pipeline we can't catch ADIdentityNotFoundException. Instead this scans each InnerException # to see if it contains ADIdentityNotFoundException. $exp = $_.Exception $foundGuids = $null while ($exp) { $exp = $exp.InnerException if ($exp -is [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]) { $foundGuids = @() break } } if ($null -eq $foundGuids) { # The exception is from the .Invoke() call, compare on the InnerException which was what was actually raised by # the pipeline. $innerException = $_.Exception.InnerException.InnerException if ($innerException -is [Microsoft.ActiveDirectory.Management.ADServerDownException]) { # Point users in the direction of the double hop problem as that is what is typically the cause of this. $msg = "Failed to contact the AD server, this could be caused by the double hop problem over WinRM. " $msg += "Try using the module with auth as Kerberos with credential delegation or CredSSP, become, or " $msg += "defining the domain_username and domain_password module parameters." $module.FailJson($msg, $innerException) } else { throw $innerException } } } $getParams = @{} if ($properties) { $getParams.Properties = $properties } $module.Result.objects = @(foreach ($adId in $foundGuids) { try { $adObject = Get-ADObject @commonParams @getParams -Identity $adId.ObjectGUID } catch { $msg = "Failed to retrieve properties for AD Object '$($adId.DistinguishedName)': $($_.Exception.Message)" $module.Warn($msg) continue } $propertyNames = $adObject.PropertyNames $propertyNames += ($properties | Where-Object { $_ -ne '*' }) # Now process each property to an easy to represent string $filteredObject = [Ordered]@{} foreach ($name in ($propertyNames | Sort-Object)) { # In the case of explicit properties that were asked for but weren't set, Get-ADObject won't actually return # the property so this is a defensive check against that scenario. if (-not $adObject.PSObject.Properties.Name.Contains($name)) { $filteredObject.$name = $null continue } $value = $adObject.$name if ($value -is [Microsoft.ActiveDirectory.Management.ADPropertyValueCollection]) { $value = foreach ($v in $value) { ConvertTo-OutputValue -InputObject $v } } else { $value = ConvertTo-OutputValue -InputObject $value } $filteredObject.$name = $value # For these 3 properties, add an _AnsibleFlags attribute which contains the enum strings that are set. $enumValue = switch ($name) { groupType { [Ansible.WinDomainObjectInfo.GroupType]$value } 'msDS-SupportedEncryptionTypes' { [Ansible.WinDomainObjectInfo.SupportedEncryptionTypes]$value } sAMAccountType { [Ansible.WinDomainObjectInfo.sAMAccountType]$value } userAccountControl { [Ansible.WinDomainObjectInfo.UserAccountControl]$value } } if ($null -ne $enumValue) { $filteredObject."$($name)_AnsibleFlags" = $enumValue.ToString() -split ', ' } } $filteredObject }) $module.ExitJson()