PowerShell script to run application (with commands) - powershell

I am trying to run an application from C:\Program Files\APP\app.exe with the application built in commands. When I run from the command prompt, I can get the result I wanted. But I would like to use the script which will check other components of servers along with this one to avoid running this command manually. I tried both of the mentioned scripts below & I am not getting any output. It just opens a command prompt window, runs the result, and closes the command prompt,but I would like to get the output in an output file. Any suggestions? Please let me know.
$Output = "C:\Information.txt"
Start-Process -FilePath "C:\Program Files\APP\app.exe" -ArgumentList "query mgmtclass" | Out-File $Output
Additionally, I also tried -
$Output = "C:\Information.txt"
Start-Process -FilePath "C:\Program Files\APP\app.exe" -PipelineVariable "query mgmtclass" | Out-File $Output
I was also thinking that I can write a batch file & get output written in the temp directory & get those output using the command mentioned below -
Get-Content -Path 'C:\Program Files\tivoli\tsm\baclient\dsmerror.log' | select-object -last 15

Can you try using the RedirectStandardOutput parameter instead of | Out-File:
$Output = "C:\Information.txt"
Start-Process -FilePath "C:\Program Files\APP\app.exe" -PipelineVariable "query mgmtclass" -RedirectStandardOutput $Output
Update:
The error you are getting ("Missing an argument") means exactly what it says. I can't see the line of code you ran to get the error, but I can replicate by omitting the value of RedirectStandardOutput. This example uses splatting so the line of code is not so long, and you can see more clearly what RedirectStandardOutput is:
$Output = "C:\Information.txt"
#{
FilePath = "C:\Program Files\APP\app.exe"
PipelineVariable = "query mgmtclass"
RedirectStandardOutput = $Output
} | % { Start-Process #_ }

Related

How can I print the output of Rust's cargo to a text file? [duplicate]

I need to collect the standard output and error log from several processes into one single log file.
So every output must append to this log file.
I want to call all the jobs with lines like this:
$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait
Where do I have to put the information to append?
In order to append to a file you'll need to use a slightly different approach. You can still redirect an individual process' standard error and standard output to a file, but in order to append it to a file you'll need to do one of these things:
Read the stdout/stderr file contents created by Start-Process
Not use Start-Process and use the call operator, &
Not use Start-Process and start the process with .NET objects
The first way would look like this:
$myLog = "C:\File.log"
$stdErrLog = "C:\stderr.log"
$stdOutLog = "C:\stdout.log"
Start-Process -File myjob.bat -RedirectStandardOutput $stdOutLog -RedirectStandardError $stdErrLog -wait
Get-Content $stdErrLog, $stdOutLog | Out-File $myLog -Append
The second way would look like this:
& myjob.bat 2>&1 >> C:\MyLog.txt
Or this:
& myjob.bat 2>&1 | Out-File C:\MyLog.txt -Append
The third way:
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "myjob.bat"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = ""
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$output = $p.StandardOutput.ReadToEnd()
$output += $p.StandardError.ReadToEnd()
$output | Out-File $myLog -Append
Like Unix shells, PowerShell supports > redirects with most of the variations known from Unix, including 2>&1 (though weirdly, order doesn't matter - 2>&1 > file works just like the normal > file 2>&1).
Like most modern Unix shells, PowerShell also has a shortcut for redirecting both standard error and standard output to the same device, though unlike other redirection shortcuts that follow pretty much the Unix convention, the capture all shortcut uses a new sigil and is written like so: *>.
So your implementation might be:
& myjob.bat *>> $logfile
Andy gave me some good pointers, but I wanted to do it in an even cleaner way. Not to mention that with the 2>&1 >> method PowerShell complained to me about the log file being accessed by another process, i.e. both stderr and stdout trying to lock the file for access, I guess. So here's how I worked it around.
First let's generate a nice filename, but that's really just for being pedantic:
$name = "sync_common"
$currdate = get-date -f yyyy-MM-dd
$logfile = "c:\scripts\$name\log\$name-$currdate.txt"
And here's where the trick begins:
start-transcript -append -path $logfile
write-output "starting sync"
robocopy /mir /copyall S:\common \\10.0.0.2\common 2>&1 | Write-Output
some_other.exe /exeparams 2>&1 | Write-Output
...
write-output "ending sync"
stop-transcript
With start-transcript and stop-transcript you can redirect ALL output of PowerShell commands to a single file, but it doesn't work correctly with external commands. So let's just redirect all the output of those to the stdout of PS and let transcript do the rest.
In fact, I have no idea why the MS engineers say they haven't fixed this yet "due to the high cost and technical complexities involved" when it can be worked around in such a simple way.
Either way, running every single command with start-process is a huge clutter IMHO, but with this method, all you gotta do is append the 2>&1 | Write-Output code to each line which runs external commands.
Maybe it is not quite as elegant, but the following might also work. I suspect asynchronously this would not be a good solution.
$p = Start-Process myjob.bat -redirectstandardoutput $logtempfile -redirecterroroutput $logtempfile -wait
add-content $logfile (get-content $logtempfile)

Wait for file to finish writing before performing next script [duplicate]

I have a PowerShell 1.0 script to just open a bunch of applications. The first is a virtual machine and the others are development applications. I want the virtual machine to finish booting before the rest of the applications are opened.
In bash I could just say "cmd1 && cmd2"
This is what I've got...
C:\Applications\VirtualBox\vboxmanage startvm superdooper
&"C:\Applications\NetBeans 6.5\bin\netbeans.exe"
Normally, for internal commands PowerShell does wait before starting the next command. One exception to this rule is external Windows subsystem based EXE. The first trick is to pipeline to Out-Null like so:
Notepad.exe | Out-Null
PowerShell will wait until the Notepad.exe process has been exited before continuing. That is nifty but kind of subtle to pick up from reading the code. You can also use Start-Process with the -Wait parameter:
Start-Process <path to exe> -NoNewWindow -Wait
If you are using the PowerShell Community Extensions version it is:
$proc = Start-Process <path to exe> -NoNewWindow -PassThru
$proc.WaitForExit()
Another option in PowerShell 2.0 is to use a background job:
$job = Start-Job { invoke command here }
Wait-Job $job
Receive-Job $job
Besides using Start-Process -Wait, piping the output of an executable will make Powershell wait. Depending on the need, I will typically pipe to Out-Null, Out-Default, Out-String or Out-String -Stream. Here is a long list of some other output options.
# Saving output as a string to a variable.
$output = ping.exe example.com | Out-String
# Filtering the output.
ping stackoverflow.com | where { $_ -match '^reply' }
# Using Start-Process affords the most control.
Start-Process -Wait SomeExecutable.com
I do miss the CMD/Bash style operators that you referenced (&, &&, ||). It
seems we have to be more verbose with Powershell.
Just use "Wait-process" :
"notepad","calc","wmplayer" | ForEach-Object {Start-Process $_} | Wait-Process ;dir
job is done
If you use Start-Process <path to exe> -NoNewWindow -Wait
You can also use the -PassThru option to echo output.
Some programs can't process output stream very well, using pipe to Out-Null may not block it.
And Start-Process needs the -ArgumentList switch to pass arguments, not so convenient.
There is also another approach.
$exitCode = [Diagnostics.Process]::Start(<process>,<arguments>).WaitForExit(<timeout>)
Including the option -NoNewWindow gives me an error: Start-Process : This command cannot be executed due to the error: Access is denied.
The only way I could get it to work was to call:
Start-Process <path to exe> -Wait
The question was asked long ago, but since answers here are kind of references, I may mention an up to date usage. With the current implementation of PowerShell (it's 7.2 LTS as of writing) you can use && as you would do in Bash.
Conditionally execute the right-hand side pipeline based on the success of the left-hand side pipeline.
# If Get-Process successfully finds a process called notepad,
# Stop-Process -Name notepad is called
Get-Process notepad && Stop-Process -Name notepad
Further info on documentation
Taking it further you could even parse on the fly
e.g.
& "my.exe" | %{
if ($_ -match 'OK')
{ Write-Host $_ -f Green }
else if ($_ -match 'FAIL|ERROR')
{ Write-Host $_ -f Red }
else
{ Write-Host $_ }
}
Building upon #Justin & #Nathan Hartley 's answers:
& "my.exe" | Out-Null #go nowhere
& "my.exe" | Out-Default # go to default destination (e.g. console)
& "my.exe" | Out-String # return a string
the piping will return it in real-time
& "my.exe" | %{
if ($_ -match 'OK')
{ Write-Host $_ -f Green }
else if ($_ -match 'FAIL|ERROR')
{ Write-Host $_ -f Red }
else
{ Write-Host $_ }
}
Note: If the executed program returns anything other than a 0 exitcode, the piping will not work. You can force it to pipe with redirection operators such as 2>&1
& "my.exe" 2>&1 | Out-String
sources:
https://stackoverflow.com/a/7272390/254276
https://social.technet.microsoft.com/forums/windowsserver/en-US/b6691fba-0e92-4e9d-aec2-47f3d5a17419/start-process-and-redirect-output-to-powershell-window
There's always cmd.
cmd /c start /wait notepad
Or
notepad | out-host

Executing a batch file from local server to multiple remote servers using powershell

I would like execute the below batch file (using PowerShell) from local server which will get results from multiple remote servers and I would like to get those results in C:\temp folder.
#echo off
cd "C:\Program Files\Tivoli\TSM\baclient"
dsmc.exe q mgmtclass > C:\temp\TSMmgmtclass.txt
After that, would like to get those output results using PowerShell script as mentioned below.
Get-Content -Path 'C:\Program Files\tivoli\tsm\baclient\dsmerror.log' | select-object -last 15
The best way to do this is probably using invoke-command, and eliminating the .bat file completely. it would look something like this
$scriptBlock = {
& "C:\Program Files\Tivoli\TSM\baclient\dsmc.exe" q mgmtclass
return $return
}
invoke-command -computername $computernames -scriptblock $scriptBlock | out-file $logfile
In this case $computernames would be an array holding the name of each computer you want to run the command against and $logfile is just the path you want the contents output to.

Printing with Powershell and files in folders

I have a script which does some onsite printing. It doesnt work too well at the moment as the below runs for various file types which are sent to a folder to print, but the problem is it will only print 1 document at a time.
Start-Process –FilePath “c:\tests\*.docx” –Verb Print
I had the idea of doing this to get around it:
get-ChildItem "C:\Tests\*.docx" | `
foreach-object {
start-process -verb Print
}
This doesnt seem to work though. So then i tried this:
get-childitem "C:\Tests\*.xlsx" | `
foreach-object {
Start-Process -Filepath "C:\Program Files\Microsoft Office\Office14\EXCEL.exe" –Verb Print }
Also no luck,
Returns this error:
Start-Process : This command cannot be run due to the error: No application is associated with the specified file for this operation.
I think i am maybe not visualing the process here. Any ideas at all anyone on how to achieve printing of every file in a folder via powershell?
Windows 7 64 bit and $PSVersion = 5.0
Thanks in advance
You are very close, start-process needs the full path and name of the file:
Get-ChildItem "c:\tests\*.docx" | ForEach-Object {start-process $_.FullName –Verb Print}
Using a foreach loop should help you too:
$files = Get-ChildItem "c:\tests\*.docx"
foreach ($file in $files){
start-process -FilePath $file.fullName -Verb Print
}

Redirection of standard and error output appending to the same log file

I need to collect the standard output and error log from several processes into one single log file.
So every output must append to this log file.
I want to call all the jobs with lines like this:
$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait
Where do I have to put the information to append?
In order to append to a file you'll need to use a slightly different approach. You can still redirect an individual process' standard error and standard output to a file, but in order to append it to a file you'll need to do one of these things:
Read the stdout/stderr file contents created by Start-Process
Not use Start-Process and use the call operator, &
Not use Start-Process and start the process with .NET objects
The first way would look like this:
$myLog = "C:\File.log"
$stdErrLog = "C:\stderr.log"
$stdOutLog = "C:\stdout.log"
Start-Process -File myjob.bat -RedirectStandardOutput $stdOutLog -RedirectStandardError $stdErrLog -wait
Get-Content $stdErrLog, $stdOutLog | Out-File $myLog -Append
The second way would look like this:
& myjob.bat 2>&1 >> C:\MyLog.txt
Or this:
& myjob.bat 2>&1 | Out-File C:\MyLog.txt -Append
The third way:
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "myjob.bat"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = ""
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$output = $p.StandardOutput.ReadToEnd()
$output += $p.StandardError.ReadToEnd()
$output | Out-File $myLog -Append
Like Unix shells, PowerShell supports > redirects with most of the variations known from Unix, including 2>&1 (though weirdly, order doesn't matter - 2>&1 > file works just like the normal > file 2>&1).
Like most modern Unix shells, PowerShell also has a shortcut for redirecting both standard error and standard output to the same device, though unlike other redirection shortcuts that follow pretty much the Unix convention, the capture all shortcut uses a new sigil and is written like so: *>.
So your implementation might be:
& myjob.bat *>> $logfile
Andy gave me some good pointers, but I wanted to do it in an even cleaner way. Not to mention that with the 2>&1 >> method PowerShell complained to me about the log file being accessed by another process, i.e. both stderr and stdout trying to lock the file for access, I guess. So here's how I worked it around.
First let's generate a nice filename, but that's really just for being pedantic:
$name = "sync_common"
$currdate = get-date -f yyyy-MM-dd
$logfile = "c:\scripts\$name\log\$name-$currdate.txt"
And here's where the trick begins:
start-transcript -append -path $logfile
write-output "starting sync"
robocopy /mir /copyall S:\common \\10.0.0.2\common 2>&1 | Write-Output
some_other.exe /exeparams 2>&1 | Write-Output
...
write-output "ending sync"
stop-transcript
With start-transcript and stop-transcript you can redirect ALL output of PowerShell commands to a single file, but it doesn't work correctly with external commands. So let's just redirect all the output of those to the stdout of PS and let transcript do the rest.
In fact, I have no idea why the MS engineers say they haven't fixed this yet "due to the high cost and technical complexities involved" when it can be worked around in such a simple way.
Either way, running every single command with start-process is a huge clutter IMHO, but with this method, all you gotta do is append the 2>&1 | Write-Output code to each line which runs external commands.
Maybe it is not quite as elegant, but the following might also work. I suspect asynchronously this would not be a good solution.
$p = Start-Process myjob.bat -redirectstandardoutput $logtempfile -redirecterroroutput $logtempfile -wait
add-content $logfile (get-content $logtempfile)