Pass command to powershell start-Process in Argument-List - powershell

I want to pass a cmdlet to be executed immediately in child Process.
---> $cmd = $(Get-Item -FORCE "PATH\to\Folder").Attributes= "Normal"
Start-Process powershell -ArgumentList " multiple $cmd Here"
PS : when i use { } , () or " " in -ArgumentList i get different behaviour anyone care to explain why ?.

Related

Start-Process ArgumentList parameter not working

I try to install .msu package using Poweshell. My code:
$Args = #(('"' + $Path_Temp + '\' + $Hotfix[1] + '.msu' + '"'), '/norestart')
echo $Args
Start-Process -FilePath ($Env:SystemRoot + '\System32\wusa.exe') -ArgumentList $Args -Verb RunAs -Wait
echo outputs this:
"C:\Users\MyUser\AppData\Local\Temp\Windows6.1-KB2758857-x64.msu"
/norestart
All looks good, but in the end wusa warns me about incorrect usage. It works well when I pass only the first argument (which is the path to .msu file) to ArgumentList. My code does not work when I pass multiple arguments, why? I use Powershell v5.1.14409.1005

Passing arguments to Powershell script

I have a script that takes in a max of 3 parameters - username, password and distro.
The script needs to run as administrator since it checks certain things are enabled and can only be done as an admin.
# the command line is:
# linux-docker <username> <password> <distro>
# if no distro is specified then Debian is used.
param ([Parameter(Mandatory)]$username, [Parameter(Mandatory)]$password, $distro='Debian')
# check if we are in admin mode and switch if we aren't
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if (-Not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs;
Read-Host -Prompt "Failure: Press Enter to exit"
exit;
}
}
# ... rest of script
However restarting the script prompts the user for username and password. I would like to pass the arguments to the promoted script.
I first thought that adding $username,$password and $distro to the Start-Process command.
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" $username $password $debian" -Verb RunAs;
but that exits with the "Failure" message.
So I looked at -ArgumentList but that dies processing that line:
Start-Process : A positional parameter cannot be found that accepts argument '-NoProfile -ExecutionPolicy Bypass -File "C:\Users\Graham Reeds\Documents\linux-docker.ps1"'.
At C:\Users\Graham Reeds\Documents\linux-docker.ps1:15 char:9
+ Start-Process powershell.exe "-NoProfile -ExecutionPolicy Byp ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand
Failure: Press Enter to exit:
It is probably something simple but I am a noob with Powershell.
Using the -ArgumentList parameter should work, but for the parameters sent to the script, you need to
get their names and values from the BoundParameters hash:
$currentPrincipal = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (!$isAdmin) {
$argList = '-NoLogo', '-NoProfile', '-NoExit', '-ExecutionPolicy Bypass', '-File', ('"{0}"' -f $PSCommandPath)
# Add script arguments
$argList += $MyInvocation.BoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key)", "$($_.Value)"}
try {
Start-Process PowerShell.exe -WorkingDirectory $pwd.ProviderPath -ArgumentList $argList -Verb Runas -ErrorAction Stop
# exit the current script
exit
}
catch {
Write-Warning "Failed to restart script '$PSCommandPath' with runas"
}
}
# rest of the script
P.S. Personally I like to always type-cast parameters and when possible make it clear in what order the mandatory parameters should be given if not used Named:
param (
[Parameter(Mandatory = $true, Position = 0)][string] $username,
[Parameter(Mandatory = $true, Position = 1)][string] $password,
[string] $distro='Debian'
)

How run a command in PowerShell from a specified directory and wait for it to complete before moving on?

