Jenkins Windows Batch Script failing to find COM object - jenkins

I have a script that updates an Install Shield .ism file (via InstallShield Automation Interface (2015)) with a version and ProductCode.
Dim projFile, projVersion
'check for arguments
If Wscript.Arguments.Count < 2 Then
WScript.Echo "InstallShield Version Utility" & _
vbNewLine & "1st argument is the full path to the .ism file" & _
vbNewLine & "2nd argument is the new version number Major.Minor.Build"
WScript.Quit 1
End If
'get the args
projFile = WScript.Arguments(0)
projVersion = WScript.Arguments(1)
'Create the end-user automation object
Dim ISWIProject
Set ISWIProject = CreateObject("ISWiAuto22.ISWiProject"): CheckError
'Open the project specified at the command line
ISWIProject.OpenProject projFile: CheckError
'change the product code to force major upgrades
Dim guidProductCode
guidProductCode = ISWIProject.GenerateGUID
ISWIProject.ProductCode = guidProductCode
'update the version
ISWIProject.ProductVersion = projVersion
'Save and close the project
ISWIProject.SaveProject: CheckError
ISWIProject.CloseProject: CheckError
WScript.Echo "Updated guid to: " & guidProductCode & ", version to: " & projVersion
Sub CheckError()
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & " " & Hex(Err) & ": " & Err.Description
WScript.Echo message
WScript.Quit 2
End Sub
I call this script with
cscript //Nologo setInstallShieldVersion.vbs <ISMPath> <VersionNumber>
When I run this via a command line on the machine (with the same user as my Jenkins service), it works fine and runs the script. However when Jenkins runs it via a Windows batch command, it gives the error
setInstallShieldVersion.vbs(17, 1) Microsoft VBScript runtime error: File not found: 'CreateObject'
the script used to work, then I had to update Jenkins (and subsequently rolled it back when the script started failing). Maybe that's part of the issue?
I've tried dumping the environmental variables with SET in both instances, and all the environmental variables are the same (except some Jenkins-specific ones). I've registered the DLL with regsvr32 multiple times. In both instances they are running in 32 bit processes. I've even opened up the permissions on the .dll (ISWiAutomation22.dll). Any other ideas on why it would work when running it one way and not the other?

Related

'No matching tab was found with the following properties: Title=Demo Web Shop*' when running testcase in Jenkins for a tosca testcase

I have integrated Tosca with jenkins to run in local .The test runs successfully on jenkins .However I see below error in result.xml file .The tests run fine in Tosca its only in Jenkins that I see this error .What do I do?
This is the result.xml output
<testcase name="Shipping Costs" time="12.7" timestamp="2022-10-07T16:04:47.1086587+05:30" log="- Failed Shipping Costs {LogInfo='Execution will be continued with the next TestCase, because there was an error in the current TestCase.'} + Passed Open Web Shop - Failed Navigate to Log In Page {LogInfo='No matching tab was found with the following properties: Title=Demo Web Shop*'} ">
- Failed Shipping Costs {LogInfo='Execution will be continued with the next TestCase, because there was an error in the current TestCase.'} + Passed Open Web Shop - Failed Navigate to Log In Page {LogInfo='No matching tab was found with the following properties: Title=Demo Web Shop*'}

How to debug PowerShell process whithout error message or exception

