Jenkins PowerShell: Start-Process with Passthru returns a different process ID when executed in Jenkins but not on PowerShell - powershell

I'm experiencing a weird scenario where I want to open a .rdp file and get its Process ID on a Jenkins Pipeline.
My PowerShell Script (which based from this answer):
$app = Start-Process "$env:windir\system32\mstsc.exe" -ArgumentList "C:\Users\AzureUser\Desktop\MyRDP.rdp /h:900 /w:1600" -WindowStyle Minimized -PassThru
Write-Host $app.id
When I ran this on PowerShell it works as expected. However, when I tried to execute this script on a Jenkins Pipeline, it opens the .rdp file but returns a different process ID.
Here's the screenshot of the result.
I also tried enclosing it in an Invoke-Command to make sure that it runs on a 64-bit Powershell but it did not change a thing.
I'm wondering what might be the other possible cause of this. Any help is going to be appreciated. :)

The solution is just simple. I will post my answer anyway incase anyone might encounter the same problem I have. You just need to make sure that Jenkins runs on 64-bit. That's all and worked like a charm.

Related

Powershell - How to use Start-Process to call file from share/pass args in single line

To preface this, I am self teaching and brand new to scripting in general, let alone powershell.
After a cumulative 12 hours, my Google fu has run out.
I had a series of programs tailored to different models of computer we support that ran a staged series of installers from a fileshare. The program would check to see if the tech deploying the software was running it as admin, if not, it used a Start-Process line to elevate and run again.
It worked flawlessly, but we wanted to see if we could remove the need for the tech to enter r to run the scripts from the share.
In trying to figure out how to add -executionpolicy bypass to the arg list for Start-Process, I've hit a wall.
It now errors on trying to call to the fileshare to retrieve the parent script, before getting to the point where I can troubleshoot the bypass can of worms.
Below is my rough framework, remember I'm self taught by googling and using tutorials point.
$principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if($principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
#usually I have a get-childitem | foreach-object loop here that runs the files from the folder one by one in a specific order,
#it also checks to see if msiexec is running or not before trying to load and install files using a if-else>do-while combo
}
else
{
Start-Process -FilePath "powershell" -ArgumentList "$('-File "\\server\dir\foo".ps1')$($MyInvocation.MyCommand.Name)$('""')" -Verb runAs
}#this calls to a script that is a 1:1 copy of the code in the if{} block
This returns an error from the -File parameter that says it can't call the file because it doesn't exist.
What am I doing wrong?
How do I pass -executionpolicy bypass as an additional arg without breaking it further?
Is there a better way to do this?
Is there a neater way to automate this?
Please help me geniuses of StackOverflow before I start gnawing on my keyboard.

Launch PowerShell script into new window while passing variables