I have a script that works to run an executable and wait until done in PS but I need to modify it to use a path defined in a variable earlier in the script.
Working:
$job = Start-Job `
-InitializationScript { Set-Location C:\MyDirectory\ } `
-ScriptBlock { C:\MyDirectory\MyCmdLineExecutable.exe }
Wait-Job $job
Receive-Job $job
Not working:
$Path = "C:\MyDirectory\"
$ExePath = $path+"MyCmdLineExecutable.exe"
$job = Start-Job `
-InitializationScript { Set-Location $Path } `
-ScriptBlock { $ExePath }
Wait-Job $job
Receive-Job $job
Here's the error:
Set-Location : Cannot process argument because the value of argument "path" is null. Change the value of argument "path" to a non-null value.
At line:1 char:2
+ Set-Location $Path
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Set-Location], PSArgumentNullException
+ FullyQualifiedErrorId : ArgumentNull,Microsoft.PowerShell.Commands.SetLocationCommand
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
49 Job49 BackgroundJob Failed False localhost $ExePath
Running startup script threw an error: Cannot process argument because the value of argument "path" is null. Change the value of argument "path" to a non-null value..
+ CategoryInfo : OpenError: (localhost:String) [], RemoteException
+ FullyQualifiedErrorId : PSSessionStateBroken
Combining info from Start-Job docs with About_Scopes article, I am certain of that you need to use -InputObject parameter:
Specifies input to the command. Enter a variable that contains the
objects, or type a command or expression that generates the
objects. In the value of the ScriptBlock parameter, use the
$Input automatic variable to represent the input objects.
$Path = "C:\MyDirectory\"
$ExePath = $path+"MyCmdLineExecutable.exe"
$job = Start-Job -InputObject #( $Path, $ExePath) `
-InitializationScript { <# $Input variable isn't defined here #> } `
-ScriptBlock {
$aux = $Input.GetEnumerator()
Set-Location $aux[0]
& $aux[1] }
Wait-Job $job
Receive-Job $job
BTW, to run commands that are stored in variables and represented by strings, use & Call operator. See the difference:
$ExePath ### output only
& $ExePath ### invocation
I think you want Start-Process with the -Wait parameter. You can also specify the -WorkingDirectory parameter to specify the working directory for the new process. Example:
Start-Process notepad -WorkingDirectory "C:\Program Files" -Wait
Write-Host "Finished"
When you run this script, Notepad will open but the script won't continue until it closes. When you close Notepad, the Write-Host line runs.

Unable to use start-process with start-job

I am trying to execute an installation via start-process but i want it to execute as a job so i can execute a few other statements while also being able to check the status of the installation as it runs in the background.
Here is a section of the code i am trying to execute -
$SetupPath = "C:\Test Installs"
# Enclose the path to setup.exe in quotes
$Setup = "`"" + "$SetupPath\setup.exe" + "`""
$command = "{$SetupProcess=" + "Start-process" + " " + `
"$Setup" + " "+ "-ArgumentList" + " " + `
"/config config.xml" + " " + "-Wait -PassThru" + "}"
# The above command equals-> {$SetupProcess=Start-process "C:\Test Installs\setup.exe" -ArgumentList /config config.xml -Wait -PassThru}
#Change string to Scriptblock
$ScriptBlock = [Scriptblock]::Create($command)
$job1 = Start-Job -ScriptBlock $ScriptBlock -Name "SetupJob"
When I run this and try to get back the result via Receieve-Job i only get back the command string I passed via script block. It appears the Start-process command is not executing. Is there something i am missing?
Get rid of the {} in your $command definition. [ScriptBlock]::Create() expects some text in which it will wrap in a scriptblock. You can also simplify this:
$SetupPath = "C:\Test Installs"
# Enclose the path to setup.exe in quotes
$Setup = "`"$SetupPath\setup.exe`""
$command = "SetupProcess = Start-process `"$Setup`" -ArgumentList `"/config config.xml`" -Wait -PassThru"

How to make powershell wait for exe to install?

So i've read every single answer related to this question but none of them seem to be working.
I've got these lines going on in the script:
$exe = ".\wls1033_oepe111150_win32.exe"
$AllArgs = #('-mode=silent', '-silent_xml=silent_install.xml', '-log=wls_install.log"')
$check = Start-Process $exe $AllArgs -Wait -Verb runAs
$check.WaitForExit()
After this runs I have a regex check on the installed files that replaces some specific strings, but no matter what I try to do it continues to run the regex check while the program is installing.
How can I make it so that the next line doesn't execute until it finishes installing the exe? I've also tried piping to Out-Null with no luck.
I created a test executable that did the following
Console.WriteLine("In Exe start" + System.DateTime.Now);
System.Threading.Thread.Sleep(5000);
Console.WriteLine("In Exe end" + System.DateTime.Now);
Then wrote this powershell script which as expected waits for the exe to finish running before outputting the text "end of ps1" and the time
push-location "C:\SRC\PowerShell-Wait-For-Exe\bin\Debug";
$exe = "PowerShell-Wait-For-Exe.exe"
$proc = (Start-Process $exe -PassThru)
$proc | Wait-Process
Write-Host "end of ps1" + (Get-Date).DateTime
This following powershell also correctly waits for the exe to finish.
$check = Start-Process $exe $AllArgs -Wait -Verb runas
Write-Host "end of ps1" + (Get-Date).DateTime
Adding the WaitForExit call gives me this error.
You cannot call a method on a null-valued expression.
At line:2 char:1
+ $check.WaitForExit()
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
However this does work
$p = New-Object System.Diagnostics.Process
$pinfo = New-Object System.Diagnostics.ProcessStartInfo("C:\PowerShell-Wait-For-Exe\bin\Debug\PowerShell-Wait-For-Exe.exe","");
$p.StartInfo = $pinfo;
$p.Start();
$p.WaitForExit();
Write-Host "end of ps1" + (Get-Date).DateTime
I think maybe you are confusing the Start-Process powershell command with the .NET framework Process object