I am trying to run the following PowerShell script from within my .NET application:
try {
Start-Process "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -ArgumentList "--headless --disable-gpu --print-to-pdf=c:\myDir\file.pdf https://www.bing.com"
$x = "Complete"
$x | Out-File C:\myDir\error.txt
}
Catch {
$_ | Out-File C:\myDir\error.txt
}
Simply, the above will create a pdf based upon bing.com website
In my dev environment it runs fine as a PowerShell script. It also runs fine on the production server (again, as a PowerShell script).
The issue occurs when I invoke this PowerShell script from my web app on the production server. My C# code is
var command = "c:\myDir\ps.ps1";
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "powershell.exe";
psi.Arguments = command;
Process process = new Process();
process.StartInfo = psi;
process.Start();
This works fine on my dev machine. It fails on the production server. The error.txt file is written to disc which suggests it's not a permissions issue. However, the content of the error.txt file always shows "complete". It never errors.
So, it appears that the catch in the PowerShell script is never being hit. As such, no error message. There is no exception thrown in the C# code. Regardless, it isn't working.
How can I debug this?
Or, if easier, I'm happy to run the code directly instead of invoking the PowerShell script file but the following also does 'nothing'.
var command = $"\"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe\" -ArgumentList \"--no-sandbox --headless --disable-gpu --print-to-pdf={imagePath} {fullUrl}";
I was able to reproduce your problem. It is caused by the fact that web application on your production server is running under the user that is not currently logged in. It is running under identity of assigned application pool. Chrome has known issue of not working correctly if it's launched under the user different from currently logged user. If you check that link, you will see that issue was registered in December 2012 and still is not resolved. You could easily reproduce the problem if launch Chrome under the different user ("Run as different user" in shortcut context menu when called with pressed Shift). In this case Chrome will not open any page and will just show gray screen.
The workaround is to launch Chrome with --no-sandbox switch. Google actually does not recomment this. However if you run Chrome in automated way to access trusted source, I believe it's ok.
So to fix the problem modify start-process in the script in the following way:
start-process "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -ArgumentList "--no-sandbox --headless --disable-gpu --print-to-pdf=c:\myDir\file.pdf https://www.bing.com"
UPDATE
I have underestimated the problem at first. Now after additional research and many tried approaches I can propose solution that works.
I didn't manage to fix your current approach of direct launch of powershell and chrome from Web Application. Chrome just fails to start and following errors appear in Event log:
Faulting application name: chrome.exe, version: 64.0.3282.186, time stamp: 0x5a8e38d5
Faulting module name: chrome_elf.dll, version: 64.0.3282.186, time stamp: 0x5a8e1e3d
Exception code: 0x80000003
Fault offset: 0x00000000000309b9
Faulting process id: 0x11524
Faulting application start time: 0x01d3bab1a89e3b4f
Faulting application path: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Faulting module path: C:\Program Files (x86)\Google\Chrome\Application\64.0.3282.186\chrome_elf.dll
Report Id: e70a5a36-26a4-11e8-ac26-b8ca3a94ba80
This error occurrs even if you configure application pool to use identity of some existing (ordinary) user that could launch the chrome.
May be it's possible to configure IIS or application pool to prevent these errors but I have not found the way.
My proposal is to switch from starting powershell process from controller action to scheduling a task with Windows task scheduler.
Here are the steps that should be taken to accomplish this task:
On your production server create a user under which the Chrome will be started. I'll refer to created user as 'testuser'.
Login under testuser, start chrome, open some site. Without this step, the flow was not successfully, probably because of missing chrome user account.
Grant "Log on as a batch job" right for testuser. This step is required for successfull execution of scheduled tasks under testuser. The procedure is described in this answer
Add --no-sandbox argument to the script as I described in my initial answer.
Replace the code of Process.Start() with scheduling of the task job.
The easiest way to schedule a task from .Net is via TaskScheduler NuGet. Install it to your application and add following code:
string powerShellScript = #"c:\myDir\ps.ps1";
string userName = #"YOURCOMP\testuser";
string userPassword = "TestPwd123";
using (TaskService ts = new TaskService())
{
TaskDefinition td = ts.NewTask();
td.Triggers.Add(new RegistrationTrigger
{
StartBoundary = DateTime.Now,
EndBoundary = DateTime.Now.AddMinutes(1),
});
td.Settings.DeleteExpiredTaskAfter = TimeSpan.FromSeconds(5);
td.Actions.Add(new ExecAction("powershell.exe", powerShellScript));
ts.RootFolder.RegisterTaskDefinition($#"Print Pdf - {Guid.NewGuid()}", td, createType: TaskCreation.Create, userId: userName, password: userPassword, logonType: TaskLogonType.Password);
}
In above code snippet change the name and password for testuser.
With this approach your script is successfully executed and pdf is printed successfully.
Update by OP
If the above continues to fail, then again, check the Event Viewer logs. In this case, I had an issues with a message similar to The machine-default permission settings do not grant Local Activation permission for the COM Server application with CLSID {20FD4E26-8E0F-4F73-A0E0-F27B8C57BE6F} and APPID Unavailable but it was resolved by granting permissions for the CLSID. Further, try to run the task in task scheduler by itself, such as create a new task to simply launch notepad or similar to make sure that this is working with the account you want to test. In my case, I had to use the administrator account.
I think additional to what CodeFuller said having no sandbox with --no-sandbox option, you should also disable all extensions, sync and bookmarks.
The best is having a Guest session alias "browse without sign-in" with--bwsi option.
What is funny is that during testing I have found out that it is better, got better pdf printout, to disable extensions explicitly with --disable-extensions before doing --bwsi.
I have tested it and for me it works. I'm looking forward for your feedback.
Edit1 and Edit3 - removing try...catch and adding user & password and adding psuser specifics
You are probably on domain so I have adjusting the script to run as different user on domain (the user must have correct rights!)
First create your credentials file with:
Login to user e.g. psuser
Create the password file:
# Encrypt user password and save it to file
Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File 'C:\<your_path>\your_secret_password.txt'
Then run the below improved script with encrypted credentials:
$username = 'psuser' # This needs to be adjusted to correct user you are using
$domain = <your_domain> # adjust to your needs
$encrypted_passwd = get-content 'C:\<your_path>\your_secret_password.txt' | ConvertTo-securestring
# Setting process invocation parameters.
$process_start_info = New-Object -TypeName System.Diagnostics.ProcessStartInfo
$process_start_info.CreateNoWindow = $true
$process_start_info.UseShellExecute = $false
$process_start_info.RedirectStandardOutput = $true
$process_start_info.RedirectStandardError = $true
$process_start_info.UserName = $username
$process_start_info.Domain = $domain
$process_start_info.Password = $encrypted_passwd
$process_start_info.Verb = 'runas'
$process_start_info.FileName = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
$process_start_info.Arguments = '--no-sandbox --disable-extensions --bwsi --headless --disable-gpu --print-to-pdf=C:\prg\PowerShell\test\chrome_file.pdf https://www.bing.com'
# Creating process object.
$process = New-Object -TypeName System.Diagnostics.Process
$process.StartInfo = $process_start_info
# Start the process
[Void]$process.Start()
$process.WaitForExit()
# synchronous output - captures everything
$output = $process.StandardOutput.ReadToEnd()
$output += $process.StandardError.ReadToEnd()
Write-Output $output
During the script debugging I have encountered these errors:
a) When you want to validate against a AD server but it is not available:
Exception calling "Start" with "0" argument(s): "There are currently no logon servers available to service the logon request"
At C:\prg\PowerShell\test\chrome_print.ps1:56 char:12
+ [Void]$process.Start()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : Win32Exception
Exception calling "WaitForExit" with "0" argument(s): "No process is associated with this object."
At C:\prg\PowerShell\test\chrome_print.ps1:58 char:12
+ $process.WaitForExit()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException
You cannot call a method on a null-valued expression.
At C:\prg\PowerShell\test\chrome_print.ps1:61 char:12
+ $output = $process.StandardOutput.ReadToEnd()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\prg\PowerShell\test\chrome_print.ps1:62 char:12
+ $output += $process.StandardError.ReadToEnd()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
b) Missing domain information in the script:
Exception calling "Start" with "0" argument(s): "The stub received bad data"
At C:\prg\PowerShell\test\chrome_print.ps1:39 char:12
+ [Void]$process.Start()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : Win32Exception
Exception calling "WaitForExit" with "0" argument(s): "No process is associated with this object."
At C:\prg\PowerShell\test\chrome_print.ps1:41 char:12
+ $process.WaitForExit()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException
You cannot call a method on a null-valued expression.
At C:\prg\PowerShell\test\chrome_print.ps1:44 char:12
+ $output = $process.StandardOutput.ReadToEnd()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\prg\PowerShell\test\chrome_print.ps1:45 char:12
+ $output += $process.StandardError.ReadToEnd()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Prints the pdf
and the stderr messages:
[0313/112937.660:ERROR:gpu_process_transport_factory.cc(1009)] Lost UI shared context.
[0313/112937.662:ERROR:instance.cc(49)] Unable to locate service manifest for metrics
[0313/112937.662:ERROR:service_manager.cc(890)] Failed to resolve service name: metrics
[0313/112938.152:ERROR:instance.cc(49)] Unable to locate service manifest for metrics
[0313/112938.153:ERROR:service_manager.cc(890)] Failed to resolve service name: metrics
[0313/112942.876:INFO:headless_shell.cc(566)] Written to file C:\prg\PowerShell\test\chrom e_file.pdf.
Edit2 Adding windows account impersonation with ASP.NET
Impersonate a windows account with ASP.NET:
ASP.NET user is not passed into the new threads (by default). When you want to invoke PowerShell script it is invoked in other thread with different credentials (you can overcome that with above script when you have a dedicated domain authenticated user for running the above script). By default the script is executed under build-in account NT AUTHORITY\NETWORK SERVICE.
These steps are to overcome it on ASP.NET level:
1) Enable Windows Authentication in IIS
a) Install it first (this is windows 2008 R2 screenshot):
b) enable it on your IIS:
Change it to enabled:
2) Change your site's web.config to correctly handle impersonation
Edit the web.config file in your site’s directory. In order to execute the server side code of the current user's security context (AD).
Find the xml tag: <system.web> and add two new elements to enable the windows authentication
<authentication mode="Windows" />
<identity impersonate="True" />
3) To correctly write code to invoke in-process PowerShell script
You need to adjust your ASP.NET code in a way that you will have powershell Runspace and you will invoke the script inside the Runspace in a pipeline
A quick example:
// You need to create a Runspace. Each other pipeline you create will run in the same Runspace
// Do it only once, all others will be pipelined
RunspaceConfiguration powershellConfiguration = RunspaceConfiguration.Create();
var powershellRunspace = RunspaceFactory.CreateRunspace(powershellConfiguration);
powershellRunspace.Open();
// create a pipeline the cmdlet invocation
using ( Pipeline psPipeline = powershellRunspace.CreatePipeline() ){
// Define the command to be executed in this pipeline
Command script = new Command("PowerShell_script");
// Add any parameter(s) to the command
script.Parameters.Add("Param1", "Param1Value");
// Add it to the pipeline
psPipeline.Commands.Add(script);
try {
// Invoke() the script
var results = psPipeline.Invoke();
// work with the results
} catch (CmdletInvocationException exception) {
// Any exceptions here - for the invoked process
}
}
4) Modify aspnet.config to allow impersonation to cross threads
This step allows you to run as your current, impersonated, user.
You have to modify your servers’s aspnet.config file.
Add two xml elements to the configuration and runtime:
<configuration>
<runtime>
...
<legacyImpersonationPolicy enabled="true" />
<alwaysFlowImpersonationPolicy enabled="false" />
</runtime>
</configuration>
You have to redirect the stdin and stdout so that it sends it from powershell.exe back to the parent process (your web app). I modified your code sample to do this:
var command = "c:\myDir\ps.ps1";
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "powershell.exe";
psi.Arguments = command;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
Process process = new Process();
process.StartInfo = psi;
process.Start();
process.WaitForExit();
Console.WriteLine(process.StandardOutput);
Console.WriteLine(process.StandardError);

