How to get output from powershell process - powershell

Here's the code
function RunPowershellAsAdmin($CommandToBeExecuted)
{
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
#$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList "$CommandToBeExecuted" -Verbose
}
}
RunPowershellAsAdmin("& { Import-Module WebAdministration; if(Test-Path 'IIS:\Sites\$Website_Name') { Remove-WebSite -Name '$Website_Name'; } }")
-Verb and -RedirectStandardOutput are not in the same parameter, so i can not use -RedirectStandardOutput to get process output as per answer from this link.
I want to run the process in a hidden window, wait for it to return and get the error, output and exit code.
Is there any other solution?
Thanks in advance.

If you need access to both RunAs in addition to redirecting any of the standard streams, you'll need to use the System.Diagnostics.Process and System.Diagnostics.ProcessStartInfo classes directly. More information on how to handle the redirected stream can be found on MSDN.
$startInfo = new-object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell"
$startInfo.Arguments = "& { Import-Module WebAdministration; ... }"
$startInfo.Verb = "runas"
$startInfo.RedirectStandardOutput = $true
$process = [System.Diagnostics.Process]::Start($startInfo)
$output = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()

Related

Start Process With Admin Credential and use RunAs to Execute specific exe in Program File C

I have this Code working perfectly and open CMD but it cannot run specific exe like chrome.
$username = "username"
$password = "password"
$credentials = New-Object System.Management.Automation.PSCredential -ArgumentList #("soft\abbas_104",(ConvertTo-SecureString -String "Abbas1122" -AsPlainText -Force))
Start-Process -PassThru -FilePath powershell -Credential $credentials -ArgumentList '-noprofile -command &{Start-Process ', cmd, ' -Wait -verb runas}'
Testabc user have the administrator right.
//Run EXTERNAL APP AS AN ADMIN
var pass = new SecureString();
pass.AppendChar('t');
pass.AppendChar('e');
pass.AppendChar('s');
pass.AppendChar('t');
var ps1File = #"C:\Users\testabc\Desktop\LT_Admin.ps1";
ProcessStartInfo processAdmin;
processAdmin = new ProcessStartInfo();
processAdmin.UseShellExecute = false;
processAdmin.CreateNoWindow = true;
processAdmin.WindowStyle=System.Diagnostics.ProcessWindowStyle.Hidden;
processAdmin.Password = pass;
processAdmin.UserName = "testabc";
processAdmin.Domain = "soft";
processAdmin.FileName = #"C:\windows\system32\windowspowershell\v1.0\powershell.exe";
processAdmin.Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{ps1File}\"";
processAdmin.RedirectStandardOutput = true;
Process.Start(processAdmin);
In ps1File I have this code
Start-Process -FilePath "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -Verb RunAs
Working perfectly...

Start-Process and powershell.exe with splatting

I've been trying for a couple of days now to multi-thread a WPF GUI which will run a PS3.0 script once the button has been clicked. I cannot use start-job as that I would have to track (multiple sessions at once), however, I would like to just run the script in a separate process of PS- as if I were to open multiple instances of the script from a shortcut. And be able to just have an open PS window which will track the progress within the script itself.
Expected results would be starting a script in powershell.exe session and passing 3 arguments - 2 strings and 1 boolean value. Which are provided by the user.
So in ISE:
C:\temp\test.ps1 -argumentlist $computername $username $citrixtest
Works fine.
I've spent a few hours scouring through the internet only to find a thread where a start-job was recommended or a way to use a background worker- this is not what I want from the script.
So I would guess the invocation from a button click would be something of the like (some of the things I have tried)
$ComputerName = "testtext1"
$UserName = "testtext2"
$CitrixTest = $True
$command = "c:\temp\test.ps1"
$arg = #{
Computername = "$computername";
Username = "$username";
CitrixTest = "$citrixtest"
}
#$WPFStartButton.Add_Click({
Start-Process powershell -ArgumentList "-noexit -command & {$command} -argumentlist $arg"
#})
Does not pass arguments to test.ps1- it is, however, getting to the "pause" - so the script successfully launches.
Where test.ps1 is
$ComputerName
$UserName
$CitrixTest
pause
Caller:
function Caller {
Param (
$ScriptPath = "c:\temp\test.ps1"
)
$Arguments = #()
$Arguments += "-computername $ComputerName"
$Arguments += "-UserName $UserName"
$Arguments += "-citrixtest $citrixtest"
$StartParams = #{
ArgumentList = "-File ""$ScriptPath""" + $Arguments
}
Start-Process powershell #StartParams
}
Caller
Does not start the script altogether- PS window just closes- possibly a path to .ps1 script not being found.
And a different approach which also nets in the script starts but not passing the arguments
$scriptFile = '"C:\temp\test.ps1"'
[string[]]$argumentList = "-file"
$argumentList += $scriptFile
$argumentlist += $computername
$argumentlist += $UserName
$argumentlist += $CitrixTest
$start_Process_info = New-Object System.Diagnostics.ProcessStartInfo
$start_Process_info.FileName = "$PSHOME\PowerShell.exe"
$start_Process_info.Arguments = $argumentList
$newProcess = New-Object System.Diagnostics.Process
$newProcess.StartInfo = $start_Process_info
$newProcess.Start() | Out-Null
Is there a way to make this work as I want it to? Or should I just dig deeper into runspaces and try with that?
#Bill_Stewart I just realized I did not put the param(args) in my script...
And that's why it would not pull those variables as I would like them to. I will have to check when I'm back in the office if it's just that what I was missing.
Checked on my laptop that's running PS 5.1 and this seems to be working as intended
$testarg = #(
'-File'
"C:\temp\test.ps1"
"$computername"
"$username"
"$citrixtest"
)
Start-Process powershell.exe -ArgumentList $testarg
Where test.ps1 is:
param(
$ComputerName,
$UserName,
$citrixtest
)
$ComputerName
$UserName
$CitrixTest
pause

