mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
New Module: Write Windows event log entries (win_eventlog_entry) (#27828)
* initial commit for win_eventlog_entry module * added test module for integration tests and minor documentation fixes
This commit is contained in:
parent
a8a3ad70ad
commit
bb7813f16f
7 changed files with 416 additions and 0 deletions
106
lib/ansible/modules/windows/win_eventlog_entry.ps1
Normal file
106
lib/ansible/modules/windows/win_eventlog_entry.ps1
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#!powershell
|
||||||
|
|
||||||
|
# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
#Requires -Module Ansible.ModuleUtils.Legacy.psm1
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Test-LogExistence {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Get information on a log's existence.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[String]$LogName
|
||||||
|
)
|
||||||
|
|
||||||
|
$log_exists = $false
|
||||||
|
$log = Get-EventLog -List | Where-Object {$_.Log -eq $LogName}
|
||||||
|
if ($log) {
|
||||||
|
$log_exists = $true
|
||||||
|
}
|
||||||
|
return $log_exists
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-SourceExistence {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Get information on a source's existence.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[String]$LogName,
|
||||||
|
[String]$SourceName
|
||||||
|
)
|
||||||
|
|
||||||
|
$source_exists = [System.Diagnostics.EventLog]::SourceExists($SourceName)
|
||||||
|
|
||||||
|
if ($source_exists) {
|
||||||
|
$source_log = [System.Diagnostics.EventLog]::LogNameFromSourceName($SourceName, ".")
|
||||||
|
if ($source_log -ne $LogName) {
|
||||||
|
Fail-Json -obj $result -message "Source $SourceName does not belong to log $LogName and cannot be written to"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $source_exists
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = Parse-Args $args -supports_check_mode $true
|
||||||
|
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
|
||||||
|
|
||||||
|
$log = Get-AnsibleParam -obj $params -name "log" -type "str" -failifempty $true
|
||||||
|
$source = Get-AnsibleParam -obj $params -name "source" -type "str" -failifempty $true
|
||||||
|
$event_id = Get-AnsibleParam -obj $params -name "event_id" -type "int" -failifempty $true
|
||||||
|
$message = Get-AnsibleParam -obj $params -name "message" -type "str" -failifempty $true
|
||||||
|
$entry_type = Get-AnsibleParam -obj $params -name "entry_type" -type "str" -validateset "Error","FailureAudit","Information","SuccessAudit","Warning"
|
||||||
|
$category = Get-AnsibleParam -obj $params -name "category" -type "int"
|
||||||
|
$raw_data = Get-AnsibleParam -obj $params -name "raw_data" -type "str"
|
||||||
|
|
||||||
|
$result = @{
|
||||||
|
changed = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$log_exists = Test-LogExistence -LogName $log
|
||||||
|
if (!$log_exists) {
|
||||||
|
Fail-Json -obj $result -message "Log $log does not exist and cannot be written to"
|
||||||
|
}
|
||||||
|
|
||||||
|
$source_exists = Test-SourceExistence -LogName $log -SourceName $source
|
||||||
|
if (!$source_exists) {
|
||||||
|
Fail-Json -obj $result -message "Source $source does not exist"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($event_id -lt 0 -or $event_id -gt 65535) {
|
||||||
|
Fail-Json -obj $result -message "Event ID must be between 0 and 65535"
|
||||||
|
}
|
||||||
|
|
||||||
|
$write_params = @{
|
||||||
|
LogName = $log
|
||||||
|
Source = $source
|
||||||
|
EventId = $event_id
|
||||||
|
Message = $message
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($entry_type) {
|
||||||
|
$write_params.EntryType = $entry_type
|
||||||
|
}
|
||||||
|
if ($category) {
|
||||||
|
$write_params.Category = $category
|
||||||
|
}
|
||||||
|
if ($raw_data) {
|
||||||
|
$write_params.RawData = [Byte[]]($raw_data -split ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$check_mode) {
|
||||||
|
Write-EventLog @write_params
|
||||||
|
}
|
||||||
|
$result.changed = $true
|
||||||
|
$result.msg = "Entry added to log $log from source $source"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Fail-Json -obj $result -message $_.Exception.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit-Json -obj $result
|
78
lib/ansible/modules/windows/win_eventlog_entry.py
Normal file
78
lib/ansible/modules/windows/win_eventlog_entry.py
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.0',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: win_eventlog_entry
|
||||||
|
version_added: "2.4"
|
||||||
|
short_description: Write entries to Windows event logs
|
||||||
|
description:
|
||||||
|
- Write log entries to a given event log from a specified source.
|
||||||
|
options:
|
||||||
|
log:
|
||||||
|
description:
|
||||||
|
- Name of the event log to write an entry to.
|
||||||
|
required: true
|
||||||
|
source:
|
||||||
|
description:
|
||||||
|
- Name of the log source to indicate where the entry is from.
|
||||||
|
required: true
|
||||||
|
event_id:
|
||||||
|
description:
|
||||||
|
- The numeric event identifier for the entry.
|
||||||
|
- Value must be between 0 and 65535.
|
||||||
|
required: true
|
||||||
|
message:
|
||||||
|
description:
|
||||||
|
- The message for the given log entry.
|
||||||
|
required: true
|
||||||
|
entry_type:
|
||||||
|
description:
|
||||||
|
- Indicates the entry being written to the log is of a specific type.
|
||||||
|
choices:
|
||||||
|
- Error
|
||||||
|
- FailureAudit
|
||||||
|
- Information
|
||||||
|
- SuccessAudit
|
||||||
|
- Warning
|
||||||
|
category:
|
||||||
|
description:
|
||||||
|
- A numeric task category associated with the category message file for the log source.
|
||||||
|
raw_data:
|
||||||
|
description:
|
||||||
|
- Binary data associated with the log entry.
|
||||||
|
- Value must be a comma-separated array of 8-bit unsigned integers (0 to 255).
|
||||||
|
notes:
|
||||||
|
- This module will always report a change when writing an event entry.
|
||||||
|
author:
|
||||||
|
- Andrew Saraceni (@andrewsaraceni)
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Write an entry to a Windows event log
|
||||||
|
win_eventlog_entry:
|
||||||
|
log: MyNewLog
|
||||||
|
source: NewLogSource1
|
||||||
|
event_id: 1234
|
||||||
|
message: This is a test log entry.
|
||||||
|
|
||||||
|
- name: Write another entry to a different Windows event log
|
||||||
|
win_eventlog_entry:
|
||||||
|
log: AnotherLog
|
||||||
|
source: MyAppSource
|
||||||
|
event_id: 5000
|
||||||
|
message: An error has occurred.
|
||||||
|
entry_type: Error
|
||||||
|
category: 5
|
||||||
|
raw_data: 10,20
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
# Default return values
|
||||||
|
'''
|
1
test/integration/targets/win_eventlog_entry/aliases
Normal file
1
test/integration/targets/win_eventlog_entry/aliases
Normal file
|
@ -0,0 +1 @@
|
||||||
|
windows/ci/group3
|
|
@ -0,0 +1,6 @@
|
||||||
|
win_test_log_source:
|
||||||
|
log: WinEventLogEntryTest
|
||||||
|
source: WinEventLogEntrySource
|
||||||
|
win_test_log_source_extra:
|
||||||
|
log: ExtraWinEventLogEntryTest
|
||||||
|
source: ExtraWinEventLogEntrySource
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!powershell
|
||||||
|
|
||||||
|
# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
#Requires -Module Ansible.ModuleUtils.Legacy.psm1
|
||||||
|
|
||||||
|
# Test module used to grab the latest entry from an event log and output its properties
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$params = Parse-Args $args -supports_check_mode $true
|
||||||
|
$log = Get-AnsibleParam -obj $params -name "log" -type "str" -failifempty $true
|
||||||
|
|
||||||
|
$result = @{
|
||||||
|
changed = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$log_entry = Get-EventLog -LogName $log | Select-Object -First 1 -Property *
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Fail-Json -obj $result -message "Could not find any entries for log $log"
|
||||||
|
}
|
||||||
|
|
||||||
|
$result.source = $log_entry.Source
|
||||||
|
$result.event_id = $log_entry.EventID
|
||||||
|
$result.message = $log_entry.Message
|
||||||
|
$result.entry_type = $log_entry.EntryType.ToString()
|
||||||
|
$result.category = $log_entry.CategoryNumber
|
||||||
|
$result.raw_data = $log_entry.Data -join ","
|
||||||
|
|
||||||
|
Exit-Json -obj $result
|
33
test/integration/targets/win_eventlog_entry/tasks/main.yml
Normal file
33
test/integration/targets/win_eventlog_entry/tasks/main.yml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# win_shell invocations can eventually be replaced with win_eventlog
|
||||||
|
- name: Remove potentially leftover test logs and sources
|
||||||
|
win_shell: Remove-EventLog -LogName "{{ item.log }}" -ErrorAction SilentlyContinue
|
||||||
|
with_items:
|
||||||
|
- "{{ win_test_log_source }}"
|
||||||
|
- "{{ win_test_log_source_extra }}"
|
||||||
|
failed_when: no
|
||||||
|
|
||||||
|
- name: Add new test logs and sources
|
||||||
|
win_shell: New-EventLog -LogName "{{ item.log }}" -Source "{{ item.source }}"
|
||||||
|
with_items:
|
||||||
|
- "{{ win_test_log_source }}"
|
||||||
|
- "{{ win_test_log_source_extra }}"
|
||||||
|
|
||||||
|
- name: Run tests for win_eventlog_entry
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Test in normal mode
|
||||||
|
include_tasks: tests.yml
|
||||||
|
vars:
|
||||||
|
in_check_mode: no
|
||||||
|
|
||||||
|
- name: Test in check-mode
|
||||||
|
include_tasks: tests.yml
|
||||||
|
vars:
|
||||||
|
in_check_mode: yes
|
||||||
|
check_mode: yes
|
||||||
|
|
||||||
|
- name: Remove test logs and sources
|
||||||
|
win_shell: Remove-EventLog -LogName "{{ item.log }}"
|
||||||
|
with_items:
|
||||||
|
- "{{ win_test_log_source }}"
|
||||||
|
- "{{ win_test_log_source_extra }}"
|
159
test/integration/targets/win_eventlog_entry/tasks/tests.yml
Normal file
159
test/integration/targets/win_eventlog_entry/tasks/tests.yml
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
# Test code for win_eventlog_entry
|
||||||
|
|
||||||
|
# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
- name: Add entry to fake log
|
||||||
|
win_eventlog_entry:
|
||||||
|
log: FakeLogName
|
||||||
|
source: "{{ win_test_log_source.source }}"
|
||||||
|
event_id: 12345
|
||||||
|
message: This is a test log entry message
|
||||||
|
register: add_entry_to_fake_log
|
||||||
|
failed_when: add_entry_to_fake_log.changed != false or add_entry_to_fake_log.msg != "Log FakeLogName does not exist and cannot be written to"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry from fake source
|
||||||
|
win_eventlog_entry:
|
||||||
|
log: "{{ win_test_log_source.log }}"
|
||||||
|
source: FakeSourceName
|
||||||
|
event_id: 12345
|
||||||
|
message: This is a test log entry message
|
||||||
|
register: add_entry_from_fake_source
|
||||||
|
failed_when: add_entry_from_fake_source.changed != false or add_entry_from_fake_source.msg != "Source FakeSourceName does not exist"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry with invalid event_id
|
||||||
|
win_eventlog_entry:
|
||||||
|
log: "{{ win_test_log_source.log }}"
|
||||||
|
source: "{{ win_test_log_source.source }}"
|
||||||
|
event_id: 67000
|
||||||
|
message: This is a test log entry message
|
||||||
|
register: add_entry_with_invalid_event_id
|
||||||
|
failed_when: add_entry_with_invalid_event_id.changed != false or add_entry_with_invalid_event_id.msg != "Event ID must be between 0 and 65535"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry from other log source
|
||||||
|
win_eventlog_entry:
|
||||||
|
log: "{{ win_test_log_source.log }}"
|
||||||
|
source: "{{ win_test_log_source_extra.source }}"
|
||||||
|
event_id: 12345
|
||||||
|
message: This is a test log entry message
|
||||||
|
register: add_entry_from_other_log_source
|
||||||
|
failed_when: add_entry_from_other_log_source.changed != false or add_entry_from_other_log_source.msg != "Source {{ win_test_log_source_extra.source }} does not belong to log {{ win_test_log_source.log }} and cannot be written to"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry
|
||||||
|
win_eventlog_entry: &wele
|
||||||
|
log: "{{ win_test_log_source.log }}"
|
||||||
|
source: "{{ win_test_log_source.source }}"
|
||||||
|
event_id: 12345
|
||||||
|
message: This is a test log entry message
|
||||||
|
register: add_entry
|
||||||
|
|
||||||
|
- name: Test add_entry
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- add_entry.changed == true
|
||||||
|
- add_entry.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
|
||||||
|
|
||||||
|
- name: Test add_entry count (normal mode)
|
||||||
|
win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
|
||||||
|
register: add_entry_count
|
||||||
|
failed_when: add_entry_count.stdout_lines[0] != "1"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
- name: Test add_entry result (normal mode)
|
||||||
|
test_win_eventlog_entry:
|
||||||
|
log: "{{ win_test_log_source.log }}"
|
||||||
|
register: add_entry_result
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
- name: Test add_entry_result (normal mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- add_entry_result.source == win_test_log_source.source
|
||||||
|
- add_entry_result.event_id == 12345
|
||||||
|
- add_entry_result.message == "This is a test log entry message"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry (again)
|
||||||
|
win_eventlog_entry: *wele
|
||||||
|
register: add_entry_again
|
||||||
|
|
||||||
|
- name: Test add_entry_again (normal mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- add_entry_again.changed == true
|
||||||
|
- add_entry_again.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
- name: Test add_entry_again count (normal mode)
|
||||||
|
win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
|
||||||
|
register: add_entry_again_count
|
||||||
|
failed_when: add_entry_again_count.stdout_lines[0] != "2"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry all options
|
||||||
|
win_eventlog_entry: &wele_ao
|
||||||
|
<<: *wele
|
||||||
|
event_id: 500
|
||||||
|
message: This is a test error message
|
||||||
|
entry_type: Error
|
||||||
|
category: 5
|
||||||
|
raw_data: 10,20
|
||||||
|
register: add_entry_all_options
|
||||||
|
|
||||||
|
- name: Test add_entry_all_options
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- add_entry_all_options.changed == true
|
||||||
|
- add_entry_all_options.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
|
||||||
|
|
||||||
|
- name: Test add_entry_all_options count (normal mode)
|
||||||
|
win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
|
||||||
|
register: add_entry_all_options_count
|
||||||
|
failed_when: add_entry_all_options_count.stdout_lines[0] != "3"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
- name: Test add_entry_all_options result (normal mode)
|
||||||
|
test_win_eventlog_entry:
|
||||||
|
log: "{{ win_test_log_source.log }}"
|
||||||
|
register: add_entry_all_options_result
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
- name: Test add_entry_all_options_result (normal mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- add_entry_all_options_result.source == win_test_log_source.source
|
||||||
|
- add_entry_all_options_result.event_id == 500
|
||||||
|
- add_entry_all_options_result.message == "This is a test error message"
|
||||||
|
- add_entry_all_options_result.entry_type == "Error"
|
||||||
|
- add_entry_all_options_result.category == 5
|
||||||
|
- add_entry_all_options_result.raw_data == "10,20"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
|
||||||
|
- name: Add entry all options (again)
|
||||||
|
win_eventlog_entry: *wele_ao
|
||||||
|
register: add_entry_all_options_again
|
||||||
|
|
||||||
|
- name: Test add_entry_all_options_again (normal mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- add_entry_all_options_again.changed == true
|
||||||
|
- add_entry_all_options_again.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
- name: Test add_entry_all_options_again count (normal mode)
|
||||||
|
win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count
|
||||||
|
register: add_entry_all_options_again_count
|
||||||
|
failed_when: add_entry_all_options_again_count.stdout_lines[0] != "4"
|
||||||
|
when: not in_check_mode
|
||||||
|
|
||||||
|
|
||||||
|
- name: Clear event log entries
|
||||||
|
win_shell: Clear-EventLog -LogName "{{ win_test_log_source.log }}"
|
||||||
|
when: not in_check_mode
|
Loading…
Reference in a new issue