As part of a an open-source project, I am writing a script that will allow to host Jenkins agent as a service.
Jenkins is running on Java, so I had to call Java.exe.
For this, I need to make sure that when the script is being terminated, the java process is being terminated as well.
I found that using CMD /c
or Start-Process
is starting a new process, and because of this, stopping the PowerShell script does not stop the java.exe
as well.
The only thing that worked was the call operator, &
.
However, as you see below it treats the infomration returned from JAVA as an exception. IT IS FALSE-POSITIVE.
I need to make sure the actual information is being sent to output as usual, not hidden.
This rules out $ErrorActionPreference = 'SilentlyContinue'
Also tried 2>&1
and *>&1
but same result
Any ideas will be great.
& "$Java\java.exe" -jar "$JenkinsPath\agent.jar" -url "$JenkinsURL/" -secret $Secret -name $env:computername -workDir "$JenkinsPath" *>>"$JenkinsPath\agent.log"
java.exe : Aug 04, 2024 5:14:14 PM org.jenkinsci.remoting.engine.WorkDirManager initializeWorkDir
At line:1 char:1
+ & "$Java\java.exe" -jar "$JenkinsPath\agent.jar" -url "$JenkinsURL/" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Aug 04, 2024 5:...itializeWorkDir:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
INFO: Using D:\Jenkins\remoting as a remoting work directory
Aug 04, 2024 5:14:14 PM org.jenkinsci.remoting.engine.WorkDirManager setupLogging
INFO: Both error and output logs will be printed to D:\Jenkins\remoting
Aug 04, 2024 5:14:14 PM hudson.remoting.Launcher createEngine
Thanks in advance.
Your problem is the unexpected rendering of stderr lines, which inappropriately render as if they were errors.[1] Do the following to avoid the problem:
Apply redirection 2>&1
directly to the java.exe
call.
java.exe
's stderr output into PowerShell's success output stream (PowerShell's stdout analog), allowing both stdout and stderr output to be processed in a PowerShell pipeline.Pipe the result to a ForEach-Object
call that calls the .ToString()
method on each resulting object (%
is a built-in alias of ForEach-Object
)
System.Management.Automation.ErrorRecord
instance, which renders as if it were a PowerShell error, which causes the unexpected output you saw. Stringification via .ToString()
yields the original stderr text.[2]Apply the redirection to the log file (>>"$JenkinsPath\agent.log"
) to the latter; since all java.exe
output is at that point routed via the success output stream >>
is sufficient (i.e. no need for *>>
in order to capture all streams).
# java.exe arguments omitted for brevity
& "$Java\java.exe" ... 2>&1 | % ToString >>"$JenkinsPath\agent.log"
Simpler alternative, via Add-Content
:
# java.exe arguments omitted for brevity
& "$Java\java.exe" ... 2>&1 | Add-Content "$JenkinsPath\agent.log"
Add-Content
, like Set-Content
, implicitly stringifies its input objects via .ToString()
.
Character-encoding caveat:
In PowerShell (Core) 7, both solutions are equivalent and create BOM-less UTF-8 files, given that this encoding is the consistent default in this PowerShell edition.
By contrast, in Windows PowerShell (the legacy, ships-with-Windows edition whose latest and last version is 5.1.x), the redirection operators >
/ >>
are in effect aliases of Out-File
, which defaults to UTF-16LE with BOM ("Unicode"), whereas Add-Content
/ Set-Content
use the system's active legacy ANSI code page by default; use the -Encoding
parameter as needed, but note that -Encoding utf8
invariably creates a UTF-8 file with BOM.
[1] Specifically, it is the first stderr line output by an external program such as java.exe
that is rendered this way when a 2>
or *>
redirection (or a >>
variant) is applied to an external-program call. In the console (terminal), subsequent stderr lines render by their text only, but are printed in red too. When redirecting such output to a file, such as in your case, coloring is lost, so it is only the first, error-like representation that stands out. A simple test command:
cmd /c 'echo stderr1 >&2 & echo stdout1 & echo stderr2 >&2' 2>&1
Note that the original output order among the stdout and stderr streams isn't always maintained - see GitHub issue #5424 for a discussion.
[2] By contrast, use of >
/ >>
/ Out-File
results in implicit stringification that uses the rich for-display representations you also see when outputting to the PowerShell console, via PowerShell's output-formatting system - except when stderr output from an external program isn't captured, i.e. prints directly to the display, in which case stderr lines print normally, as uncolored strings.