From 0f6aa07d88a69b7a3d9d2637986cc524826566af Mon Sep 17 00:00:00 2001 From: Jason Ritchie Date: Fri, 11 Nov 2016 13:40:37 -0500 Subject: [PATCH] Detect and correct PowerShell mishandling nssm Unicode output as UTF8 (#2867) * extra detail on which step triggered 'change', detect and handle powershell mishandling nssm's unicode as utf8 * Simpler handling of nssm output encoding Thanks @nitzmahone for a cleaner way to control PowerShell's behavior --- .../modules/extras/windows/win_nssm.ps1 | 167 +++++++++++------- 1 file changed, 102 insertions(+), 65 deletions(-) diff --git a/lib/ansible/modules/extras/windows/win_nssm.ps1 b/lib/ansible/modules/extras/windows/win_nssm.ps1 index 3ea4a211c3a..91e63069ddc 100644 --- a/lib/ansible/modules/extras/windows/win_nssm.ps1 +++ b/lib/ansible/modules/extras/windows/win_nssm.ps1 @@ -42,6 +42,33 @@ $dependencies = Get-Attr $params "dependencies" -default $null $user = Get-Attr $params "user" -default $null $password = Get-Attr $params "password" -default $null + +#abstract the calling of nssm because some PowerShell environments +#mishandle its stdout(which is Unicode) as UTF8 +Function Nssm-Invoke +{ + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [string]$cmd + ) + Try { + $encodingWas = [System.Console]::OutputEncoding + [System.Console]::OutputEncoding = [System.Text.Encoding]::Unicode + + $nssmOutput = invoke-expression "nssm $cmd" + return $nssmOutput + } + Catch { + $ErrorMessage = $_.Exception.Message + Fail-Json $result "an exception occurred when invoking NSSM: $ErrorMessage" + } + Finally { + # Set the console encoding back to what it was + [System.Console]::OutputEncoding = $encodingWas + } +} + Function Service-Exists { [CmdletBinding()] @@ -63,11 +90,11 @@ Function Nssm-Remove if (Service-Exists -name $name) { - $cmd = "nssm stop ""$name""" - $results = invoke-expression $cmd + $cmd = "stop ""$name""" + $results = Nssm-Invoke $cmd - $cmd = "nssm remove ""$name"" confirm" - $results = invoke-expression $cmd + $cmd = "remove ""$name"" confirm" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -76,6 +103,7 @@ Function Nssm-Remove Throw "Error removing service ""$name""" } + Set-Attr $result "changed_by" "remove_service" $result.changed = $true } } @@ -101,9 +129,7 @@ Function Nssm-Install if (!(Service-Exists -name $name)) { - $cmd = "nssm install ""$name"" $application" - - $results = invoke-expression $cmd + $results = Nssm-Invoke "install ""$name"" $application" if ($LastExitCode -ne 0) { @@ -112,11 +138,11 @@ Function Nssm-Install Throw "Error installing service ""$name""" } + Set-Attr $result "changed_by" "install_service" $result.changed = $true } else { - $cmd = "nssm get ""$name"" Application" - $results = invoke-expression $cmd + $results = Nssm-Invoke "get ""$name"" Application" if ($LastExitCode -ne 0) { @@ -125,11 +151,11 @@ Function Nssm-Install Throw "Error installing service ""$name""" } - if ($results -ne $application) + if ($results -cnotlike $application) { - $cmd = "nssm set ""$name"" Application $application" + $cmd = "set ""$name"" Application $application" - $results = invoke-expression $cmd + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -137,7 +163,9 @@ Function Nssm-Install Set-Attr $result "nssm_error_log" "$results" Throw "Error installing service ""$name""" } + Set-Attr $result "application" "$application" + Set-Attr $result "changed_by" "reinstall_service" $result.changed = $true } } @@ -184,8 +212,8 @@ Function Nssm-Update-AppParameters [string]$appParameters ) - $cmd = "nssm get ""$name"" AppParameters" - $results = invoke-expression $cmd + $cmd = "get ""$name"" AppParameters" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -228,11 +256,11 @@ Function Nssm-Update-AppParameters { if ($appParameters) { - $cmd = "nssm set ""$name"" AppParameters $singleLineParams" + $cmd = "set ""$name"" AppParameters $singleLineParams" } else { - $cmd = "nssm set ""$name"" AppParameters '""""'" + $cmd = "set ""$name"" AppParameters '""""'" } - $results = invoke-expression $cmd + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -241,11 +269,12 @@ Function Nssm-Update-AppParameters Throw "Error updating AppParameters for service ""$name""" } + Set-Attr $result "changed_by" "update_app_parameters" $result.changed = $true } } -Function Nssm-Set-Ouput-Files +Function Nssm-Set-Output-Files { [CmdletBinding()] param( @@ -255,8 +284,8 @@ Function Nssm-Set-Ouput-Files [string]$stderr ) - $cmd = "nssm get ""$name"" AppStdout" - $results = invoke-expression $cmd + $cmd = "get ""$name"" AppStdout" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -265,16 +294,16 @@ Function Nssm-Set-Ouput-Files Throw "Error retrieving existing stdout file for service ""$name""" } - if ($results -ne $stdout) + if ($results -cnotlike $stdout) { if (!$stdout) { - $cmd = "nssm reset ""$name"" AppStdout" + $cmd = "reset ""$name"" AppStdout" } else { - $cmd = "nssm set ""$name"" AppStdout $stdout" + $cmd = "set ""$name"" AppStdout $stdout" } - $results = invoke-expression $cmd + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -283,11 +312,12 @@ Function Nssm-Set-Ouput-Files Throw "Error setting stdout file for service ""$name""" } + Set-Attr $result "changed_by" "set_stdout" $result.changed = $true } - $cmd = "nssm get ""$name"" AppStderr" - $results = invoke-expression $cmd + $cmd = "get ""$name"" AppStderr" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -296,12 +326,12 @@ Function Nssm-Set-Ouput-Files Throw "Error retrieving existing stderr file for service ""$name""" } - if ($results -ne $stderr) + if ($results -cnotlike $stderr) { if (!$stderr) { - $cmd = "nssm reset ""$name"" AppStderr" - $results = invoke-expression $cmd + $cmd = "reset ""$name"" AppStderr" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -310,8 +340,8 @@ Function Nssm-Set-Ouput-Files Throw "Error clearing stderr file setting for service ""$name""" } } else { - $cmd = "nssm set ""$name"" AppStderr $stderr" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppStderr $stderr" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -321,6 +351,7 @@ Function Nssm-Set-Ouput-Files } } + Set-Attr $result "changed_by" "set_stderr" $result.changed = $true } @@ -329,28 +360,28 @@ Function Nssm-Set-Ouput-Files ### #set files to overwrite - $cmd = "nssm set ""$name"" AppStdoutCreationDisposition 2" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppStdoutCreationDisposition 2" + $results = Nssm-Invoke $cmd - $cmd = "nssm set ""$name"" AppStderrCreationDisposition 2" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppStderrCreationDisposition 2" + $results = Nssm-Invoke $cmd #enable file rotation - $cmd = "nssm set ""$name"" AppRotateFiles 1" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppRotateFiles 1" + $results = Nssm-Invoke $cmd #don't rotate until the service restarts - $cmd = "nssm set ""$name"" AppRotateOnline 0" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppRotateOnline 0" + $results = Nssm-Invoke $cmd #both of the below conditions must be met before rotation will happen #minimum age before rotating - $cmd = "nssm set ""$name"" AppRotateSeconds 86400" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppRotateSeconds 86400" + $results = Nssm-Invoke $cmd #minimum size before rotating - $cmd = "nssm set ""$name"" AppRotateBytes 104858" - $results = invoke-expression $cmd + $cmd = "set ""$name"" AppRotateBytes 104858" + $results = Nssm-Invoke $cmd } Function Nssm-Update-Credentials @@ -365,8 +396,8 @@ Function Nssm-Update-Credentials [string]$password ) - $cmd = "nssm get ""$name"" ObjectName" - $results = invoke-expression $cmd + $cmd = "get ""$name"" ObjectName" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -386,8 +417,8 @@ Function Nssm-Update-Credentials } If ($results -ne $fullUser) { - $cmd = "nssm set ""$name"" ObjectName $fullUser $password" - $results = invoke-expression $cmd + $cmd = "set ""$name"" ObjectName $fullUser $password" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -396,6 +427,7 @@ Function Nssm-Update-Credentials Throw "Error updating credentials for service ""$name""" } + Set-Attr $result "changed_by" "update_credentials" $result.changed = $true } } @@ -412,8 +444,8 @@ Function Nssm-Update-Dependencies [string]$dependencies ) - $cmd = "nssm get ""$name"" DependOnService" - $results = invoke-expression $cmd + $cmd = "get ""$name"" DependOnService" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -423,8 +455,8 @@ Function Nssm-Update-Dependencies } If (($dependencies) -and ($results.Tolower() -ne $dependencies.Tolower())) { - $cmd = "nssm set ""$name"" DependOnService $dependencies" - $results = invoke-expression $cmd + $cmd = "set ""$name"" DependOnService $dependencies" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -433,6 +465,7 @@ Function Nssm-Update-Dependencies Throw "Error updating dependencies for service ""$name""" } + Set-Attr $result "changed_by" "update-dependencies" $result.changed = $true } } @@ -447,8 +480,8 @@ Function Nssm-Update-StartMode [string]$mode ) - $cmd = "nssm get ""$name"" Start" - $results = invoke-expression $cmd + $cmd = "get ""$name"" Start" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -459,9 +492,9 @@ Function Nssm-Update-StartMode $modes=@{"auto" = "SERVICE_AUTO_START"; "manual" = "SERVICE_DEMAND_START"; "disabled" = "SERVICE_DISABLED"} $mappedMode = $modes.$mode - if ($mappedMode -ne $results) { - $cmd = "nssm set ""$name"" Start $mappedMode" - $results = invoke-expression $cmd + if ($results -cnotlike $mappedMode) { + $cmd = "set ""$name"" Start $mappedMode" + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -470,6 +503,7 @@ Function Nssm-Update-StartMode Throw "Error updating start mode for service ""$name""" } + Set-Attr $result "changed_by" "start_mode" $result.changed = $true } } @@ -482,8 +516,8 @@ Function Nssm-Get-Status [string]$name ) - $cmd = "nssm status ""$name""" - $results = invoke-expression $cmd + $cmd = "status ""$name""" + $results = Nssm-Invoke $cmd return ,$results } @@ -526,9 +560,9 @@ Function Nssm-Start-Service-Command [string]$name ) - $cmd = "nssm start ""$name""" + $cmd = "start ""$name""" - $results = invoke-expression $cmd + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -537,6 +571,7 @@ Function Nssm-Start-Service-Command Throw "Error starting service ""$name""" } + Set-Attr $result "changed_by" "start_service" $result.changed = $true } @@ -548,9 +583,9 @@ Function Nssm-Stop-Service-Command [string]$name ) - $cmd = "nssm stop ""$name""" + $cmd = "stop ""$name""" - $results = invoke-expression $cmd + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -559,6 +594,7 @@ Function Nssm-Stop-Service-Command Throw "Error stopping service ""$name""" } + Set-Attr $result "changed_by" "stop_service_command" $result.changed = $true } @@ -581,9 +617,9 @@ Function Nssm-Stop if ($currentStatus -ne "SERVICE_STOPPED") { - $cmd = "nssm stop ""$name""" + $cmd = "stop ""$name""" - $results = invoke-expression $cmd + $results = Nssm-Invoke $cmd if ($LastExitCode -ne 0) { @@ -592,6 +628,7 @@ Function Nssm-Stop Throw "Error stopping service ""$name""" } + Set-Attr $result "changed_by" "stop_service" $result.changed = $true } } @@ -612,7 +649,7 @@ Function NssmProcedure { Nssm-Install -name $name -application $application Nssm-Update-AppParameters -name $name -appParameters $appParameters - Nssm-Set-Ouput-Files -name $name -stdout $stdoutFile -stderr $stderrFile + Nssm-Set-Output-Files -name $name -stdout $stdoutFile -stderr $stderrFile Nssm-Update-Dependencies -name $name -dependencies $dependencies Nssm-Update-Credentials -name $name -user $user -password $password Nssm-Update-StartMode -name $name -mode $startMode