win_auto_logon - check, diff and store pass in LSA (#65528)

* win_auto_logon - check, diff and store pass in LSA

* Ensure baseline keys are set for test

* Skip remove item prop on check mode due to win bug

* Start at a cleared baseline to ensure old LSA secrets are cleared
This commit is contained in:
Jordan Borean 2019-12-05 11:24:30 +10:00 committed by GitHub
parent cff80f1319
commit 4d3ebd65db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 802 additions and 65 deletions

View file

@ -3,27 +3,31 @@
# Copyright: (c) 2019, Prasoon Karunan V (@prasoonkarunan) <kvprasoon@Live.in>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# All helper methods are written in a binary module and has to be loaded for consuming them.
#AnsibleRequires -CSharpUtil Ansible.Basic
#Requires -Module Ansible.ModuleUtils.AddType
Set-StrictMode -Version 2.0
$spec = @{
options = @{
logon_count = @{type = "int"}
password = @{type = "str"; no_log = $true}
state = @{type = "str"; choices = "absent","present"; default = "present"}
state = @{type = "str"; choices = "absent", "present"; default = "present"}
username = @{type = "str"}
}
required_if = @(
, @("state", "present", @("username", "password"))
,@("state", "present", @("username", "password"))
)
supports_check_mode = $true
}
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$password = $module.params.password
$state = $module.params.state
$username = $module.params.username
$logonCount = $module.Params.logon_count
$password = $module.Params.password
$state = $module.Params.state
$username = $module.Params.username
$domain = $null
if ($username) {
@ -40,44 +44,360 @@ if ($username) {
$domain, $username = $ntAccount.Value -split '\\'
}
#Build ParamHash
$autoAdminLogon = 1
if($state -eq 'absent'){
$autoadminlogon = 0
# Make sure $null regardless of any input value if state: absent
if ($state -eq 'absent') {
$password = $null
}
$autoLogonKeyList = @{
DefaultPassword = $password
DefaultUserName = $username
DefaultDomain = $domain
AutoAdminLogon = $autoAdminLogon
}
$actionTaken = $null
$autoLogonRegPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\'
$autoLogonKeyRegList = Get-ItemProperty -LiteralPath $autoLogonRegPath -Name $autoLogonKeyList.GetEnumerator().Name -ErrorAction SilentlyContinue
Foreach($key in $autoLogonKeyList.GetEnumerator().Name){
$currentKeyValue = $autoLogonKeyRegList | Select-Object -ExpandProperty $key -ErrorAction SilentlyContinue
if (-not [String]::IsNullOrEmpty($currentKeyValue)) {
$expectedValue = $autoLogonKeyList[$key]
if(($state -eq 'present') -and ($currentKeyValue -ne $expectedValue)) {
Set-ItemProperty -LiteralPath $autoLogonRegPath -Name $key -Value $autoLogonKeyList[$key] -Force
$actionTaken = $true
Add-CSharpType -AnsibleModule $module -References @'
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
namespace Ansible.WinAutoLogon
{
internal class NativeHelpers
{
[StructLayout(LayoutKind.Sequential)]
public class LSA_OBJECT_ATTRIBUTES
{
public UInt32 Length = 0;
public IntPtr RootDirectory = IntPtr.Zero;
public IntPtr ObjectName = IntPtr.Zero;
public UInt32 Attributes = 0;
public IntPtr SecurityDescriptor = IntPtr.Zero;
public IntPtr SecurityQualityOfService = IntPtr.Zero;
}
elseif($state -eq 'absent') {
$actionTaken = $true
Remove-ItemProperty -LiteralPath $autoLogonRegPath -Name $key -Force
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
public static explicit operator string(LSA_UNICODE_STRING s)
{
byte[] strBytes = new byte[s.Length];
Marshal.Copy(s.Buffer, strBytes, 0, s.Length);
return Encoding.Unicode.GetString(strBytes);
}
public static SafeMemoryBuffer CreateSafeBuffer(string s)
{
if (s == null)
return new SafeMemoryBuffer(IntPtr.Zero);
byte[] stringBytes = Encoding.Unicode.GetBytes(s);
int structSize = Marshal.SizeOf(typeof(LSA_UNICODE_STRING));
IntPtr buffer = Marshal.AllocHGlobal(structSize + stringBytes.Length);
try
{
LSA_UNICODE_STRING lsaString = new LSA_UNICODE_STRING()
{
Length = (UInt16)(stringBytes.Length),
MaximumLength = (UInt16)(stringBytes.Length),
Buffer = IntPtr.Add(buffer, structSize),
};
Marshal.StructureToPtr(lsaString, buffer, false);
Marshal.Copy(stringBytes, 0, lsaString.Buffer, stringBytes.Length);
return new SafeMemoryBuffer(buffer);
}
catch
{
// Make sure we free the pointer before raising the exception.
Marshal.FreeHGlobal(buffer);
throw;
}
}
}
}
else {
if ($state -eq 'present') {
$actionTaken = $true
New-ItemProperty -LiteralPath $autoLogonRegPath -Name $key -Value $autoLogonKeyList[$key] -Force | Out-Null
internal class NativeMethods
{
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaClose(
IntPtr ObjectHandle);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaFreeMemory(
IntPtr Buffer);
[DllImport("Advapi32.dll")]
internal static extern Int32 LsaNtStatusToWinError(
UInt32 Status);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaOpenPolicy(
IntPtr SystemName,
NativeHelpers.LSA_OBJECT_ATTRIBUTES ObjectAttributes,
LsaPolicyAccessMask AccessMask,
out SafeLsaHandle PolicyHandle);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaRetrievePrivateData(
SafeLsaHandle PolicyHandle,
SafeMemoryBuffer KeyName,
out SafeLsaMemory PrivateData);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaStorePrivateData(
SafeLsaHandle PolicyHandle,
SafeMemoryBuffer KeyName,
SafeMemoryBuffer PrivateData);
}
internal class SafeLsaMemory : SafeBuffer
{
internal SafeLsaMemory() : base(true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.LsaFreeMemory(handle) == 0;
}
}
internal class SafeMemoryBuffer : SafeBuffer
{
internal SafeMemoryBuffer() : base(true) { }
internal SafeMemoryBuffer(IntPtr ptr) : base(true)
{
base.SetHandle(ptr);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
if (handle != IntPtr.Zero)
Marshal.FreeHGlobal(handle);
return true;
}
}
public class SafeLsaHandle : SafeHandleZeroOrMinusOneIsInvalid
{
internal SafeLsaHandle() : base(true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.LsaClose(handle) == 0;
}
}
public class Win32Exception : System.ComponentModel.Win32Exception
{
private string _exception_msg;
public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
public Win32Exception(int errorCode, string message) : base(errorCode)
{
_exception_msg = String.Format("{0} - {1} (Win32 Error Code {2}: 0x{3})", message, base.Message, errorCode, errorCode.ToString("X8"));
}
public override string Message { get { return _exception_msg; } }
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
}
[Flags]
public enum LsaPolicyAccessMask : uint
{
ViewLocalInformation = 0x00000001,
ViewAuditInformation = 0x00000002,
GetPrivateInformation = 0x00000004,
TrustAdmin = 0x00000008,
CreateAccount = 0x00000010,
CreateSecret = 0x00000020,
CreatePrivilege = 0x00000040,
SetDefaultQuotaLimits = 0x00000080,
SetAuditRequirements = 0x00000100,
AuditLogAdmin = 0x00000200,
ServerAdmin = 0x00000400,
LookupNames = 0x00000800,
Read = 0x00020006,
Write = 0x000207F8,
Execute = 0x00020801,
AllAccess = 0x000F0FFF,
}
public class LsaUtil
{
public static SafeLsaHandle OpenPolicy(LsaPolicyAccessMask access)
{
NativeHelpers.LSA_OBJECT_ATTRIBUTES oa = new NativeHelpers.LSA_OBJECT_ATTRIBUTES();
SafeLsaHandle lsaHandle;
UInt32 res = NativeMethods.LsaOpenPolicy(IntPtr.Zero, oa, access, out lsaHandle);
if (res != 0)
throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaOpenPolicy({0}) failed", access.ToString()));
return lsaHandle;
}
public static string RetrievePrivateData(SafeLsaHandle handle, string key)
{
using (SafeMemoryBuffer keyBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(key))
{
SafeLsaMemory buffer;
UInt32 res = NativeMethods.LsaRetrievePrivateData(handle, keyBuffer, out buffer);
using (buffer)
{
if (res != 0)
{
// If the data object was not found we return null to indicate it isn't set.
if (res == 0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND
return null;
throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaRetrievePrivateData({0}) failed", key));
}
NativeHelpers.LSA_UNICODE_STRING lsaString = (NativeHelpers.LSA_UNICODE_STRING)
Marshal.PtrToStructure(buffer.DangerousGetHandle(),
typeof(NativeHelpers.LSA_UNICODE_STRING));
return (string)lsaString;
}
}
}
public static void StorePrivateData(SafeLsaHandle handle, string key, string data)
{
using (SafeMemoryBuffer keyBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(key))
using (SafeMemoryBuffer dataBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(data))
{
UInt32 res = NativeMethods.LsaStorePrivateData(handle, keyBuffer, dataBuffer);
if (res != 0)
{
// When clearing the private data with null it may return this error which we can ignore.
if (data == null && res == 0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND
return;
throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaStorePrivateData({0}) failed", key));
}
}
}
}
}
if($actionTaken){
'@
$autoLogonRegPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
$logonDetails = Get-ItemProperty -LiteralPath $autoLogonRegPath
$before = @{
state = 'absent'
}
if ('AutoAdminLogon' -in $logonDetails.PSObject.Properties.Name -and $logonDetails.AutoAdminLogon -eq 1) {
$before.state = 'present'
}
$mapping = @{
DefaultUserName = 'username'
DefaultDomainName = 'domain'
AutoLogonCount = 'logon_count'
}
foreach ($map_detail in $mapping.GetEnumerator()) {
if ($map_detail.Key -in $logonDetails.PSObject.Properties.Name) {
$before."$($map_detail.Value)" = $logonDetails."$($map_detail.Key)"
}
}
$module.Diff.before = $before
$propParams = @{
LiteralPath = $autoLogonRegPath
WhatIf = $module.CheckMode
Force = $true
}
# First set the registry information
# The DefaultPassword reg key should never be set, we use LSA to store the password in a more secure way.
if ('DefaultPassword' -in (Get-Item -LiteralPath $autoLogonRegPath).Property) {
# Bug on older Windows hosts where -WhatIf causes it fail to find the property
if (-not $module.CheckMode) {
Remove-ItemProperty -Name 'DefaultPassword' @propParams
}
$module.Result.changed = $true
}
$autoLogonKeyList = @{
DefaultUserName = @{
before = if ($before.ContainsKey('username')) { $before.username } else { $null }
after = $username
}
DefaultDomainName = @{
before = if ($before.ContainsKey('domain')) { $before.domain } else { $null }
after = $domain
}
AutoLogonCount = @{
before = if ($before.ContainsKey('logon_count')) { $before.logon_count } else { $null }
after = $logonCount
}
}
# Check AutoAdminLogon separately as it has different logic (key must exist)
if ($state -ne $before.state) {
$newValue = if ($state -eq 'present') { 1 } else { 0 }
$null = New-ItemProperty -Name 'AutoAdminLogon' -Value $newValue -PropertyType DWord @propParams
$module.Result.changed = $true
}
foreach ($key in $autoLogonKeyList.GetEnumerator()) {
$beforeVal = $key.Value.before
$after = $key.Value.after
if ($state -eq 'present' -and $beforeVal -cne $after) {
if ($null -ne $after) {
$null = New-ItemProperty -Name $key.Key -Value $after @propParams
}
elseif (-not $module.CheckMode) {
Remove-ItemProperty -Name $key.Key @propParams
}
$module.Result.changed = $true
}
elseif ($state -eq 'absent' -and $null -ne $beforeVal) {
if (-not $module.CheckMode) {
Remove-ItemProperty -Name $key.Key @propParams
}
$module.Result.changed = $true
}
}
# Finally update the password in the LSA private store.
$lsaHandle = [Ansible.WinAutoLogon.LsaUtil]::OpenPolicy('CreateSecret, GetPrivateInformation')
try {
$beforePass = [Ansible.WinAutoLogon.LsaUtil]::RetrievePrivateData($lsaHandle, 'DefaultPassword')
if ($beforePass -cne $password) {
# Due to .NET marshaling we need to pass in $null as NullString.Value so it's truly a null value.
if ($null -eq $password) {
$password = [NullString]::Value
}
if (-not $module.CheckMode) {
[Ansible.WinAutoLogon.LsaUtil]::StorePrivateData($lsaHandle, 'DefaultPassword', $password)
}
$module.Result.changed = $true
}
}
finally {
$lsaHandle.Dispose()
}
# Need to manually craft the after diff in case we are running in check mode
$module.Diff.after = @{
state = $state
}
if ($state -eq 'present') {
$module.Diff.after.username = $username
$module.Diff.after.domain = $domain
if ($null -ne $logonCount) {
$module.Diff.after.logon_count = $logonCount
}
}
$module.ExitJson()

View file

@ -16,6 +16,14 @@ description:
- Used to apply auto logon registry setting.
version_added: "2.10"
options:
logon_count:
description:
- The number of times to do an automatic logon.
- This count is deremented by Windows everytime an automatic logon is
performed.
- Once the count reaches C(0) then the automatic logon process is
disabled.
type: int
username:
description:
- Username to login automatically.
@ -29,6 +37,8 @@ options:
- Password to be used for automatic login.
- Must be set when C(state=present).
- Value of this input will be used as password for I(username).
- While this value is encrypted by LSA it is decryptable to any user who
is an Administrator on the remote host.
type: str
state:
description:
@ -54,6 +64,12 @@ EXAMPLES = r'''
- name: Remove autologon for user1
win_auto_logon:
state: absent
- name: Set autologon for user1 with a limited logon count
win_auto_logon:
username: User1
password: str0ngp@ssword
logon_count: 5
'''
RETURN = r'''

View file

@ -0,0 +1,3 @@
# This doesn't have to be valid, just testing weird chars in the pass
test_logon_password: 'café - 💩'
test_logon_password2: '.ÅÑŚÌβŁÈ [$!@^&test(;)]'

View file

@ -0,0 +1,214 @@
#!powershell
#AnsibleRequires -CSharpUtil Ansible.Basic
#Requires -Module Ansible.ModuleUtils.AddType
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
Add-CSharpType -AnsibleModule $module -References @'
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
namespace Ansible.TestAutoLogonInfo
{
internal class NativeHelpers
{
[StructLayout(LayoutKind.Sequential)]
public class LSA_OBJECT_ATTRIBUTES
{
public UInt32 Length = 0;
public IntPtr RootDirectory = IntPtr.Zero;
public IntPtr ObjectName = IntPtr.Zero;
public UInt32 Attributes = 0;
public IntPtr SecurityDescriptor = IntPtr.Zero;
public IntPtr SecurityQualityOfService = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
public static explicit operator string(LSA_UNICODE_STRING s)
{
byte[] strBytes = new byte[s.Length];
Marshal.Copy(s.Buffer, strBytes, 0, s.Length);
return Encoding.Unicode.GetString(strBytes);
}
public static SafeMemoryBuffer CreateSafeBuffer(string s)
{
if (s == null)
return new SafeMemoryBuffer(IntPtr.Zero);
byte[] stringBytes = Encoding.Unicode.GetBytes(s);
int structSize = Marshal.SizeOf(typeof(LSA_UNICODE_STRING));
IntPtr buffer = Marshal.AllocHGlobal(structSize + stringBytes.Length);
try
{
LSA_UNICODE_STRING lsaString = new LSA_UNICODE_STRING()
{
Length = (UInt16)(stringBytes.Length),
MaximumLength = (UInt16)(stringBytes.Length),
Buffer = IntPtr.Add(buffer, structSize),
};
Marshal.StructureToPtr(lsaString, buffer, false);
Marshal.Copy(stringBytes, 0, lsaString.Buffer, stringBytes.Length);
return new SafeMemoryBuffer(buffer);
}
catch
{
// Make sure we free the pointer before raising the exception.
Marshal.FreeHGlobal(buffer);
throw;
}
}
}
}
internal class NativeMethods
{
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaClose(
IntPtr ObjectHandle);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaFreeMemory(
IntPtr Buffer);
[DllImport("Advapi32.dll")]
internal static extern Int32 LsaNtStatusToWinError(
UInt32 Status);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaOpenPolicy(
IntPtr SystemName,
NativeHelpers.LSA_OBJECT_ATTRIBUTES ObjectAttributes,
UInt32 AccessMask,
out SafeLsaHandle PolicyHandle);
[DllImport("Advapi32.dll")]
public static extern UInt32 LsaRetrievePrivateData(
SafeLsaHandle PolicyHandle,
SafeMemoryBuffer KeyName,
out SafeLsaMemory PrivateData);
}
internal class SafeLsaMemory : SafeBuffer
{
internal SafeLsaMemory() : base(true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.LsaFreeMemory(handle) == 0;
}
}
internal class SafeMemoryBuffer : SafeBuffer
{
internal SafeMemoryBuffer() : base(true) { }
internal SafeMemoryBuffer(IntPtr ptr) : base(true)
{
base.SetHandle(ptr);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
if (handle != IntPtr.Zero)
Marshal.FreeHGlobal(handle);
return true;
}
}
public class SafeLsaHandle : SafeHandleZeroOrMinusOneIsInvalid
{
internal SafeLsaHandle() : base(true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.LsaClose(handle) == 0;
}
}
public class Win32Exception : System.ComponentModel.Win32Exception
{
private string _exception_msg;
public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
public Win32Exception(int errorCode, string message) : base(errorCode)
{
_exception_msg = String.Format("{0} - {1} (Win32 Error Code {2}: 0x{3})", message, base.Message, errorCode, errorCode.ToString("X8"));
}
public override string Message { get { return _exception_msg; } }
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
}
public class LsaUtil
{
public static SafeLsaHandle OpenPolicy(UInt32 access)
{
NativeHelpers.LSA_OBJECT_ATTRIBUTES oa = new NativeHelpers.LSA_OBJECT_ATTRIBUTES();
SafeLsaHandle lsaHandle;
UInt32 res = NativeMethods.LsaOpenPolicy(IntPtr.Zero, oa, access, out lsaHandle);
if (res != 0)
throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaOpenPolicy({0}) failed", access.ToString()));
return lsaHandle;
}
public static string RetrievePrivateData(SafeLsaHandle handle, string key)
{
using (SafeMemoryBuffer keyBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(key))
{
SafeLsaMemory buffer;
UInt32 res = NativeMethods.LsaRetrievePrivateData(handle, keyBuffer, out buffer);
using (buffer)
{
if (res != 0)
{
// If the data object was not found we return null to indicate it isn't set.
if (res == 0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND
return null;
throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res),
String.Format("LsaRetrievePrivateData({0}) failed", key));
}
NativeHelpers.LSA_UNICODE_STRING lsaString = (NativeHelpers.LSA_UNICODE_STRING)
Marshal.PtrToStructure(buffer.DangerousGetHandle(),
typeof(NativeHelpers.LSA_UNICODE_STRING));
return (string)lsaString;
}
}
}
}
}
'@
$details = Get-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
$module.Result.AutoAdminLogon = $details.AutoAdminLogon
$module.Result.DefaultUserName = $details.DefaultUserName
$module.Result.DefaultDomainName = $details.DefaultDomainName
$module.Result.DefaultPassword = $details.DefaultPassword
$module.Result.AutoLogonCount = $details.AutoLogonCount
$handle = [Ansible.TestAutoLogonInfo.LsaUtil]::OpenPolicy(0x00000004)
try {
$password = [Ansible.TestAutoLogonInfo.LsaUtil]::RetrievePrivateData($handle, 'DefaultPassword')
$module.Result.LsaPassword = $password
} finally {
$handle.Dispose()
}
$module.ExitJson()

View file

@ -1,36 +1,42 @@
# Copyright: (c) 2019, Prasoon Karunan V (@prasoonkarunan) <kvprasoon@Live.in>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: Set autologon registry keys
win_auto_logon:
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
state: present
register: win_auto_logon_create_registry_key_set
- name: get user domain split for ansible_user
win_shell: |
$account = New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList '{{ ansible_user }}'
$sid = $account.Translate([System.Security.Principal.SecurityIdentifier])
$sid.Translate([System.Security.Principal.NTAccount]).Value -split '{{ "\\" }}'
changed_when: False
register: test_user_split
- name: check win_auto_logon_create_registry_key_set is changed
assert:
that:
- win_auto_logon_create_registry_key_set is changed
- set_fact:
test_domain: '{{ test_user_split.stdout_lines[0] }}'
test_user: '{{ test_user_split.stdout_lines[1] }}'
- name: Set autologon registry keys with missing input
win_auto_logon:
username: "{{ ansible_user }}"
state: present
register: win_auto_logon_create_registry_key_missing_input
ignore_errors: true
- name: check win_auto_logon_create_registry_key_missing_input is failed
assert:
that:
- win_auto_logon_create_registry_key_missing_input is failed
- name: Remove autologon registry keys
- name: ensure auto logon is cleared before test
win_auto_logon:
state: absent
register: win_auto_logon_create_registry_key_remove
- name: check win_auto_logon_create_registry_key_remove is changed
assert:
that:
- win_auto_logon_create_registry_key_remove is changed
- name: ensure defaults are set
win_regedit:
path: HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
name: '{{ item.name }}'
data: '{{ item.value }}'
type: '{{ item.type }}'
state: present
loop:
# We set the DefaultPassword to ensure win_auto_logon clears this out
- name: DefaultPassword
value: abc
type: string
# Ensures the host we test on has a baseline key to check against
- name: AutoAdminLogon
value: 0
type: dword
- block:
- name: run tests
include_tasks: tests.yml
always:
- name: make sure the auto logon is cleared
win_auto_logon:
state: absent

View file

@ -0,0 +1,178 @@
# Copyright: (c) 2019, Prasoon Karunan V (@prasoonkarunan) <kvprasoon@Live.in>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: set autologon registry keys (check mode)
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password }}'
state: present
register: set_check
check_mode: yes
- name: get acutal of set autologon registry keys (check mode)
test_autologon_info:
register: set_actual_check
- name: assert set autologon registry keys (check mode)
assert:
that:
- set_check is changed
- set_actual_check.AutoAdminLogon == 0
- set_actual_check.AutoLogonCount == None
- set_actual_check.DefaultDomainName == None
- set_actual_check.DefaultPassword == 'abc'
- set_actual_check.DefaultUserName == None
- set_actual_check.LsaPassword == None
- name: set autologon registry keys
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password }}'
state: present
register: set
- name: get acutal of set autologon registry keys
test_autologon_info:
register: set_actual
- name: assert set autologon registry keys
assert:
that:
- set is changed
- set_actual.AutoAdminLogon == 1
- set_actual.AutoLogonCount == None
- set_actual.DefaultDomainName == test_domain
- set_actual.DefaultPassword == None
- set_actual.DefaultUserName == test_user
- set_actual.LsaPassword == test_logon_password
- name: set autologon registry keys (idempotent)
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password }}'
state: present
register: set_again
- name: assert set autologon registry keys (idempotent)
assert:
that:
- not set_again is changed
- name: add logon count (check mode)
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password }}'
logon_count: 2
state: present
register: logon_count_check
check_mode: yes
- name: get result of add logon count (check mode)
test_autologon_info:
register: logon_count_actual_check
- name: assert add logon count (check mode)
assert:
that:
- logon_count_check is changed
- logon_count_actual_check.AutoLogonCount == None
- name: add logon count
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password }}'
logon_count: 2
state: present
register: logon_count
- name: get result of add logon count
test_autologon_info:
register: logon_count_actual
- name: assert add logon count
assert:
that:
- logon_count is changed
- logon_count_actual.AutoLogonCount == 2
- name: change auto logon (check mode)
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password2 }}'
state: present
register: change_check
check_mode: yes
- name: get reuslt of change auto logon (check mode)
test_autologon_info:
register: change_actual_check
- name: assert change auto logon (check mode)
assert:
that:
- change_check is changed
- change_actual_check == logon_count_actual
- name: change auto logon
win_auto_logon:
username: '{{ ansible_user }}'
password: '{{ test_logon_password2 }}'
state: present
register: change
- name: get reuslt of change auto logon
test_autologon_info:
register: change_actual
- name: assert change auto logon
assert:
that:
- change is changed
- change_actual.AutoLogonCount == None
- change_actual.LsaPassword == test_logon_password2
- name: remove autologon registry keys (check mode)
win_auto_logon:
state: absent
register: remove_check
check_mode: yes
- name: get result of remove autologon registry keys (check mode)
test_autologon_info:
register: remove_actual_check
- name: assert remove autologon registry keys (check mode)
assert:
that:
- remove_check is changed
- remove_actual_check == change_actual
- name: remove autologon registry keys
win_auto_logon:
state: absent
register: remove
- name: get result of remove autologon registry keys
test_autologon_info:
register: remove_actual
- name: assert remove autologon registry keys
assert:
that:
- remove is changed
- remove_actual.AutoAdminLogon == 0
- remove_actual.AutoLogonCount == None
- remove_actual.DefaultDomainName == None
- remove_actual.DefaultPassword == None
- remove_actual.DefaultUserName == None
- remove_actual.LsaPassword == None
- name: remove autologon registry keys (idempotent)
win_auto_logon:
state: absent
register: remove_again
- name: assert remove autologon registry keys (idempotent)
assert:
that:
- not remove_again is changed