How to run a program as another user and add arguments in powershell?

We have a program that only updates when being run with the switch /t from an administrator account.
I came up with the CMD prompt version, but I'm new to powershell and having a hard time translating it to Powershell.
The CMD version is:
C:\Windows\System32\runas.exe /savecred /user:ourdomain\ouruseracct "C:\Program Files (x86)\ProjectMatrix\ProjectNotify\ProjectNotify.exe /t"
So far I got:
C:\Windows\System32\runas.exe /user:ourdomain\ouruseracct /savecred "powershell -c start-process -FilePath \"'C:\Program Files (x86)\ProjectMatrix\ProjectNotify\ProjectNotify.exe'\" -verb runAs"
Which runs powershell as admin and starts the program as admin but we need to pass the argument -t or /t to projectnotify.exe when running it.
I believe we need to make use of the -argumentlist but not sure how to word it.
I tried
$t = "-t"
Start-Process -FilePath "C:\Program Files (x86)\ProjectMatrix\ProjectNotify\projectnotify.exe" -ArgumentList $t -Verb runas
Which runs the program but not sure if that's how you pass the argument.
Extra work (troubleshooting):
$Cred = Get-Credential
$ProcInfo = New-Object -TypeName 'System.Diagnostics.ProcessStartInfo'
$ProcInfo.Domain = $Cred.GetNetworkCredential().Domain
$ProcInfo.UserName = $Cred.UserName
$ProcInfo.Password = $Cred.Password
$ProcInfo.FileName = "${Env:ProgramFiles(x86)}\ProjectMatrix\ProjectNotify\ProjectNotify.exe"
$ProcInfo.Arguments = '/t'
$ProcInfo.WorkingDirectory = "${Env:ProgramFiles(x86)}\ProjectMatrix\ProjectNotify"
$ProcInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Normal
$ProcInfo.Verb = 'RunAs'
$ProcInfo.UseShellExecute = $true
[System.Diagnostics.Process]::Start($ProcInfo)
After some more thought, here's a simpler way (in a single command even):
Start-Job -Credential (Get-Credential) -ScriptBlock {
$Dir = "${Env:ProgramFiles(x86)}\ProjectMatrix\ProjectNotify"
$StartArgs = #{
'FilePath' = "$Dir\ProjectNotify.exe"
'ArgumentList' = '/t'
'Verb' = 'RunAs'
'WindowStyle' = 'Normal'
'WorkingDirectory' = $Dir
'PassThru' = $true
}
Start-Process #StartArgs
} | Wait-Job | Receive-Job
My previous answer is at the bottom of this post now.
References:
about_Splatting
Get-Credential
Start-Process
Start-Job
Extra reading:
Import-CliXml
Export-CliXml
Assuming an on-demand script, you should create a pscredential object if you want to natively run this from powershell:
Launch.cmd
SET "PS=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe"
SET "SCRIPT=%SYSTEMDRIVE%\Path\to\wrapper.ps1"
%PS% -NoProfile -NoLogo -ExecutionPolicy Bypass -File "%SCRIPT%"
wrapper.ps1
$Cred = Get-Credential
# To avoid prompting every time:
#
# if (-not (Test-Path -Path '.\mycred.xml')) {
# Get-Credential | Export-CliXml -Path '.\mycred.xml'
# }
# $Cred = Import-CliXml -Path '.\mycred.xml'
$StartArgs = #{
'FilePath' = "$PSHOME\powershell.exe"
'ArgumentList' = '-NoProfile', '-NoLogo', '-File', '.\runas.ps1'
'Credential' = $Cred
}
Start-Process #StartArgs
runas.ps1
$StartArgs = #{
'FilePath' = "${Env:ProgramFiles(x86)}\ProjectMatrix\ProjectNotify\ProjectNotify.exe"
'ArgumentList' = '/t'
'Verb' = 'RunAs'
}
Start-Process #StartArgs
I know the question asks for arguements, but if you don't them, this works:
Start cmd.exe -Verb RunAs
You can also run this using the 'Run' window or search box:
powershell -command start cmd.exe -verb runas

