invoking command while copying file over ps remote session fails - powershell

I have a question regarding how to properly structure a command with powershell.
Here is the code where I am having the issue.
$python_command =
{
param($script)
C:\Python27\python.exe $script
return $lastexitcode
}
$exit_code = Invoke-Command Copy-Item -Path C:\TestWare\jsonStuff.json -Destination
C:\Tunnel\Tunneling\jsonStuff.json -ToSession $Session - ScriptBlock $python_command -ArgumentList $exec_script
#Clean up
ExitWithCode($exit_code)
I'm assuming there there is an issue with how $exit_code is formatted because when it has this value
Copy-Item -Path C:\TestWare\jsonStuff.json -Destination C:\Tunnel\Tunneling\jsonStuff.json -ToSession $Session
there are no issues. I want the python command to run as well though. Can these commands be separated or how would they work as one? At the moment, I am getting the following error
Invoke-Command : A parameter cannot be found that matches parameter name 'Path'.
At C:\TestWare\run-test3.ps1:122 char:39
+ $exit_code = Invoke-Command Copy-Item -Path C:\TestWare\ ...
+ ~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.InvokeCommandCommand
Any ideas on how to fix? I am on Powershell version 5 as well.
(EDIT) Here is my ExitWithCode function
function ExitWithCode
{
param
(
$exitcode
)
$host.SetShouldExit($exitcode)
exit
}

Invoke-Command has many different parameter sets, but just two fundamental ways to specify what command to invoke [remotely]:
via the -FilePath parameter, which expects a local script's path whose content is converted to a script block, which is then executed on the target machine.
via the -ScriptBlock parameter, which accepts a script block ({ ... })
Therefore, your attempt to pass a script block and a Copy-Item call directly cannot work.
It looks like you need 2 statements:
The Copy-Item call to copy something to session $Session with -ToSession.
The Invoke-Command statement to execute script block $python_command in session -Session $Session.
You could only get away with a single Invoke-Command call if you read the content of C:\TestWare\jsonStuff.json into memory and passed it as an argument to the script block and acted on that argument accordingly.

Related

powershell script is not working [duplicate]

