Powershell: Backgrounding command causes it not to work - powershell

My script stores a bunch of External application commands from an app like so
$app1 = get-command "C:\Where\Command\Located.exe"
Then I call it with
& $app1 -S -P 9000
(where -S -P and 9000 are parameters as I'd pass them in a cmd.exe shell). Up to here everything works perfectly. However, I want to run this as a background task and here's where I begin running into trouble.
Start-Job -ScriptBlock { & $app1 -S -P 9000 }
fails with "The expression after '&' in a pipeline element produced an invalid object." I've searched google for about two days and everything I've tried seems to be for naught. Enclosing parameters in #() and trying to splat them out, Invoke-Expression, Invoke-Command, Invoke-Item (still unclear as to what these are all doing). I've also tried converting the whole command to a string and then calling Invoke-Expression within the start job but it doesn't seem to be working either. So this question is resources to understand when all these things are appropriate to use and why it doesn't work as soon as I pass it to a background job.

Try passing the $app1 variable to the script block:
Start-Job -ScriptBlock {param($app1) & $app1 -S -P 9000 } -ArgumentList $app1
Note that instead of
$app1 = get-command "C:\Where\Command\Located.exe"
you can also just have
$app1 = "C:\Where\Command\Located.exe"

Related

Trying to run an executable with paremeters from Powershell

I'm trying to run the following executable with parameters from Powershell:
wgrib2.exe test_t.grib -if "^(1|2):" -grid_def -else -s -lola 0:360:1 -90:181:1 1x1_t.grib grib -endif
So far I've tried several different methods but none have worked. Initially using cmd.exe:
$wg= test_t.grib -if "^(1|2):" -grid_def -else -s -lola 0:360:1 -90:181:1 1x1_t.grib grib -endif
$jobregrid = Start-Job { cmd.exe /c F:; chdir F:\nwp\global\grib; wgrib2.exe $using:wg" }
Wait-Job $jobregrid
Receive-Job $jobregrid
$jobregrid = $null
Also tried Invoke-Expression and Start-Process.
The command works when run directly from a DOS prompt or from a batch file. The problem seems to be that I don't understand PowerShell syntax sufficiently to deal with "^(1|2):" section. I have tried using the escape character ` but I still can't get it to work.
Help please?
Brian

Run PowerShell script with PsExec and collect output objects

From remote PowerShell, I need to run a PowerShell "GUI" script under an interactive user session. The only solution I found so far is to use PsExec (with the -i parameter). That works (I see the PowerShell window pop up).
But I need to transmit the outputs of this "GUI" script to the host of my remote script. Ideally, that should happen asynchronously during that the "GUI" script is running (i.e. without waiting for it to finish).
Is there a way to redirect the script output/error streams from the new powershell process to the caller powershell process?
CODE:
Remote script returning outputs to C# host asynchrounously (via a Pipeline):
Write-Output "Starting remote script..." # this string is transmitted to host
# Run interactiveScript.ps1 in other session using PsExec:
$EncodedCommand = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('& "interactiveScript.ps1" -myArg1 "abc"'))
$CommandString = "-accepteula -nobanner -i 1 -u admin -p admin -h \\localhost cmd /c `"echo . | powershell.exe -ExecutionPolicy Bypass -EncodedCommand $EncodedCommand`"
$Result = Start-Process -FilePath $PsExecExecutable -ArgumentList $CommandString -Wait -NoNewWindow -PassThru -RedirectStandardOutput $TempFileNameSTDOUT -RedirectStandardError $TempFileNameSTDERR -ErrorAction Continue"
Interactive script interactiveScript.ps1 that should redirect all its outputs/errors to calling script, which transmits them asynchronously to C# host:
param
(
[Parameter(Mandatory=$true)]
[string]$myArg1
)
Write-Output "Starting interactive script..." # this string must be transmitted to host
Write-Error "This is an error" # this error must be transmitted to host
Sleep 1 # Here the user interacts with the script
[System.Drawing.Bitmap]$img = ... # Here the script takes a screenshot of a window
Write-Output ([string](MyImageSerialization($img)) # this string must be transmitted to host
Note: I can't transmit directly an object such as [System.Drawing.Bitmap] to the host because it is a reference so I will serialize it to a string. Therefore it is acceptable if the solution works only for string outputs and errors.
POSSIBLE CLUE:
I am thinking about using named pipes to communicate between processes. But I don't know how to redirect the powershell streams through the pipes.

Pass Powershell Variables to Command Prompt line

I want to make a PowerShell script that can be used to connect computers to various client's SonicWall VPNs (specifically through Global VPN and NetExtender). I would like to have it be like a user interface to prompt the user (which will set the variables) and then use that information to pass through to command lines in the command prompt.
I want to be able to have information entered in be applied in the cmd line in the script.
I have tried using the MobileConnect connection through (Using the the app from the app store) and connecting with the Microsoft VPN client, but that does not grab all the network information; specifically DNS servers.
The best way is to install either Global VPN or NetExtender and connect through cmd line; that way will grab the entire network information.
This is the basic command to run it:
Function Connect-VPN {
Set-Location -Path "C:\Program Files (x86)\SonicWALL\SSL-VPN\NetExtender"
cmd /c "NECLI connect -s address:4433 -u Uname -p Password -d Domain -A"
Set-Location -Path C:\
}
Basically, you change the directory and execute the commands with those arguments.
I would like to prompt in POSH, create the variables with the user input, then have those arguments passed down.
What I have right now is:
param(
[string]$Testadd ,
[string]$Testun ,
[string]$TestPW ,
[string]$TestDom
)
If ($Testadd -eq "")
{$Testadd = (Read-Host "test")
}
If ($Testun -eq "")
{$Testun = (Read-Host "test")
}
If ($TestPW -eq "")
{$TestPW = (Read-Host "test")
}
If ($TestDom -eq "")
{$TestDom = (Read-Host "test")
}
Set-Location -Path "C:\Program Files (x86)\SonicWALL\SSL-VPN\NetExtender"
cmd /c "NECLI connect -s "$($Testadd)" -u "$($Testun)" -p "$($TestPW)" -d "$($TestDom)" -A"
Set-Location -Path C:\
The problem is that the all the arguments come out null. I do not know if it is possible, but I wanted to see.
You can try to build the string before running the cmd
param (
[string]$Testadd,
[string]$Testun,
[string]$TestPW,
[string]$TestDom
)
If ($Testadd -eq "")
{
$Testadd = (Read-Host "testadd")
}
If ($Testun -eq "")
{
$Testun = (Read-Host "testun")
}
If ($TestPW -eq "")
{
$TestPW = (Read-Host "testpw")
}
If ($TestDom -eq "")
{
$TestDom = (Read-Host "testdom")
}
Set-Location -Path "C:\Program Files (x86)\SonicWALL\SSL-VPN\NetExtender"
#build the string before
$cmd = "NECLI connect -s " + $($Testadd) + " -u " + $($Testun) + " -p " + $($TestPW) + " -d " + $($TestDom) + " -A"
# Or even like this
$cmd = "NECLI connect -s $Testadd -u $Testun -p $TestPW -d $TestDom -A"
# exec command
cmd /c $cmd
Set-Location -Path C:\
To add to #Desinternauta, I suspect it is how the command is interpreting the quotes and the variables. i.e. when you write out the string as you have it, it adds spaces:
$b = "b"
Write-Host "a"$($b)"c"
Outputs:
a b c
The good news is that double quoted strings allow you to embed the variables into the string:
cmd /c "NECLI connect -s $Testadd -u $Testun -p $TestPW -d $TestDom -A"
Calling external exe / commands that use cmd.exe, require special consideration and outing specifics. You also do not need to call cmd.exe directly, as that will just happen. This is a well documented this. For example:
PowerShell: Running Executables
The Call Operator &
Why: Used to treat a string as a SINGLE command. Useful for dealing
with spaces.
In PowerShell V2.0, if you are running 7z.exe (7-Zip.exe) or another
command that starts with a number, you have to use the command
invocation operator &.
The PowerShell V3.0 parser do it now smarter, in this case you don’t
need the & anymore .
Details: Runs a command, script, or script block. The call operator,
also known as the "invocation operator," lets you run commands that
are stored in variables and represented by strings. Because the call
operator does not parse the command,it cannot interpret command
parameters
# Example:
& 'C:\Program Files\Windows Media Player\wmplayer.exe' "c:\videos\my home video.avi" /fullscreen
Start-Process (start/saps)
Why: Starts a process and returns the .Net process object Jump if
-PassThru is provided. It also allows you to control the environment in which the process is started (user profile, output redirection
etc). You can also use the Verb parameter (right click on a file, that
list of actions) so thatyou can, for example, play a wav file.
Details: Executes a program returning the process object of the
application. Allows you to control the action on a file (verb
mentioned above) and control the environment in which the app is run.
You also have the ability to wait on the processto end. You can also
subscribe to the processes Exited event.
#Example:
#starts a process, waits for it to finish and then checks the exit code.
$p = Start-Process ping -ArgumentList "invalidhost" -wait -NoNewWindow -PassThru
$p.HasExited
$p.ExitCode
10. Stop-Parsing Symbol --%
Why: Its a quick way to handle program arguments that are not standard. Also its the new cool way to do it.
Details: The stop-parsing symbol (--%), introduced in Windows PowerShell 3.0, directs Windows PowerShell to refrain from interpreting input as Windows PowerShell commands or expressions. When calling an executable program in Windows PowerShell, placethe stop-parsing symbol before the program arguments.
After the stop-parsing symbol --% , the arguments up to the end of the line (or pipe, if you are piping) are passed as is.
#Examples:
# icacls in V2
# You must use escape characters to prevent PowerShell from misinterpreting the parentheses.
icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F
# In V3 you can use the stop-parsing symbol.
icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F
See also:
Using Windows PowerShell to run old command line tools (and their weirdest parameters)
Solve Problems with External Command Lines in PowerShell
Quoting
About Quoting Rules
A Story of PowerShell Quoting Rules

Trying to Remotely use PsTools (PsExec) to Return a Result on Powershell

I am trying to run a script remotely that will double check that the IP address is correct using PsExec in Powershell. The problem is I only want it to return the result True or False and not show any other lines within Powershell.
I have tried running background jobs as well but have not seemed to get that working, as when I do that it simply gives me nothing.
function remoteIPTest($Computer) {
$result = & cmd /c PsExec64.exe \\$Computer -s cmd /c "ipconfig"
if ($result -like "*10.218.5.202*") {
return "True"
}
}
$Computer = "MUC-1800035974"
remoteIPTest $Computer
After running this, I just want the application to give return:
True
Instead of returning:
Starting cmd on MUC-1800035974... MUC-1800035974...
cmd exited on MUC-1800035974 with error code 0.
True
psexec prints its status messages to stderr, which a variable assignment such as $result = does not capture, so these messages still print to the screen.
Variable assignments only capture stdout output from external programs such as psexec, which in this case is ipconfig's output.
Therefore, the answer is to suppress stderr, which you can do with 2>$null (2 is the number of PowerShell's error stream, which stderr maps to) - see Redirecting Error/Output to NULL.
Do note that this will also suppress true error messages.
In addition, the cmd /c calls are not needed, because you can use psexec to invoke other programs directly, if you have the path configured properly.
Instead of this:
$result = & cmd /c PsExec64.exe \\$Computer -s cmd /c "ipconfig"
Do This:
$result = PsExec64.exe \\$Computer -s ipconfig 2>$null
Hope it helps.

Using powershell to script psftp and pass parameters

The more forums i look on, the more confused i get, and i've found very similar posts, but not exactly what i'm looking for, i'm a powershell newbie, can someone tell me the best way of being able to write this in powershell.
I can get the program to launch but it's passing the parameters and the syntax i'm struggling with. To make it easier to read i have removed any formatting from the $programArgs command so i'm hoping it's just putting in the correct synatax around it.
This is what i have so far:-
$program = "C:\Program Files (x86)\PuTTY\psftp.exe"
$programArgs = "-pw 1234 -P 10023 -i D:\sftp\Keys\mykey.ppk bigG#Dmydomain.co.uk -b d:\sftp\Scripts\GetAll.txt"
Invoke-Command -ScriptBlock { & $program $programArgs }
Should be able to just use Invoke-Expression "$program $programArgs".
To Clarify this is the command i used to launch psftp and pass various parameters:-
Start-Process -FilePath "c:\Program Files (x86)\PuTTY\psftp.exe" -ArgumentList "-pw Password123 -P 10023 -i D:\Keys\pub.ppk username#username.com -b d:\Scripts\GetAll.txt" -Wait -NoNewWindow