How to save MS Test's result in a Jenkins variable?

One of my Jenkins job is executing MSTest. I am passing the following command to
Execute Windows batch command:
del TestResults.trx
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\MSTest.exe" /testcontainer:D:\Projects\Jenkins\TestResultVerificationFromJenkins\TestResultVerificationFromJenkins\bin\Debug\TestResultVerificationFromJenkins.dll /resultsfile:TestResults.trx /nologo /detail:stdout
At the time of execution, Console Output is displaying the following values:
Starting execution...
Results Top Level Tests
------- ---------------
Passed TestResultVerificationFromJenkins.UnitTest1.PassTest
[stdout] = Test is passed*
1/1 test(s) Passed
Summary
Test Run Completed.
Passed 1
Total 1
Results file: C:\Program Files (x86)\Jenkins\jobs\JenkinsTestResultReader\workspace\TestResults.trx
Test Settings: Default Test Settings
In the post build step, I have to pass the MS test result "Test is passed" to a HTTP Request.
Is there any way to save this result in a Jenkins variable so that I can pass that to HTTP Request?
Regards,
Umesh
Since you are in the postbuild step, would parsing the console output for the test result and sending it off to the HTTP Request be an option for you?
For example, using Groovy Postbuild plugin, you could write a small script that could do this.
Perhaps something like:
if(manager.build.logFile.text.indexOf("Test Run Completed. Passed") >= 0)
manager.listener.logger.println (new URL("http://localhost?parameter=Test+is+passed")).getText()

