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
Related
How to use -ArgumentList with Invoke-Command to pass flags to a script?
# File: ./setup.ps1
param(
[Parameter(Mandatory=$false)]
[alias("force")]
[switch]$opt_force
)
if ($opt_force) {
write-host "FORCING something!"
}
write-host "Done"
Powershell Command Line:
PS> Invoke-Command -Computer pv3039 -FilePath ./setup.ps1 -ArgumentList "-force"
Error Message:
positional parameter cannot be found that accepts argument '-force'.
+ CategoryInfo : InvalidArgument: (:) [], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound
+ PSComputerName : pv3039
If you want to call a remote script, you can use Start-Process instead of Invoke-Command. Maybe you can try something like this.
Start-Process PowerShell -ArgumentList "YOUR_SCRIPT_PATH\setup.ps1 -Force" -NoNewWindow -Wait
This way it can accept parameters from the called script.
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 will start by saying that I have successfully tested this script when running locally on my laptop against a remote dev server.
However, when I have migrated the script to our TFS server, I am now encountering the below (sanitized) error message.
2019-06-10T18:46:05.8256626Z Generating script.
2019-06-10T18:46:05.8257313Z Formatted command: . 'E:\***.ps1' -username "***" -password "***" -servername "***" -ScriptPath "***" -SourcePath "***" -DestinationPath "***" -CleanupFlag "***"
2019-06-10T18:46:06.0290179Z ##[command]"C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'E:\***.ps1'"
2019-06-10T18:46:06.7520864Z Method invocation failed because [System.Management.Automation.PSCredential] does not contain a method named 'new'.
2019-06-10T18:46:06.7521292Z At E:\***.ps1:5 char:1
2019-06-10T18:46:06.7521480Z + $CredentialSec = [System.Management.Automation.PSCredential]::new($username,$PWsec)
2019-06-10T18:46:06.7523016Z + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-06-10T18:46:06.7523588Z + CategoryInfo : InvalidOperation: (:) [], ParentContainsErrorRecordException
2019-06-10T18:46:06.7524614Z + FullyQualifiedErrorId : MethodNotFound
2019-06-10T18:46:06.7525361Z
2019-06-10T18:46:06.8602349Z ##[error]PowerShell exited with code '1'.
The script is attempting to Invoke-Command (to run a different script) on a remote system. It appears to be messing up at the section where it creates a credential from the username and encrypted password.
This is the code that I'm attempting to execute:
param($username, $password, $servername, $ScriptPath, $SourcePath, $DestinationPath, $CleanupFlag)
$PWsec = ConvertTo-SecureString -String $password -AsPlainText -Force
$CredentialSec = [System.Management.Automation.PSCredential]::new($username,$PWsec)
Invoke-Command -ComputerName $servername -Credential $CredentialSec -FilePath $ScriptPath -ArgumentList $SourcePath, $DestinationPath, $CleanupFlag
Per mcclayton's suggestion in the comments... because the new server is running an older version of Powershell, it worked when I changed from this format:
$CredentialSec = [System.Management.Automation.PSCredential]::new($username,$PWsec)
To this format:
$CredentialSec = New-Object System.Management.Automation.PSCredential($username,$PWsec)
I tried different ways to escape the space in "Program Files" but this is not working. I receive the following error in Jenkins after this part is executed:
powershell.exe : FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or 'lpt1:', call At
C:\web\JenkinsMaster\workspace\XXX#tmp\durable-d3011838\powershellWrapper.ps1:5
char:3
+ & powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Fi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (FileStream was ... 'lpt1:', call :String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr.
CategoryInfo : OpenError: (:) [Out-File], NotSupportedException
FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
PSComputerName : XXXXX
powershell script: '''
$pass = ConvertTo-SecureString -AsPlainText "XXXX" -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList "XXXX",$pass
$sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ComputerName XXXXXXXX -UseSSL -Credential $cred -SessionOption $sessionOption
Copy-Item $env:WORKSPACE\\* -Destination "C:\\data\\install\\" -Filter *TEST* -Recurse -Force -Verbose -ToSession $session
$filename = $env:JOB_NAME + "_" + $env:BUILD_DISPLAY_NAME + "_wwwroot.7z"
Invoke-Command -Session $session -ScriptBlock {cmd /c "C:\\Program Files\\7-Zip\\7z.exe\\" x C:\\Data\\Install\\$filename -oC:\\data\\install\\test -aoa >NUL}
Remove-PSSession $session
Exit-PSSession
'''
If I change the Invoke-Command to the following, the Program Files directory seems to be resolved correctly, but then the variable $filename is not resolved anymore.
Invoke-Command -Session $session -ScriptBlock {cmd /c \'"C:\\Program Files\\7-Zip\\7z.exe" x C:\\Data\\Install\\$filename -oC:\\data\\install\\test -aoa >NUL'}
powershell.exe : NotSpecified: (:String) [], RemoteException At
C:\web\Jenkins\workspace\XXX#tmp\durable-53dbead2\powershellWrapper.ps1:5
char:3
+ & powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Fi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (NotSpecified: (...RemoteException:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
CategoryInfo : NotSpecified: (:String) [], RemoteException
FullyQualifiedErrorId : NativeCommandError
PSComputerName : XXXXX
ERROR: The system cannot find the file specified.
C:\Data\Install\$filename
System ERROR:
The system cannot find the file specified.
Hopefully you can assist me in this case! The rest of the commands is working fine.
Thanks!
The 7z.exe path in your first command has an extraneous trailing \, which causes problems:
cmd /c "C:\\Program Files\\7-Zip\\7z.exe\\" # <- trailing \\ shouldn't be there
In your 2nd command, you're using single quotes around the command passed to cmd /c ('...'), but the contents of '...' strings in PowerShell are treated as literals, which explains why $fileName was not expanded (interpolated);
only double-quoted ("...") strings and, within limits, unquoted command arguments are expanded in PowerShell; e.g., compare the output from Write-Output '$HOME' to the output from Write-Output "$HOME" / Write-Output $HOME.
As iRon mentions, there's no need to involve cmd at all - PowerShell is perfectly capable of executing command-line programs directly, so this should work:
Invoke-Command -Session $session -ScriptBlock { & "C:\\Program Files\\7-Zip\\7z.exe" x C:\\Data\\Install\\$using:filename -oC:\\data\\install\\test -aoa >$null }
Due to invoking 7z.exe directly, now there's no outer quoting needed anymore, and $fileName should be expanded.
Note, however, that $fileName was replaced with $using:fileName, which is necessary in order for the target session to know about the local $fileName variable - see Get-Help about_Remote_Variables.
Since the 7z.exe file path is quoted (of necessity, due to containing spaces), you must use &, the call operator, to invoke it.
Since the > redirection is now performed by PowerShell itself, the cmd-style >NUL output suppression was replaced with its PowerShell analog, >$null.
I wonder if it necessarily at all to invoke a CMD shell for this.
I guess it would be simpler to directly invoke the 7z.exe with its parameters.
Nevertheless, you can build you own script block like this:
[ScriptBlock]::Create('cmd /c "C:\\Program Files\\7-Zip\\7z.exe" x C:\\Data\\Install\\' + $filename + ' -oC:\\data\\install\\test -aoa >NUL')
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)