I've been using the site for a while, searching through the questions and answers, trying to map them to my scenario, but I'm either missing something, or what I'm looking to do isn't possible (at least the way I'm trying to do it), hence I'm hoping for a push in the right direction. Thanks in advance for reading.
I've been working on a fairly sizeable automation project. My main script performs a number of tasks, and generally works well, and reliably. At one stage of the script, I execute another PowerShell script, which was written by another team. I call the script as follows:
.\DeployMySQLProvider.ps1 -AzCredential $asdkCreds `
-VMLocalCredential $vmLocalAdminCreds `
-CloudAdminCredential $cloudAdminCreds
-PrivilegedEndpoint $ERCSip `
-DefaultSSLCertificatePassword $secureVMpwd -AcceptLicense
When I call it this way, from my main script, it works fine, however, this script uses and registers a DLL file during it's deployment, and locks it until the PowerShell window and session is closed. At the end of my main script, I have a cleanup phase, which can't complete it's job because of this locked DLL.
My thoughts therefore, were to launch the 2nd script into a new PowerShell window and session, either using Start-Process or Invoke-Expression, but I just can't seem to get either right. Most of the variables I'm passing through to the 2nd script aren't just strings, which is probably where I'm falling over. They are a mix of usernames and passwords (secure strings) along with $ERCSip which is a string.
Should I be looking at Start-Process / Invoke-Expression, or something else entirely? When I was testing with Start-Process, I had the following defined, but couldn't get the ArgumentList side working correcly for me (blank below):
Start-Process "$pshome\powershell.exe" -PassThru -Wait `
-Verb RunAs -ErrorAction Stop -ArgumentList ""
Any pointers in the right direction would be much appreciated.
Thanks!
I've used something similar to this in my scripting:
$scriptpath="c:\pathto\deploysqlProvider"
$a = "$scriptpath\DeployMySQLProvider.ps1 -AzCredential $asdkCreds `
-VMLocalCredential $vmLocalAdminCreds `
-CloudAdminCredential $cloudAdminCreds
-PrivilegedEndpoint $ERCSip ` "
-DefaultSSLCertificatePassword $secureVMpwd -AcceptLicense
Start-Process -Verb runas -FilePath powershell.exe -ArgumentList $a -wait -PassThru ;
Not sure if you need it to runas admin or not (-verb runas).
I'd suggest you then look for the Powershell process and path. So that if you have to kill this separate process you can.

How to run multiple Powershell Scripts at the same time?

so I have two .ps1 scripts that check for new Tasks every 60 seconds and I want to run them at the same time. I use them every day and starting them gets a little annoying.
Ideally, I want to write a script that I can run that runs those two for me.
The Problem is that as they don't stop at some point, I can't just start them one after the other and I can't find a command to open a new PS ISE instance. However, one instance can't run both scripts at the same time. The Ctrl+T Option would be perfect, but I can't find the equivalent command.
Does anyone have an idea on how to solve this?
Thanks!
I think what you want is something like
Start-Process Powershell.exe -Argumentlist "-file C:\myscript.ps1"
Start-Process Powershell.exe -Argumentlist "-file C:\myscript2.ps1"
In addition to that: Use Import-Module $Modulepath inside the scripts to ensure the availability of the modules.
If you have Powershell 3.0+ you could use workflows. they are similar to functions, but have the advantage that you can run commands parallel.
so your workflow would be something like this:
workflow RunScripts {
parallel {
InlineScript { C:\myscript.ps1 }
InlineScript { C:\myotherscript.ps1 }
}
}
keep in mind that a workflow behaves like a function. so it needs to be loaded into the cache first, and then called by running the RunScripts command.
more information:
https://blogs.technet.microsoft.com/heyscriptingguy/2013/01/09/powershell-workflows-nesting/
Use CTRL+T to create a new powershell instance (a tab is created, which is called powershell 2, I believe) inside Powershell ISE.
From the new Powershell tab you can now open a second powershell script and run it aside the script running in other powershell tabs.

wusa silent install error

I am trying to automate updating Powershell on Windows 7 using Windows6.1-KB2506143-x64.msu, and having a heck of a time. The following code works fine in a standalone ps1 file. And it works in my main ps1 file. But when run from a module it fails with exit code -2145124341. This is in PS v2, where negative exit codes are handled wrong, so that number is perhaps useless, and FWIW I have a good 40 other installers of various types that work from this module. However, this is my first attempt at automating msu files, so maybe there is a known interaction here that I haven't discovered yet? There's thousands of lines of code between the root ps1 file where this works and the module where it doesn't, so tracking down what is triggering the error is going to be a beast without some sort of trail to follow at the very least. So, anyone have an idea where I should start?
$filePath = 'wusa.exe'
$argumentList = '"\\PX_SERVER\Rollouts\Microsoft\Windows6.1-KB2506143-x64.msu" /quiet /norestart'
$exitCode = (Start-Process -filePath:$filePath -argumentList:$argumentList -wait -errorAction:stop -passThru).exitCode
Also, running wusa.exe leaves some detritus in the script folder, but only when it is run from the module. Is this an issue with the msu file, or just a bug in wusa? Or does it point at what is causing the issue perhaps?
I had hoped to get this update to work to enable some new features, but between not being able to automate and garbage being left behind, I am very close to abandoning that path and juts continuing to target v2. But hopefully someone can point me in the right direction as that is not my preferred solution at all.
a few toughts on first reading :
The ArgumentList parameter for Start-process needs an ARRAY to work well :
$argumentList = #( "\\PX_SERVER\Rollouts\Microsoft\Windows6.1-KB2506143-x64.msu", "/quiet", "/norestart" )
wusa.exe takes a log parameter : /log:c:\fso\install.log can you had it to your script for this particular package to check what happens ?
a powershell script trying to update powershell ... I'm not quite sure this is meant to work ... it's the only case in wich i'll backup on another scrpting language (people, please correct me if i'm wrong ... )
Please let me know the result of the wusa.exe /log command, thanks

