diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 16:04:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 16:04:21 +0000 |
commit | 8a754e0858d922e955e71b253c139e071ecec432 (patch) | |
tree | 527d16e74bfd1840c85efd675fdecad056c54107 /test/support/windows-integration/plugins/modules/win_user.ps1 | |
parent | Initial commit. (diff) | |
download | ansible-core-upstream/2.14.3.tar.xz ansible-core-upstream/2.14.3.zip |
Adding upstream version 2.14.3.upstream/2.14.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | test/support/windows-integration/plugins/modules/win_user.ps1 | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/test/support/windows-integration/plugins/modules/win_user.ps1 b/test/support/windows-integration/plugins/modules/win_user.ps1 new file mode 100644 index 0000000..54905cb --- /dev/null +++ b/test/support/windows-integration/plugins/modules/win_user.ps1 @@ -0,0 +1,273 @@ +#!powershell + +# Copyright: (c) 2014, Paul Durivage <paul.durivage@rackspace.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.AccessToken +#Requires -Module Ansible.ModuleUtils.Legacy + +######## +$ADS_UF_PASSWD_CANT_CHANGE = 64 +$ADS_UF_DONT_EXPIRE_PASSWD = 65536 + +$adsi = [ADSI]"WinNT://$env:COMPUTERNAME" + +function Get-User($user) { + $adsi.Children | Where-Object {$_.SchemaClassName -eq 'user' -and $_.Name -eq $user } + return +} + +function Get-UserFlag($user, $flag) { + If ($user.UserFlags[0] -band $flag) { + $true + } + Else { + $false + } +} + +function Set-UserFlag($user, $flag) { + $user.UserFlags = ($user.UserFlags[0] -BOR $flag) +} + +function Clear-UserFlag($user, $flag) { + $user.UserFlags = ($user.UserFlags[0] -BXOR $flag) +} + +function Get-Group($grp) { + $adsi.Children | Where-Object { $_.SchemaClassName -eq 'Group' -and $_.Name -eq $grp } + return +} + +Function Test-LocalCredential { + param([String]$Username, [String]$Password) + + try { + $handle = [Ansible.AccessToken.TokenUtil]::LogonUser($Username, $null, $Password, "Network", "Default") + $handle.Dispose() + $valid_credentials = $true + } catch [Ansible.AccessToken.Win32Exception] { + # following errors indicate the creds are correct but the user was + # unable to log on for other reasons, which we don't care about + $success_codes = @( + 0x0000052F, # ERROR_ACCOUNT_RESTRICTION + 0x00000530, # ERROR_INVALID_LOGON_HOURS + 0x00000531, # ERROR_INVALID_WORKSTATION + 0x00000569 # ERROR_LOGON_TYPE_GRANTED + ) + + if ($_.Exception.NativeErrorCode -eq 0x0000052E) { + # ERROR_LOGON_FAILURE - the user or pass was incorrect + $valid_credentials = $false + } elseif ($_.Exception.NativeErrorCode -in $success_codes) { + $valid_credentials = $true + } else { + # an unknown failure, reraise exception + throw $_ + } + } + return $valid_credentials +} + +######## + +$params = Parse-Args $args; + +$result = @{ + changed = $false +}; + +$username = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true +$fullname = Get-AnsibleParam -obj $params -name "fullname" -type "str" +$description = Get-AnsibleParam -obj $params -name "description" -type "str" +$password = Get-AnsibleParam -obj $params -name "password" -type "str" +$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent","query" +$update_password = Get-AnsibleParam -obj $params -name "update_password" -type "str" -default "always" -validateset "always","on_create" +$password_expired = Get-AnsibleParam -obj $params -name "password_expired" -type "bool" +$password_never_expires = Get-AnsibleParam -obj $params -name "password_never_expires" -type "bool" +$user_cannot_change_password = Get-AnsibleParam -obj $params -name "user_cannot_change_password" -type "bool" +$account_disabled = Get-AnsibleParam -obj $params -name "account_disabled" -type "bool" +$account_locked = Get-AnsibleParam -obj $params -name "account_locked" -type "bool" +$groups = Get-AnsibleParam -obj $params -name "groups" +$groups_action = Get-AnsibleParam -obj $params -name "groups_action" -type "str" -default "replace" -validateset "add","remove","replace" + +If ($null -ne $account_locked -and $account_locked) { + Fail-Json $result "account_locked must be set to 'no' if provided" +} + +If ($null -ne $groups) { + If ($groups -is [System.String]) { + [string[]]$groups = $groups.Split(",") + } + ElseIf ($groups -isnot [System.Collections.IList]) { + Fail-Json $result "groups must be a string or array" + } + $groups = $groups | ForEach-Object { ([string]$_).Trim() } | Where-Object { $_ } + If ($null -eq $groups) { + $groups = @() + } +} + +$user_obj = Get-User $username + +If ($state -eq 'present') { + # Add or update user + try { + If (-not $user_obj) { + $user_obj = $adsi.Create("User", $username) + If ($null -ne $password) { + $user_obj.SetPassword($password) + } + $user_obj.SetInfo() + $result.changed = $true + } + ElseIf (($null -ne $password) -and ($update_password -eq 'always')) { + # ValidateCredentials will fail if either of these are true- just force update... + If($user_obj.AccountDisabled -or $user_obj.PasswordExpired) { + $password_match = $false + } + Else { + try { + $password_match = Test-LocalCredential -Username $username -Password $password + } catch [System.ComponentModel.Win32Exception] { + Fail-Json -obj $result -message "Failed to validate the user's credentials: $($_.Exception.Message)" + } + } + + If (-not $password_match) { + $user_obj.SetPassword($password) + $result.changed = $true + } + } + If (($null -ne $fullname) -and ($fullname -ne $user_obj.FullName[0])) { + $user_obj.FullName = $fullname + $result.changed = $true + } + If (($null -ne $description) -and ($description -ne $user_obj.Description[0])) { + $user_obj.Description = $description + $result.changed = $true + } + If (($null -ne $password_expired) -and ($password_expired -ne ($user_obj.PasswordExpired | ConvertTo-Bool))) { + $user_obj.PasswordExpired = If ($password_expired) { 1 } Else { 0 } + $result.changed = $true + } + If (($null -ne $password_never_expires) -and ($password_never_expires -ne (Get-UserFlag $user_obj $ADS_UF_DONT_EXPIRE_PASSWD))) { + If ($password_never_expires) { + Set-UserFlag $user_obj $ADS_UF_DONT_EXPIRE_PASSWD + } + Else { + Clear-UserFlag $user_obj $ADS_UF_DONT_EXPIRE_PASSWD + } + $result.changed = $true + } + If (($null -ne $user_cannot_change_password) -and ($user_cannot_change_password -ne (Get-UserFlag $user_obj $ADS_UF_PASSWD_CANT_CHANGE))) { + If ($user_cannot_change_password) { + Set-UserFlag $user_obj $ADS_UF_PASSWD_CANT_CHANGE + } + Else { + Clear-UserFlag $user_obj $ADS_UF_PASSWD_CANT_CHANGE + } + $result.changed = $true + } + If (($null -ne $account_disabled) -and ($account_disabled -ne $user_obj.AccountDisabled)) { + $user_obj.AccountDisabled = $account_disabled + $result.changed = $true + } + If (($null -ne $account_locked) -and ($account_locked -ne $user_obj.IsAccountLocked)) { + $user_obj.IsAccountLocked = $account_locked + $result.changed = $true + } + If ($result.changed) { + $user_obj.SetInfo() + } + If ($null -ne $groups) { + [string[]]$current_groups = $user_obj.Groups() | ForEach-Object { $_.GetType().InvokeMember("Name", "GetProperty", $null, $_, $null) } + If (($groups_action -eq "remove") -or ($groups_action -eq "replace")) { + ForEach ($grp in $current_groups) { + If ((($groups_action -eq "remove") -and ($groups -contains $grp)) -or (($groups_action -eq "replace") -and ($groups -notcontains $grp))) { + $group_obj = Get-Group $grp + If ($group_obj) { + $group_obj.Remove($user_obj.Path) + $result.changed = $true + } + Else { + Fail-Json $result "group '$grp' not found" + } + } + } + } + If (($groups_action -eq "add") -or ($groups_action -eq "replace")) { + ForEach ($grp in $groups) { + If ($current_groups -notcontains $grp) { + $group_obj = Get-Group $grp + If ($group_obj) { + $group_obj.Add($user_obj.Path) + $result.changed = $true + } + Else { + Fail-Json $result "group '$grp' not found" + } + } + } + } + } + } + catch { + Fail-Json $result $_.Exception.Message + } +} +ElseIf ($state -eq 'absent') { + # Remove user + try { + If ($user_obj) { + $username = $user_obj.Name.Value + $adsi.delete("User", $user_obj.Name.Value) + $result.changed = $true + $result.msg = "User '$username' deleted successfully" + $user_obj = $null + } else { + $result.msg = "User '$username' was not found" + } + } + catch { + Fail-Json $result $_.Exception.Message + } +} + +try { + If ($user_obj -and $user_obj -is [System.DirectoryServices.DirectoryEntry]) { + $user_obj.RefreshCache() + $result.name = $user_obj.Name[0] + $result.fullname = $user_obj.FullName[0] + $result.path = $user_obj.Path + $result.description = $user_obj.Description[0] + $result.password_expired = ($user_obj.PasswordExpired | ConvertTo-Bool) + $result.password_never_expires = (Get-UserFlag $user_obj $ADS_UF_DONT_EXPIRE_PASSWD) + $result.user_cannot_change_password = (Get-UserFlag $user_obj $ADS_UF_PASSWD_CANT_CHANGE) + $result.account_disabled = $user_obj.AccountDisabled + $result.account_locked = $user_obj.IsAccountLocked + $result.sid = (New-Object System.Security.Principal.SecurityIdentifier($user_obj.ObjectSid.Value, 0)).Value + $user_groups = @() + ForEach ($grp in $user_obj.Groups()) { + $group_result = @{ + name = $grp.GetType().InvokeMember("Name", "GetProperty", $null, $grp, $null) + path = $grp.GetType().InvokeMember("ADsPath", "GetProperty", $null, $grp, $null) + } + $user_groups += $group_result; + } + $result.groups = $user_groups + $result.state = "present" + } + Else { + $result.name = $username + if ($state -eq 'query') { + $result.msg = "User '$username' was not found" + } + $result.state = "absent" + } +} +catch { + Fail-Json $result $_.Exception.Message +} + +Exit-Json $result |