197 lines
6 KiB
PowerShell
197 lines
6 KiB
PowerShell
|
#!powershell
|
||
|
|
||
|
# Copyright: (c) 2017, Jordan Borean <jborean93@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
|
||
|
|
||
|
$ErrorActionPreference = 'Stop'
|
||
|
|
||
|
$params = Parse-Args $args -supports_check_mode $true
|
||
|
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
|
||
|
$diff_mode = Get-AnsibleParam -obj $Params -name "_ansible_diff" -type "bool" -default $false
|
||
|
|
||
|
$section = Get-AnsibleParam -obj $params -name "section" -type "str" -failifempty $true
|
||
|
$key = Get-AnsibleParam -obj $params -name "key" -type "str" -failifempty $true
|
||
|
$value = Get-AnsibleParam -obj $params -name "value" -failifempty $true
|
||
|
|
||
|
$result = @{
|
||
|
changed = $false
|
||
|
section = $section
|
||
|
key = $key
|
||
|
value = $value
|
||
|
}
|
||
|
|
||
|
if ($diff_mode) {
|
||
|
$result.diff = @{}
|
||
|
}
|
||
|
|
||
|
Function Run-SecEdit($arguments) {
|
||
|
$stdout = $null
|
||
|
$stderr = $null
|
||
|
$log_path = [IO.Path]::GetTempFileName()
|
||
|
$arguments = $arguments + @("/log", $log_path)
|
||
|
|
||
|
try {
|
||
|
$stdout = &SecEdit.exe $arguments | Out-String
|
||
|
} catch {
|
||
|
$stderr = $_.Exception.Message
|
||
|
}
|
||
|
$log = Get-Content -Path $log_path
|
||
|
Remove-Item -Path $log_path -Force
|
||
|
|
||
|
$return = @{
|
||
|
log = ($log -join "`n").Trim()
|
||
|
stdout = $stdout
|
||
|
stderr = $stderr
|
||
|
rc = $LASTEXITCODE
|
||
|
}
|
||
|
|
||
|
return $return
|
||
|
}
|
||
|
|
||
|
Function Export-SecEdit() {
|
||
|
$secedit_ini_path = [IO.Path]::GetTempFileName()
|
||
|
# while this will technically make a change to the system in check mode by
|
||
|
# creating a new file, we need these values to be able to do anything
|
||
|
# substantial in check mode
|
||
|
$export_result = Run-SecEdit -arguments @("/export", "/cfg", $secedit_ini_path, "/quiet")
|
||
|
|
||
|
# check the return code and if the file has been populated, otherwise error out
|
||
|
if (($export_result.rc -ne 0) -or ((Get-Item -Path $secedit_ini_path).Length -eq 0)) {
|
||
|
Remove-Item -Path $secedit_ini_path -Force
|
||
|
$result.rc = $export_result.rc
|
||
|
$result.stdout = $export_result.stdout
|
||
|
$result.stderr = $export_result.stderr
|
||
|
Fail-Json $result "Failed to export secedit.ini file to $($secedit_ini_path)"
|
||
|
}
|
||
|
$secedit_ini = ConvertFrom-Ini -file_path $secedit_ini_path
|
||
|
|
||
|
return $secedit_ini
|
||
|
}
|
||
|
|
||
|
Function Import-SecEdit($ini) {
|
||
|
$secedit_ini_path = [IO.Path]::GetTempFileName()
|
||
|
$secedit_db_path = [IO.Path]::GetTempFileName()
|
||
|
Remove-Item -Path $secedit_db_path -Force # needs to be deleted for SecEdit.exe /import to work
|
||
|
|
||
|
$ini_contents = ConvertTo-Ini -ini $ini
|
||
|
Set-Content -Path $secedit_ini_path -Value $ini_contents
|
||
|
$result.changed = $true
|
||
|
|
||
|
$import_result = Run-SecEdit -arguments @("/configure", "/db", $secedit_db_path, "/cfg", $secedit_ini_path, "/quiet")
|
||
|
$result.import_log = $import_result.log
|
||
|
Remove-Item -Path $secedit_ini_path -Force
|
||
|
if ($import_result.rc -ne 0) {
|
||
|
$result.rc = $import_result.rc
|
||
|
$result.stdout = $import_result.stdout
|
||
|
$result.stderr = $import_result.stderr
|
||
|
Fail-Json $result "Failed to import secedit.ini file from $($secedit_ini_path)"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Function ConvertTo-Ini($ini) {
|
||
|
$content = @()
|
||
|
foreach ($key in $ini.GetEnumerator()) {
|
||
|
$section = $key.Name
|
||
|
$values = $key.Value
|
||
|
|
||
|
$content += "[$section]"
|
||
|
foreach ($value in $values.GetEnumerator()) {
|
||
|
$value_key = $value.Name
|
||
|
$value_value = $value.Value
|
||
|
|
||
|
if ($null -ne $value_value) {
|
||
|
$content += "$value_key = $value_value"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $content -join "`r`n"
|
||
|
}
|
||
|
|
||
|
Function ConvertFrom-Ini($file_path) {
|
||
|
$ini = @{}
|
||
|
switch -Regex -File $file_path {
|
||
|
"^\[(.+)\]" {
|
||
|
$section = $matches[1]
|
||
|
$ini.$section = @{}
|
||
|
}
|
||
|
"(.+?)\s*=(.*)" {
|
||
|
$name = $matches[1].Trim()
|
||
|
$value = $matches[2].Trim()
|
||
|
if ($value -match "^\d+$") {
|
||
|
$value = [int]$value
|
||
|
} elseif ($value.StartsWith('"') -and $value.EndsWith('"')) {
|
||
|
$value = $value.Substring(1, $value.Length - 2)
|
||
|
}
|
||
|
|
||
|
$ini.$section.$name = $value
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $ini
|
||
|
}
|
||
|
|
||
|
if ($section -eq "Privilege Rights") {
|
||
|
Add-Warning -obj $result -message "Using this module to edit rights and privileges is error-prone, use the win_user_right module instead"
|
||
|
}
|
||
|
|
||
|
$will_change = $false
|
||
|
$secedit_ini = Export-SecEdit
|
||
|
if (-not ($secedit_ini.ContainsKey($section))) {
|
||
|
Fail-Json $result "The section '$section' does not exist in SecEdit.exe output ini"
|
||
|
}
|
||
|
|
||
|
if ($secedit_ini.$section.ContainsKey($key)) {
|
||
|
$current_value = $secedit_ini.$section.$key
|
||
|
|
||
|
if ($current_value -cne $value) {
|
||
|
if ($diff_mode) {
|
||
|
$result.diff.prepared = @"
|
||
|
[$section]
|
||
|
-$key = $current_value
|
||
|
+$key = $value
|
||
|
"@
|
||
|
}
|
||
|
|
||
|
$secedit_ini.$section.$key = $value
|
||
|
$will_change = $true
|
||
|
}
|
||
|
} elseif ([string]$value -eq "") {
|
||
|
# Value is requested to be removed, and has already been removed, do nothing
|
||
|
} else {
|
||
|
if ($diff_mode) {
|
||
|
$result.diff.prepared = @"
|
||
|
[$section]
|
||
|
+$key = $value
|
||
|
"@
|
||
|
}
|
||
|
$secedit_ini.$section.$key = $value
|
||
|
$will_change = $true
|
||
|
}
|
||
|
|
||
|
if ($will_change -eq $true) {
|
||
|
$result.changed = $true
|
||
|
if (-not $check_mode) {
|
||
|
Import-SecEdit -ini $secedit_ini
|
||
|
|
||
|
# secedit doesn't error out on improper entries, re-export and verify
|
||
|
# the changes occurred
|
||
|
$verification_ini = Export-SecEdit
|
||
|
$new_section_values = $verification_ini.$section
|
||
|
if ($new_section_values.ContainsKey($key)) {
|
||
|
$new_value = $new_section_values.$key
|
||
|
if ($new_value -cne $value) {
|
||
|
Fail-Json $result "Failed to change the value for key '$key' in section '$section', the value is still $new_value"
|
||
|
}
|
||
|
} elseif ([string]$value -eq "") {
|
||
|
# Value was empty, so OK if no longer in the result
|
||
|
} else {
|
||
|
Fail-Json $result "The key '$key' in section '$section' is not a valid key, cannot set this value"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Exit-Json $result
|