How to get command prompt's output into a variable with PowerShell

I'm using PowerShell v3.0 to start a new cmd.exe process, in which I then load up the Visual Studio Command Prompt to perform a build, like so:
Start-Process cmd.exe -ArgumentList $cmdArgumentsToRunMsBuildInVsCommandPrompt -WindowStyle $windowStyle -Wait
This works, and it opens a new command prompt window and I can see the build happen, and then when the build is finished the command prompt window closes. I would like to be able to get the text that is written to the command prompt window and store it in a variable, in order to inspect if the build passed or not. I tried using this, but it doesn't work; the $buildOutput variable is empty:
Start-Process cmd.exe -ArgumentList $cmdArgumentsToRunMsBuildInVsCommandPrompt -WindowStyle $windowStyle -Wait -OutVariable buildOutput
Write-Host "Build output = $buildOutput"
This makes sense since the cmd.exe process isn't returning any text; it is just writing it to it's own window. Is there a way for me to be able to store that text in a variable for the original powershell script to use? I know that I can provide a parameter to MsBuild to have it write the build log to a file, but I'm looking for a solution that doesn't involve writing to a log file and having to delete it later.
Any suggestions are appreciated. Thanks!
<# EDIT #>
Thanks for all of the responses so far! A popular suggestion has been to just call MsBuild.exe directly without using cmd.exe. The reason I need to go through cmd.exe is some projects don't build successfully if called directly from MsBuild.exe (e.g. XNA projects). Instead I need to call MsBuild.exe from the Visual Studio Command Prompt so that (I assume) all of the required environmental variables are set. I guess I could just call the VS Command Prompt directly, but it will have the same problem as calling cmd.exe too. If I can't find the VS Command Prompt I fallback to calling MsBuild.exe directly, so those answers are still appreciated.
You can always capture the output of console programs this way:
$output = [string](nuget.exe)
Here I used nuget ($output will contain the available commands list), but you can of course use msbuild.exe with the appropriate arguments.
I've solved my problem using a suggestion from the first comment on my question, which was to write the build output to a log file, consume it, then delete it. This allows me to still show the user the cmd window with the build progress if they need, as well inspect the build output once the build completes. It also still allows me to run the build in another process, so we can use PassThru if we don't want our script to wait for the build to complete before continuing execution.
I've created an Invoke-MsBuild powershell module to make building with MsBuild a snap while providing lots of parameters for additional functionality (returns if build succeeded or failed, can show/hide build window, can wait/not wait for build to finish, can automatically show build log on failed builds, etc.). You can view and download the script from my blog.
$process = New-Object System.Diagnostics.Process;
$process.StartInfo.UseShellExecute = $false;
$process.StartInfo.RedirectStandardOutput = $true;
$process.StartInfo.FileName = "cmd.exe";
$process.StartInfo.Arguments = $cmdArgumentsToRunMsBuildInVsCommandPrompt;
$process.Start();
$outputStream = $process.StandardOutput;
$outputStream.ReadToEnd();
You could also redirect StandardError.
edit: I ended up using #David Brabant's answer
I ran into this problem and created an echo function
function echo()
{
$input
}
which let me do this
$output = &"cmd.exe" $args | echo