Launch PowerShell script into new window while passing variables - powershell

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.

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.

Labeling a process to determine its execution status

I have a script D:\Script.ps1 that runs using a shortcut:
# The shortcut is located in the startup folder $Env:AppData\Microsoft\Windows\Start Menu\Programs\Startup\Script.lnk
# The object in this shortcut description
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File D:\Script.ps1
How can I see in the console that the process Script is working? How can I mark this process in script or in shortcut description so that I can see if it is working or has already completed the task and completed the work? I could track the process using an ID (Get-Process).ID, but I do not know the ID of my process when starting OS. I can’t Get it's Name easy and Set, as, for example, in Start-Job. I can not distinguish it from other running processes powershell via (Get-Process).ProcessName, they all have the ProcessName of powershell. What can I do to distinguish my powershell process from other powershell running ones? Thanks
If you can switch from using a batch file as a wrapper or can tolerate another PowerShell script to launch the real script. You can use Start-Process with the -PassThru parameter combined with Wait-Process to tell you when it's complete.
Something like:
$Process = Start-Process -FilePath C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -ArgumentList "-command .{read-host} -WindowStyle Normal" -passthru
$Process | Wait-Process
Write-Host "The process has completed."
However, if you need to observe the process completely apart from it there are a couple of other approaches I can think of.
Get-Process doesn't return a command line property but the WMI Win32_Process class does. You can match some aspect of the CommandLine to differentiate & isolate the process running the script of interest. Something like:
Get-CimInstance win32_Process -Filter "CommandLine LIKE '%d:\\script.ps1'"
You can use this directly or to get the PID or any other characteristic to further observe with. You can certainly get more elaborate with the filter.
Note: Typical best practice is to move the filter criteria to the left, but in this case you might think about using a PowerShell | Where-Object{}, as performance probably wouldn't be a concern. It might make it somewhat easier to filter based on CommandLine. I'd only do that if the existing filter was troublesome.
You can also add the command line column in Task Manager to watch just the same, but without scripting etc...
These aren't exactly eloquent solutions, but let me know if it's helpful.

start powershell.exe inside a ps1-script with a predefined variable

so this is my first post here on stackoverflow :-) hm,... would think i operate with powershell as an "experienced beginner", written some nice-working scripts for OS-automation in the last 2 years. no programming-skills, only little bit of scripting to make my life as sysadmin easier.
currently i have a tricky problem - excuse me in case this was already solved in another thread, but didn´t find a solution to it.
here the purpose of the code:
enable a normal windows-user (not member of local admin-group) to execute some scripts with administrative rights.
switch current user to a user with admin-rights >> solved. created a pscredential-object ($pscreds). works good.
start an elevated powershell-session to have the ability to do admin-stuff >> solved. powershell.exe -verb RunAs bla bla. works good.
launch a fix-named script with admin-rights >> solved.
problem itself:
script-name is not always the same one.... i want to enable the code to use the path and name of current running script ($Myinvocation.Mycommand.Definition).
$x = $myinvocation.MyCommand.Definition
Start-Process powershell.exe -Credential $pscreds -ArgumentList {
Start-Process powershell.exe -Verb RunAs -ArgumentList {
start-process powershell.exe -ArgumentList (-file "$x")
}
}
how to modify the code that the variable $x at -file "$x" takes the value defined in first line?
i found a workaround by myself write the path & scriptname to a temp-file and read it back to $x with "get-content". but i didn´t like this ugly solution and hoped solve this in a better way.
thanks for help and best greetings from germany
Ralph
I think that without getting into a whole host of Windows Auth issues doing that inside one script, I'd stick to what you are already talking about as a kludge - Try letting the non-admin edit that $x value in a file they have access to. Then run a script on schedule with an admin account that reads the file.

How do I get a Powershell process that was opened by another Powershell process?