Powershell stop-process not killing Logstash

I am writing a powershell script that allows Logstash to run for a certain amount of time and then stops the program by process id. Here is a basic version of the code:
$logstashFilepath = "C:\Users\emckenzie\Downloads\logstash-5.3.2\logstash-5.3.2\bin\logstash.bat"
$logstashArguments = "-f C:\users\emckenzie\Downloads\logstash-5.3.2\logstash-5.3.2\test_loader.conf"
$logstashprocess = Start-Process -FilePath $logstashFilepath -ArgumentList $logstashArguments -PassThru
$logstashid = $logstashprocess.Id
Write-Host $logstashid
Start-Sleep -s 60
Stop-Process $logstashid
In this test case Logstash only writes from stdin to stdout. When I run this program the output looks like this:
17120
Stop-Process : Cannot find a process with the process identifier 17120.
At C:\Users\emckenzie\Documents\Loaders\testLoader.ps1:13 char:13
+ Stop-Process <<<< $logstashid
+ CategoryInfo : ObjectNotFound: (17120:Int32) [Stop-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenId,Microsoft.PowerShell.Commands.StopProcessCommand
Is this a problem in Logstash or Powershell?
Any help would be much appreciated!
I ended up using NSSM to start Logstash as a service instead, and I control NSSM through Powershell.
# You must configure testlogstash using the GUI NSSM provides
$logstashFilepath = "C:\Users\emckenzie\Downloads\nssm-2.24\nssm-
2.24\win64\nssm.exe"
$start = "start testlogstash"
$stop = "stop testlogstash"
$logstashprocess = Start-Process -FilePath $logstashFilepath -ArgumentList
$start -PassThru
Start-Sleep -s 60
Start-Process -FilePath $logstashFilepath -ArgumentList $stop
After reading the comments on the original post I believe there is a solution for you. If you know the program running that needs to stay running until the job is finished:
$logstashprocess = Start-Process -FilePath $logstashFilepath -ArgumentList $logstashArguments -PassThru
$logstashid = $logstashprocess.Id
$Global:IsRunning = $false
Do {
$process = Get-Process -processname "NameOfProcessHere"
If ($process){
$IsRunning = $true
}else{
$IsRunning = $false
}
} While ($IsRunning -eq $true)
Stop-Process -processname "$logstashid"
Let me know if this is helpful, or if i'm not understanding the question.

Powershell start-process -wait parameter fails in remote script block

So here's a sample of what I'm trying to do:
Invoke-Command [Connection Info] -ScriptBlock {
param (
[various parameters]
)
Start-Process [some .exe] -Wait
} -ArgumentList [various parameters]
It connects to the other machine just fine, and launches the process fine. The problem is it doesn't wait for the process to complete before moving on. This causes issues. Any ideas?
Quick edit: why does the -Wait parameter fail when running the process remotely?
I ran into this once before, and IIRC, the workaround was:
Invoke-Command [Connection Info] -ScriptBlock {
param (
[various parameters]
)
$process = Start-Process [some .exe] -Wait -Passthru
do {Start-Sleep -Seconds 1 }
until ($Process.HasExited)
} -ArgumentList [various parameters]
This is the problem with Powershell version 3, but not version 2 where -Wait works as it should.
In Powershell 3 .WaitForExit() does the trick for me:
$p = Start-Process [some .exe] -Wait -Passthru
$p.WaitForExit()
if ($p.ExitCode -ne 0) {
throw "failed"
}
Just Start-Sleep until .HasExited - doesn't set .ExitCode, and it's usually good to know how your .exe finished.
You can also work around this by using the System.Diagnostics.Process class. If you do not care about the output you can just use:
Invoke-Command [Connection Info] -ScriptBlock {
$psi = new-object System.Diagnostics.ProcessStartInfo
$psi.FileName = "powershell.exe"
$psi.Arguments = "dir c:\windows\fonts"
$proc = [System.Diagnostics.Process]::Start($psi)
$proc.WaitForExit()
}
If you do care you can do something similar to the following:
Invoke-Command [Connection Info] -ScriptBlock {
$psi = new-object System.Diagnostics.ProcessStartInfo
$psi.FileName = "powershell.exe"
$psi.Arguments = "dir c:\windows\fonts"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$proc = [System.Diagnostics.Process]::Start($psi)
$proc.StandardOutput.ReadToEnd()
}
This will wait for the process to complete and then return the standard output stream.