Connecting to Active Directory

I have the following script from a book. When I try to run this, I get nothing output to the screen.
$objADSI = [adsi]""
$domain = $objADSI.distinguishedname
$userContainer = [adsi]("LDAP://cn=users," + $domain)
foreach($child in $userContainer) {
Write-Host $child.samaccountname
}
If I echo $userContainer, I get:
distinguishedName : {CN=Users,DC=company,DC=co,DC=uk}
Path : LDAP://cn=users,DC=company,DC=co,DC=uk
Do I need to run winrm quickconfig on the Active Directory server? The Active Directory server is running Windows Server 2003 standard edition. Or am I getting nothing returned for some other reason?
Change your foreach like this:
foreach($child in $userContainer.children)

Integrate Specs2 results with Jenkins

I want to integrate the Specs2 test results with Jenkins.
I was added the below properties in sbt:
resolver:
"maven specs2" at "http://mvnrepository.com/artifact"
libraryDependencies:
"org.specs2" %% "specs2" % "2.0-RC1" % "test",
System Property:
testOptions in Test += Tests.Setup(() => System.setProperty("specs2.outDir", "/target/specs2-reports")) //Option1
//testOptions in Test += Tests.Setup(() => System.setProperty("specs2.junit.outDir", "/target/specs2-reports")) //Option2
testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "console", "junitxml")
If I run the below command, it is not generating any specs reports in the above mentioned directory("/target/specs2-reports").
sbt> test
If I run the below command, it is asking for the directory as shown in the below error message:
sbt> test-only -- junitxml
[error] Could not run test code.model.UserSpec: java.lang.IllegalArgumentException: junitxml requires directory to be specified, example: junitxml(directory="xxx")
And it is working only if I give the directory as shown below:
sbt> test-only -- junitxml(directory="\target\specs-reports")
But sometimes its not generating all the specs report xmls (some times generating only one report, sometimes only two reports etc.).
If I give test-only -- junitxml(directory="\target\specs-reports") in the jenkins it is giving the below error.
[error] Not a valid key: junitxml (similar: ivy-xml)
[error] junitxml(
[error] ^
My main goal is, I want to generate the consolidated test reports in junit xml format and integrate with Jenkins. Kindly help me to solve my problem.
Best Regards,
Hari
The option for the junitxml output directory is: "specs2.junit.outDir" and the default value is "target/test-reports".
So if you don't change anything you could just instruct Jenkins to grab the xml files from "target/test-reports" which is what I usually do.
Also you might have to enclose your sbt commands in Jenkins with quotes. This is what I typically do:
"test-only -- html junitxml console"

Resources