I am running multiple PowerShell scripts at once. I would like to be able to wait on certain ones to finish before opening new scripts. Basically, I was thinking if I could find the command line option that ran it something like "powershell.exe -Path "<script dir>" that would do it.
I tried doing a Get-Process | gm to find any parameters that I could call to get that information and I didn't see any (doesn't mean they aren't there) I tried looking through Task Manager to see if I could view something through the gui that I could link to but that didn't help either.
I hope I can get something like
Start-Process -FilePath ".\<script>.ps1" -ArgumentList "<args>"
do
{
sleep 10
}
until ((Get-Process -ProcessName "PowerShell" | where "<paramater>" -EQ ".\<script>")
I need to wait until that process is done but I don't want to put a wait at the end of the Start-Process because after that Start-Process kicks off I need some other items to go to while my .\ is running. I just need it to wait before another section of script kicks off.
Have a look at the "Job" cmdlets https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_jobs?view=powershell-6
And the $PID automatic variable, this will give the process ID of the current PowerShell session.

Run Powershell script that uses -List (parameter) with alternate credentials that

I was struggling to get this simple (?) function working today.
I have a PowerShell script that reads computer names from a txt-based file. It works fine when run from a PowerShell session by the following one-liner:
./"Server Health Check.ps1" -List One-off.txt
As you can see, it's got a long file name, so it's wrapped with quotes.
However, I'm building a PowerShell GUI form with radio boxes that will pass on a choice for a text file that will be used to a call the script. Trick is, the script needs to be run with alternate admin account, and i'm not clear how to make that work.
For another script I've got that doesn't use I know i can use something along the lines of the following, this uses the old DOS "runas", however, it doesn't work with the -list function.
invoke-command -scriptblock {runas.exe /user:domain\$Env:Username"admin" "powershell.exe -file \"\\Server\c$\LONG FOLDER\Server Health Check.PS1""}
So, in a nutshell, how do get a script to launch with alternate credentials that reads a parameter (-List) from the command line? I'm also keen to preserve my directory structure, which includes folders with spaces. The script is titled: "Server health check.ps1"
The last thing I tried was the following
$ScriptPath = "C:\SCRIPTS FOLDER\Server Health Check.ps1"
$ArgList = "-List C:\SCRIPTS FOLDER\One-off.txt"
Invoke-Command -filepath $ScriptPath -Credential DragonBallDomain\$Env:UserName"Admin" -ArgumentList $ArgList
The result was the following message:
Invoke-Command : Parameter set cannot be resolved using the specified named parameters.
I'm almost certain this is do-able by invoke-command or start-process, it's just a matter of getting the correct formatting? I'm probably missing a / or a ' or "" somewhere in my trials with start-process or invoke-command.
Any help appreciated!
Update for April 30:
I've tried some more to make this work, i'm close, but still not quite there.
$LongScriptPath = resolve-path Script.ps1
$LongFolderPath = \\UNC\PATH TO FOLDER\WITH LONG NAME\
start-process -filepath powershell.exe -argumentlist " -file``"$($FilePath.path)`"" -cred DOMAIN\USERID -WorkingDirectory "$LongFolderPath"
Adding the -credential is what causes an error that states that the -file parameter is invalid. I'm sure there's a way to do this.
Note: Completely rewritten after the requirements became clearer.
To run a command as a different user locally, use Start-Process -Credential ...
That is what you've attempted in your update in principle, but there are problems with how you're passing parameters; try this instead:
$LongScriptPath = resolve-path Script.ps1
$LongFolderPath = '\\UNC\PATH TO FOLDER\WITH LONG NAME\'
start-process `
powershell.exe `
-ArgumentList '-file', $LongScriptPath, '-List', 'One-off.txt' `
-Credential DOMAIN\USERID `
-WorkingDirectory $LongFolderPath
The key to making this work is to pass all parameters to pass to powershell.exe as an array via Start-Process's -ArgumentList parameter, which means that the parameters must be ,-separated.
Note how an array is always parsed in expression mode, which means that literal string elements such as -file and -List must be quoted.
It is important in general to understand the difference between PowerShell's two fundamental parsing modes, argument mode and expression mode, and which is applied when - see https://technet.microsoft.com/en-us/library/hh847892.aspx
Add -Wait to wait for the script to finish; Start-Process is asynchronous by default (all PS cmdlets named Start-* are).
Caveat: For commands invoked as a different user, you can only wait from an elevated prompt.
If it isn't, the command will still execute, but will do so asynchronously, and you'll get an Access denied error message in the current console; in effect, -Wait is ignored.
Only if not running as a different user: Add -NoNewWindow -Wait if you want to run the script in the current console window; Start-Process opens a new window by default for console applications such as powershell.exe and cmd.exe.
If you do run the command as a different user, -NoNewWindow is quietly ignored.
As for the original symptom and why using Invoke-Command to run a command locally as a different user is ill-advised:
Invoke-Command -Credential ... requires that the -ComputerName parameter be specified too.
Run Get-Help Invoke-Command to see all parameter sets that involve the -Credential parameter. The OP's original command had only -Credential, but not -ComputerName, which caused PS to complain that no parameter set could be unambiguously identified.
Once you use -ComputerName, PowerShell remoting is invariably used, even if you specify . - the local computer - as the only computer to target.
Using remoting has two implications:
Remoting is not available by default, and must be configured on the target computer (the local computer, in this case).
Using remoting requires invocation with admin privileges.
In short:
While you can perform purely local invocations with Invoke-Command, you cannot do so as another user, because that invariably involves remoting.
Start-Process, by contrast, solely exists to run commands locally, optionally as a different user.