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)
Related
When I am running a PowerShell script normally it's working fine, issue is raising when calling the same script from batch file.
Unt1.ps1 script:
$linux_app_user="ORXXXX\"+$args[0]
$pass_win=$args[1]
$path=$args[2]
$pass = ConvertTo-SecureString -AsPlainText $pass_win -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList
$linux_app_user, $pass
$Invoke-Command -ComputerName XXXXXXXX.XXXX.XXX.XXXX -Credential $cred -ErrorAction
Stop -ScriptBlock {
param($path)
Invoke-Expression $path
} -Arg $path
cal.bat script:
#echo off
SET Server=slXXXXXXXX.XXX.XXXX.com
SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0
CD /D "%PowerShellDir%
powershell.exe -ExecutionPolicy RemoteSigned -File
C:\Users\chaj\Documents\String\Unt1.ps1 'XXXX' 'XXXX#321' 'C:\cal.bat'
Error:
[xxxxxx.xx.xxxxx.xxx] Connecting to remote server xxxxxx.xx.xxxxx.xxx failed
with the following error message : The user name or password is incorrect.
For more information, see the about_Remote_Troubleshooting Help topic.
At C:\Users\chafg\Documents\String\Unt1.ps1:7 char:1
+ $Result=Invoke-Command -ComputerName xxxxxx.xx.xxxxx.xxx -Credenti ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (xxxxxx.xx.xxxxx.xxx) [], PSRemotingTransportException
+ FullyQualifiedErrorId : LogonFailure,PSSessionStateBroken
When using the PowerShell CLI with the -File parameter, all arguments are used verbatim - except if enclosed in "..." (double quotes): unlike when you use -Command, '...' (single quotes) are not recognized as string delimiters.
Therefore, your command (simplified here):
powershell.exe -File C:\path\to\Unt1.ps1 'XXXX' 'XXXX#321' 'C:\cal.bat'
causes the Unt1.ps1 script to see the arguments with the enclosing ', which is not your intent; e.g., instead of $args[0] receiving XXXX, as intended, it receives 'XXXX', verbatim.
The fix is to use "..." (double quotes):
powershell.exe -File C:\path\to\Unt1.ps1 "XXXX" "XXXX#321" "C:\cal.bat"
Alternatively, given that your specific sample arguments don't require quoting (though the real ones may):
powershell.exe -File C:\path\to\Unt1.ps1 XXXX XXXX#321 C:\cal.bat
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.
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
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.
I'm having to construct some paths before attempting to invoke the script which is present on the remote computer. I'm adapting something we have working in TeamCity, but I'm currently getting the following error:
The command cannot be run because the File parameter requires a file path. Supply a path for the File parameter and then try the command again.
+ CategoryInfo : NotSpecified: (The command can... command again.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Relevant code below:
$stageScript = "D:\pkg\${dir}\stage.ps1"
$options = "production \\192.168.0.x\staging \\${server}\staging"
Invoke-Command -computername server.domain.com { powershell.exe -noprofile -executionpolicy Bypass -file $stageScript $options } -Credential $credential
You need to pass local variables to the script block as an argument list
$stageScript = "D:\pkg\${dir}\stage.ps1"
$options = "production \\192.168.0.x\staging \\${server}\staging"
Invoke-Command -computername server.domain.com { powershell.exe -noprofile -executionpolicy Bypass -file $args[0] $args[1] } -ArgumentList $stageScript,$options -Credential $credential