I am trying to follow this article to expand a variable in a scriptblock
My code tries this:
$exe = "setup.exe"
invoke-command -ComputerName $j -Credential $credentials -ScriptBlock {cmd /c 'C:\share\[scriptblock]::Create($exe)'}
How to fix the error:
The filename, directory name, or volume label syntax is incorrect.
+ CategoryInfo : NotSpecified: (The filename, d...x is incorrect.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ PSComputerName : remote_computer
You definitely don't need to create a new script block for this scenario, see Bruce's comment at the bottom of the linked article for some good reasons why you shouldn't.
Bruce mentions passing parameters to a script block and that works well in this scenario:
$exe = 'setup.exe'
invoke-command -ComputerName $j -Credential $credentials -ScriptBlock { param($exe) & "C:\share\$exe" } -ArgumentList $exe
In PowerShell V3, there is an even easier way to pass parameters via Invoke-Command:
$exe = 'setup.exe'
invoke-command -ComputerName $j -Credential $credentials -ScriptBlock { & "C:\share\$using:exe" }
Note that PowerShell runs exe files just fine, there's usually no reason to run cmd first.
To follow the article, you want to make sure to leverage PowerShell's ability to expand variables in a string and then use [ScriptBlock]::Create() which takes a string to create a new ScriptBlock. What you are currently attempting is to generate a ScriptBlock within a ScriptBlock, which isn't going to work. It should look a little more like this:
$exe = 'setup.exe'
# The below line should expand the variable as needed
[String]$cmd = "cmd /c 'C:\share\$exe'"
# The below line creates the script block to pass in Invoke-Command
[ScriptBlock]$sb = [ScriptBlock]::Create($cmd)
Invoke-Command -ComputerName $j -Credential $credentials -ScriptBlock $sb

How to pass arguments to an Invoke-Expression, in PowerShell?

I have the following (not working) PowerShell script:
$scriptPath = ((new-object net.webclient).DownloadString('https://gist.githubus
ercontent.com/AndrewSav/c4fb71ae1b379901ad90/raw/23f2d8d5fb8c9c50342ac431cc0360ce44465308/SO33205298')); $args = "`"aaa
bbb`""; iex $scriptPath $args
So I'm:
downloading the script to execute.
settiping up my argument list to send into the script
executing the script (for me, this is in the cli right now).
but it's erroring:
Invoke-Expression : A positional parameter cannot be found that accepts argument '"aaa bbb"'.
At line:1 char:209
+ ... 44465308/SO33205298')); $args = "`"aaa bbb`""; iex $scriptPath $args
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Expression], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.InvokeExpressionCommand
How can I pass in the args to this script?
Note: this question references/spawned from this other SO question.
You should try something like this :
$scriptPath = ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/AndrewSav/c4fb71ae1b379901ad90/raw/23f2d8d5fb8c9c50342ac431cc0360ce44465308/SO33205298'))
Invoke-Command -ScriptBlock ([scriptblock]::Create($scriptPath)) -ArgumentList "coucou"
You have to create a ScriptBlock from source before invoking it.
As a pure one liner (you don't need to create the scriptblock separately)
Also, using DownloadData in case the script has UTF-8 characters. Finally, Use an array for the ArgumentList to avoid issues with spaces in args.
powershell -nop -ExecutionPolicy Bypass -c "Invoke-Command -ScriptBlock ([scriptblock]::Create([System.Text.Encoding]::UTF8.GetString((New-Object Net.WebClient).DownloadData('https://server.com/upload/script.ps1')))) -ArgumentList #('somearg','someotherarg')"

Invoke-Command with local function in ScriptBlock doesn't work when the function has no return statement

I'm trying to get the Invoke-Command cmdlet working with a CredSsp session by passing a locally defined function.
I have two local functions:
MyCopy which just invokes Copy-Item cmdlet on passed params with additional switches
MyCopyReturn which is the same as above, but in addition has return statement at the end
Now when I pass those functions to Invoke-Command without -Session parameter, they both succeed.
However, when specifying -Session for Invoke-Command, MyCopy fails with following exception (2. case):
Cannot bind argument to parameter 'Path' because it is null.
+ CategoryInfo : InvalidData: (:) [Copy-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand
+ PSComputerName : localhost
Could someone please explain why result of passing MyCopyReturn is different from passing MyCopy?
function MyCopy ($from, $to) {
Copy-Item $from $to -Force -Recurse -Verbose
}
function MyCopyReturn ($from, $to) {
Copy-Item $from $to -Force -Recurse -Verbose
return
}
$credential = Get-Credential
$computerName = 'localhost'
$session = New-PSSession -ComputerName $computerName -Credential $credential -Authentication Credssp
# src is a file
$src = "c:\sandbox\a\test"
# dest is a directory
$dest = "c:\sandbox\b"
# 1.
# MyCopy works fine without giving session
Invoke-Command -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
# 2.
# MyCopy DOESN'T WORK when session is given
Invoke-Command -Session $session -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
# 4.
# MyCopyReturn works fine without the session
Invoke-Command -ScriptBlock ${function:MyCopyReturn} -ArgumentList $src,$dest
# 3.
# MyCopyReturn works fine with session too
Invoke-Command -Session $session -ScriptBlock ${function:MyCopyReturn} -ArgumentList $src,$dest
Remove-PSSession $session
I make some digging with ILSpy and can say, that the problem in the bug in ScriptBlock.GetPowerShell method. It does not bind parameters properly, if them come not from param block:
function f($Arg){write "`$Arg=`"$Arg`";`$Args=`"$Args`""}
function g{param($Arg) write "`$Arg=`"$Arg`";`$Args=`"$Args`""}
$Function:f.GetPowerShell('Test1','Test2').Invoke()
# $Arg="";$Args="Test1 Test2"
$Function:g.GetPowerShell('Test1','Test2').Invoke()
# $Arg="Test1";$Args="Test2"
As you can see, $Function:f.GetPowerShell('Test1','Test2') bind both arguments to $Args automatic variable and nothing get bound to $Arg. So when you invoke this command
Invoke-Command -Session $session -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
$from and $to does not get bound properly and cause error.
Why error does not happens when you not use -Session parameter?
Looks like Invoke-Command have to convert ScriptBlock to PowerShell to invoke command in remote session and that does not required when ScriptBlock invoked locally.
Why MyCopyReturn does not cause same error?
Not all ScripBlocks can be converted to PowerShell by GetPowerShell method (in particular, it is required that ScriptBlock must have a single statement, having another statement return violate this). If that is the case (GetPowerShell throws ScriptBlockToPowerShellNotSupportedException), than Invoke-Command use some backup scenario to convert ScriptBlock to PowerShell and that scenario does not suffer from bug of GetPowerShell method.

Run an executable with a parameter using Invoke-Command

I am trying to run an executable with a config file as a parameter using invoke-command through a PowerShell script.
Here is what I have so far in my PowerShell script:
$config = 'D:\EmailLoader\App.config'
invoke-command -ComputerName SERVER-NAME -ScriptBlock {param($config) & 'D:\EmailLoader\GetMailAndAttachment.exe' $config} -ArgumentList $config
I then Execute the PowerShell script with the following command:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -File "D:\PowerShellScripts\Email.ps1"
And I get the following error:
Unexpected token 'config' in expression or statement.
At D:\PowerShellScripts\Email.ps1:3 char:121
+ invoke-command -ComputerName SERVER-NAME -ScriptBlock {param($config) 'D:\EmailLoader\GetMailAndAttachment.exe' $config <<<< } -ArgumentList $config
+ CategoryInfo : ParserError: (config:String) [], ParentContainsE rrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
The code looks like it should work. But the exception message is clearly missing the & symbol. I would check that first, because you are getting the exact same message I would anticipate to get when the & was missing. So maybe there is problem with the saved file, rather than with your code.
Side note: If you are on PowerShell 3.0 or newer you should consider using the $using: scope in the script block to avoid adding the param and -ArgumentList.
$config = 'D:\EmailLoader\App.config'
Invoke-Command -ComputerName SERVER-NAME -ScriptBlock {
&'D:\EmailLoader\GetMailAndAttachment.exe' $using:config
}
There is no need to pass $config as a parameter to a ScriptBlock. Also not needed to add the $config parameter twice. This should work:
$config = 'D:\EmailLoader\App.config'
Invoke-Command -ComputerName SERVER-NAME -ScriptBlock {&('D:\EmailLoader\GetMailAndAttachment.exe')} -ArgumentList #($config)

Start-job resulting in null parameter

I'm trying to execute the following two lines of code in PowerShell v2.0 as a job, and am having trouble. I think I have the syntax right, but I can't get it to do what I think it should do, so I clearly am doing something wrong...
$report = <command line thing>
invoke-expression $report
These two lines work in PowerShell. But when I try to put it into a start-job command:
start-job -scriptblock {invoke-expression $report} -argumentlist $report | wait-job | receive-job
I get the following error:
Cannot bind argument to parameter 'Command' because it is null.
+ CategoryInfo : InvalidData: (:) [Invoke-Expression], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.InvokeExpre
ssionCommand
+ PSComputerName : localhost
I understand that error as saying that the argument I'm passing the invoke-expression is null, but, I'd thought that by passing $report in the -argumentlist param, it'd get through?
You cannot access $report directly unless you do:
-scriptblock {param($report) invoke-expression $report}
The param($report) part captures the $report variable passed in via -ArgumentList and makes it available for use inside the scriptblock.