Handling Jenkins Groovy script exceptions - c#

I am executing a C# exe, CRS.exe, that I expect to return a non-zero value, such as -1. I am using ps to get the value back, and have this within a stage:
try{
pcode = (powershell(returnStdout: true, script: 'return Invoke-Expression -Command \" .\\perfmon\\CRS.exe hello \"'))''
echo "Pcode = ${pcode} "
}
catch (err) {echo err.message }
echo "Pcode = ${pcode} "
Based on this post, "Normally, a script which exits with a nonzero status code will cause the step to fail with an exception." --
Jenkins pipeline bubble up the shell exit code to fail the stage
I want to handle this non-zero result, is the exception handler the only way?
Results of above run:
Running PowerShell script
tester arg = hello
[Pipeline] echo
script returned exit code -1
[Pipeline] echo
Pcode = null
Interestingly enough, a char return seems to be fine? This returns without throwing an exception
icode = (powershell(returnStdout: true, script: 'return Invoke-Expression -Command \'.\\perfmon\\zipInstaller.ps1 -urlString ' + fileContents + "'"))
echo "icode = ${icode} "
Results in
[Pipeline] {
[Pipeline] powershell
[Chris] Running PowerShell script
[Pipeline] echo
icode = -5
I would like to catch the return codes from the exe's and manage my groovy pipelines flow based on that. Any insight would be greatly appreciated.

Instead of using returnStdout: true, try using returnStatus: true. It should always return the exit code. Not as helpful if you need the output from the powershell command all at once (without returnStdout, it will just print output to the Jenkins log), but as a workaround for that you could pipe output to a file and then print that out.
Another option (but it's ugly, so I don't recommend it) is to call Powershell from a bat command. bat should mask the error code for the powershell command, so Jenkins won't get excited and fail automatically, and you'll still get stdout. Obviously not too helpful if you actually wanted the error code though. Your line would look something like
pcode = (bat(returnStdout: true, script: 'Powershell.exe "return Invoke-Expression -Command \" .\\perfmon\\CRS.exe hello \"'"))
That line will need a bit of refining, but it might be another option.

Related

C# pass parameter to power shell script file throws error

C# code has to pass parameter value to powershell script file. The code is working fine if I m not paasing any parameter. When I use .AddParameter or AddArgument it throws error.
while using AddArgument it throws error as 'A positional parameter cannot be found that accepts argument 'Test 111'.'
while using AddParameter I am getting erro as : 'A parameter cannot be found that matches parameter name 'FilePrefix'.'
Please find my C# code below
using (PowerShell ps = PowerShell.Create())
{
var scriptfile = #"\\cbc0056\work\Powershell\Scenarios\Test.ps1";
ps.AddCommand("Set-ExecutionPolicy")
.AddParameter("ExecutionPolicy", "RemoteSigned")
.AddParameter("Scope", "Process")
.AddParameter("Force");
ps.AddScript(scriptfile).AddCommand("Out-String");
//ps.AddArgument("Test 222");
ps.AddParameter("FilePrefix", "Test 222");
Collection<PSObject> results = ps.Invoke();
foreach (PSObject item in results)
{
_logger.LogInformation("Power Shell returned Values as given below " + "\r\n"+item.BaseObject.ToString());
// write some business logic
}
PowerShelll script Test.ps1 file as given below
Param(
[Parameter(Position=1)]
[string]$FilePrefix
)
$test = $FilePrefix
Write-Host "hello this is a test " | Out-String
Write-Host $test| Out-String
$test
Get-Process | Out-String
What is wrong in passing parameter ? Any help would be highly appreciated.
Use .AddCommand() to execute a script file (.ps1); only use .AddScript() to execute a script block, i.e. a piece of PowerShell code.
As Mathias notes, your .AddParameter() call must come before adding another pipeline segement with .AddCommand("Out-String").
ps.AddCommand(scriptfile).AddParameter("FilePrefix", "Test 222").AddCommand("Out-String");
Also note that there's an easier way to set the execution policy, via an object specifying the initial session state: see this answer.

File counter expression in SSIS using execute process task output variable

I have a console application in c# that downloads files from a website.
I have created a variable named Filecount that counts the number of files downloaded in that instance.
In SSIS, I have set the StandardOutputVariable in the Execute process task configuration as User::FileCount that should pass through the number of files that it has downloaded.
I want to create an SQL task that will truncate the table if the file count is greater than 0.
However, when I try to evaluate my expression, it always comes back as true however, this should not occur as no counts have been passed through yet meaning it should be evaluated as false.
Can someone explain if I have either written the expression wrong or set the variable incorrectly?
int fileCount = 0;
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
var response = await client.GetAsync(siteUrl + "/_api/Web/GetFolderByServerRelativeUrl('XXX')/Files");
response.EnsureSuccessStatusCode();
json = await response.Content.ReadAsStringAsync();
Root deserializedResults = JsonConvert.DeserializeObject<Root>(json);
foreach (Result result in deserializedResults.d.results)
{
if (result.TimeCreated > DateTime.Today.AddDays(-7))
{
DownloadFileViaRestAPI(siteUrl, credentials, "XXX", result.Name, "XXX");
fileCount++;
}
}
}
Console.Write(fileCount);
SSIS Execute Process Task;
StandardOutVariable = User::FileCount
SQL Task expression;
Property: Disable
Expression: Len(Trim(#[User::FileCount])) > 0 ? False : True
tl;dr; What you've described and my implementation work fine so something else is going awry in your situation.
Set up
I built out a simple SSIS package. Execute Package Task -> Script task (to dump variable values to console) -> A Sequence Container that has your disable logic on it => Another script task (to dump to console if the disable works/does not work)
I have your original variable, User::FileCount of type String and added User::HasFile of type Boolean with an expression of Len(Trim(#[User::FileCount])) > 0 to test your logic.
SO_71067359.bat
I created a batch file that will serve as your C# app. When needed, I'll remove line 2 so no output is generated. Contents are
#echo off
echo 1
Results
C:\ssisdata>SO_71067359.bat
1
EPT Download File
Execute Package Task. Working directory set to the location of my batch file. Executable is the batch script. StandardOutputVariable is User::FileCount
SCR Echo Back
This is my standard echo back script and I'll add User::FileCount and User::HasFile. When the package runs, this will dump the values to the Console output which is something I can copy and paste unlike the pretty Results tab most are familiar with
Content in case my blog goes away is
bool fireAgain = false;
string message = "{0}::{1} : {2}";
foreach (var item in Dts.Variables)
{
Dts.Events.FireInformation(0, "SCR Echo Back", string.Format(message, item.Namespace, item.Name, item.Value), "", 0, ref fireAgain);
}
SEQC Simulate Other
This is a sequence container that has your Disable logic directly added to it. Yes, I have the variable but since you have the inversion of the results, I didn't want to sully the test.
Yes it ran
Inside the sequence container is a copy/paste of the SCR Echo Back except I renamed it to "Yes it ran" and specified the only variable is System::TaskName If the task runs, the console will print the name of the task.
Test round 1
The output of the batch script will be "1" so we expect to see the Inner task fire. Let's check the console
SSIS package "C:\Users\bfellows\source\repos\SO_Trash\SO_Trash\SO_71067359.dtsx" starting.
Information: 0x0 at SCR Echo Back, SCR Echo Back: User::FileCount->1
Information: 0x0 at SCR Echo Back, SCR Echo Back: User::HasFiles->True
Information: 0x0 at Yes it ran, SCR Echo Back: System::TaskName->Yes it ran
SSIS package "C:\Users\bfellows\source\repos\SO_Trash\SO_Trash\SO_71067359.dtsx" finished: Success.
The program '[2268] DtsDebugHost.exe: DTS' has exited with code 0 (0x0).
Test Round 2
Clearing line 2 of the bat file
SSIS package "C:\Users\bfellows\source\repos\SO_Trash\SO_Trash\SO_71067359.dtsx" starting.
Information: 0x0 at SCR Echo Back, SCR Echo Back: User::FileCount->
Information: 0x0 at SCR Echo Back, SCR Echo Back: User::HasFiles->False
SSIS package "C:\Users\bfellows\source\repos\SO_Trash\SO_Trash\SO_71067359.dtsx" finished: Success.
The program '[75252] DtsDebugHost.exe: DTS' has exited with code 0 (0x0).

Get git result from commad using powershell and pipeline in c#

Hi I am trying to create some sort of hybrid using power shell and c# as managing tool, so simple script in powershell that checks repo status
$git_status = git status
Write-Output $git_status
Now using Pipeline and Run
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(powershellScript);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder output = new StringBuilder();
foreach (PSObject obj in results)
{
output.AppendLine(obj.ToString());
}
return output.ToString();
}
But I am getting empty result, when I run script in IDE power shell result looks like for example:
Write-Host "$git_status"
On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed:
(use "git reset HEAD ..." to unstage) modified: DeviceDatabase/Platforms.xml
What can i do to get that response back to c# procedure?
Write-Host will only print output to terminal, but it will not pass it to stdout. If you want to get the output - use Write-Output.
Write-Host is there to build UX: change output text color, etc. For anything else use Write-Output if you want to have your scripts as tools that can be combined to solve larger problems.
You can find a better explanation here. I'll use example code from the link to expand a little:
function Receive-Output
{
process
{
# catch input from pipe and print it in green
Write-Host $_ -ForegroundColor Green
}
}
# this will print green text, because it was passed to Receive-Output
Write-Output "this is a test" | Receive-Output
# this will print white text, because it was not passed to Receive-Output
# there's a good chance "this is a test" will already be printed by the time Receive-Output gets called
Write-Host "this is a test" | Receive-Output
Edit:
As git status prints a colorful text we can safely assume it's using Write-Host in PowerShell. Based on how Posh-Git reads git status into an object I've compiled a little example code that should solve your problem:
> $status = (git -c color.status=false status)
> Write-Output $status
This is the output I get (Windows 10, PowerShell Core 6.0):

C# process's exit code always returning Zero while running ADB commands? [duplicate]

We have an android device and as part of testing I need to excute a console test application on the target device. If the test application detects an error it returns -1.
I can use adb shell to run the test applications remotely on the target but I can't find a way of getting back the return code. I need this so I that I can build this into an automated test suite.
I could try grepping the console output for some failure text but that is a bit grubby. Does anyone know of a more elegant solution?
This is a workaround to get the exit code:
adb shell '{your command here} > /dev/null 2>&1; echo $?'
This is a wrapper around adb in Ruby:
def adb(opt)
input = "#{adb_command} #{opt[:command]} #{opt[:params]}"
puts "Executing #{input}...\n"
output = nil
exit_code = 0
def wait_for(secs)
if secs
begin
Timeout::timeout(secs) { yield }
rescue
print 'execution expired'
end
else
yield
end
end
wait_for(opt[:timeout]) do
case opt[:command]
when :install, :push, :uninstall
output, exit_code = `#{input}`, $?.to_i
when :shell
input = "#{adb_command} shell \"#{opt[:params]}; echo \\$?\""
output = `#{input}`.split("\n")
exit_code = output.pop.to_i
output = output.join("\n")
else
raise 'Error: param command to adb not defined!'
end
end
return if opt[:ignore_fail] and output =~ /#{opt[:ignore_fail]}/
raise output unless exit_code == 0
end
You could use Facebook's fb-adb, a "A better shell for Android devices" which "propagates program exit status instead of always exiting with status 0".

Call PS Script, Save String Returned

My PS script returns a string.
Function GetData {
Param(
[string]$id
)
Process
{
return "Value is $id"
}
GetData -id $arg
The below is the C# that calls the PS script:
PowerShell ps = PowerShell.Create();
string psScript = "GetData.ps1";
ps.AddScript(psScript);
// only takes one parameter
ps.AddParameter("25");
Collection<PSObject> results = ps.Invoke();
foreach (PSObject r in results)
{
Console.WriteLine(r.ToString());
}
Console.ReadLine();
Nothing returns.
I double checked the script and it does return a value when I pass in the path manually when calling the script directly in PowerShell. I also made sure that in the Properties of the project the Platform target is x64 (based on another question's error). I also tried to directly save the result in the Invoke method, but it gave an error, which showed that I have to actually save it in a collection, even though it's one record.
Forgot, also tried:
psParam = "25";
string psScript = "GetData.ps1 -arg'" + psParam + "'";
And no result on the console.
Tested this:
PowerShell ps = PowerShell.Create();
string psScript = ".\\GetData.ps1";
ps.AddCommand(psScript);
ps.AddArgument("25");
Collection<PSObject> results = ps.Invoke();
foreach (PSObject r in results)
{
Console.WriteLine(r.ToString());
}
Console.ReadLine();
And used most of the above and this errors because it says GetData.ps1 is not recognized as the name of a cmdlet, function, script file, or operable program. If I point directly to it by placing it on my C drive (C:\GetData.ps1), it does nothing.
Double check; inside the script I am calling the function on the last line:
GetData -id $arg
Is this correct?
Pay attention to your function. It gets an open curly brace '{', but not the matching close curly brace '}'. Your defective PowerShell code will emit an error not caught by your code.
After you correct this simple error, notice how you're calling your function. What is $arg? I assure you it's not any automatic variable. Have a look in about_automatic_variables...
P.S.: you'd better off asking enormously difficult questions like this one in social . technet . microsoft . com / Forums / windowsserver / en-US / home?forum=winserverpowershell . If you ha did it, the answer would have been posted many hours ago.
The problem is that "return" is not what you think.
In Powershell, the "return value" is the last value on the stack when execution ends. In your case, just omit the "return" keyword, and the string will come out as you expect.
Function return value in PowerShell
Alternatively, you can use Write-Output which would explicitly send the data to the output like a C-style return statement.
Note: Do NOT use Write-Host, as it writes directly to the powershell host, skipping the pipeline and never giving you a chance to see the value.

Categories

Resources