I'm doing a project with not enough time to rewrite what is written in HTA.
I need to call a HTA using cmd.exe /C (so it closes the window after it formulates, generating a flashing hta box). I am able to do this in an invoke-expression fashion, but I'm trying to get it as a start-job with a mixture of variables.
$RunHTA = {
param(
[string]$FP, ### filepath to hta
[string]$output) ### output
Invoke-Expression -command 'cmd.exe /C $FP /H:`"$output`"' ### this line works alone. the /H is the save report feature and the double quotes are needed by the hta
}
$fp="C:\Path\To\HTA\file.hta"
$output = "C:\Output\path"
$j = Start-job $RunHTA -ArgumentList $FP,$output
$j | Receive-job
The filename, directory name, or volume label syntax is incorrect.
+ CategoryInfo : NotSpecified: (The filename, d...x is incorrect.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
I've done some testing and the variables are getting passed through correctly. Using returns to see the full variables.
Seems simple and probably something that should work without hassle.
Any ideas?
Try wrapping command in double quotes instead
Invoke-Expression -command "cmd /c $FP /H:`"$output`""
Related
I need to execute a command file (B.cmd) on Machine B from a Powershell script (A.ps1) on Machine A. I don't want to statically specify the path
B.cmd is supposed to execute C.ps1 which is in the same folder as B.cmd
MACHINE A: A.ps1
MACHINE B: B.cmd, C.ps1 (all in same folder)
so my command file looks like this B.cmd
#echo off
powershell.exe -file ".\C.ps1" -Iterations 10
echo
echo
pause
There's an error thrown in a A.ps1 file from which I'm calling the B.cmd file
A.ps1
Invoke-Command -ComputerName $systemName -credential $credentials -ScriptBlock {Invoke-Expression -Command: "cmd.exe /c C:\Temp\Batch\Test\B.cmd"}
A.ps1 throws error:
**The argument '.\C.ps1' to the -File parameter does not exist. Provide the path to an existing '.ps1' file as an argument to the -File parameter.**
+ CategoryInfo : NotSpecified: (The argument '....File parameter.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ PSComputerName : XXX
How do I make the .\ work or is there an alternative or is it wrong to use the .\ for a remote execution ?
Please forgive my ignorance anywhere as I'm very very new to PS, Thank You !
If you're able to change the ABC.cmd you could use the following
powershell.exe -file "%~dp0\XYZ.ps1"
This will get the folder the ABC.cmd script is running from. Note that %~dp0 won't work in cmd for testing you'll need to test it from within a script.
So don't wrap a batch file around it. A waste of time and confuses the issue.
invoke-command -comp $computername -filepath C:\Temp\Batch\Test\XYZ.ps1
If you need to run something 10 times, do it in a loop inside your PS script.
I want to run a script that will continue executing even when I close the terminal window.
I use the following command on PowerShell 2.0 to download files from the Internet:
$fyle = New-Object System.Net.WebClient;
$fyle.DownloadFile($url, $dest);
The following script downloads and runs a .ps1 script, and I can close the window, but not immediately since I have to wait for the file to download..
$fyle = New-Object System.Net.WebClient;
$fyle.DownloadFile($url, $dest_filename);
Start-Process cmd -ArgumentList " /c start /min powershell -Exec Bypass $dest_filename" -NoNewWindow
To try to fix that, all I did was put $fyle inside the Start-Process block:
$url = "https://google.com";
$dir = "$env:userprofile/adir";
$dest_filename = "$dir/script.ps1";
Start-Process cmd -ArgumentList " /c start powershell -Exec Bypass mkdir $dir; $fyle=New-Object System.Net.WebClient; $fyl.DownloadFile($url,$dest_filename); $dest_filename"
However, I get this error:
The term '=New-Object' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.
At line:1 char:40
+ mkdir C:\Users\IEUser/adir; =New-Object <<<< System.Net.WebClient; .DownloadFile(https://google.com,C:\Users\IEUser/adir/script.ps1); C:\Users\IEUser/adir/script.ps1
+ CategoryInfo : ObjectNotFound: (=New-Object:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
The typo in your code aside, if you take a closer look at the statement throwing the error it becomes pretty much apparent what is happening:
+ mkdir C:\Users\IEUser/adir; =New-Object <<<< System.Net.WebClient; .DownloadFile(https://google.com,C:\Users\IEUser/adir/script.ps1); C:\Users\IEUser/adir/script.ps1
^^ ^^
The variable you intend to use is missing at the positions I indicated above. Without the variable the statements become incomplete commands, thus throwing the error you observed.
The reason for this is that you're passing the arguments for CMD in a double-quoted string. PowerShell's parser expands all variables in that string before passing it to Start-Process. Undefined variables are expanded to empty strings, leaving you with an incomplete commandline to execute. The variable expansion also leads to another issue with your code, because the variables that serve as the arguments for DownloadFile() are also expanded before the string is passed to Start-Process. However, DownloadFile() expects strings not bare words as its arguments.
You can fix this by escaping the $ in variables you define inside your argument string and adding quotes around the arguments for DownloadFile():
Start-Process cmd -ArgumentList " /c start powershell -Exec Bypass mkdir $dir; `$fyle=New-Object System.Net.WebClient; `$fyle.DownloadFile('$url','$dest_filename'); $dest_filename"
# ^ ^ ^ ^ ^ ^
Better yet, define your argument list as an array before passing it to Start-Process:
$params = '/c', 'start', 'powershell', '-Exec Bypass',
"mkdir $dir;",
'$fyle=New-Object System.Net.WebClient;',
"`$fyle.DownloadFile('$url','$dest_filename');",
"$dest_filename"
Start-Process cmd -ArgumentList $params
msiexec /i "example.msi" /q UserName="my username" password="my password"
The above command is executed perfectly in the command line but I need to execute in the powershell in a single line.
So any one please suggest.
I am new to the powershell.
I have tried below one:
Start-Process -FilePath msiexec -ArgumentList / /i, example.msi, "UserName='my username'","password='my password" -Wait
but it shows some issue:
Start-Process : A positional parameter cannot be found that accepts argument 'System.Object[]'.
At line:1 char:1
+ Start-Process -FilePath msiexec -ArgumentList / /i, "'example.msi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand
You've nearly got it, try this:
start msiexec -ArgumentList
"/i example.msi /q UserName=""my username"" password=""my password"""
If any of your arguments need quotes, you need to double them up.
Try using the "Invoke-Command" cmdlet. Should look something like this:
$computerlist = get-content c:\temp\ComputerNames.txt
foreach ($computer in $computerlist) {
Invoke-Command -ComputerName $computer -ScriptBlock {msiexec /i "\\servername\pathToFile\example.msi" /q UserName="my username" password="my password"}
}
Try looking at the help for this command.
In general when you see parameters such as arguments or argumentslist always keep in mind that an array is expected. Same for the `& path args' format.
The cool thing about the array is that each item will be offered to the executable as if it was implicitly quoted, similar to you surrounding with quotes a parameter in command prompt that contains a space.
For this reason I always use structures like
$arguments=#($var1,$var2)
Like this I never have to worry about what is in the variables. When creating the array in multi line and depending on each case it also makes easier the change management because adding a parameter is a line change. It also helps with commenting one out when troubleshooting
For example
$arguments=#(
$var1
$injectedVar
#$disabled
$var2
)
I am trying to use PowerShell to call an EXE that is at a location/path containing spaces. When I call the script from the command line, the EXE's full path is not being passed to the script. Any ideas as to why this is happening?
PowerShell Script Contents (Untitled1.ps1)
Here is the entire script that gets called from the command line:
param(
[string] $ParamExePath
)
function Run-CallThisExe {
param(
[string] $ThisExePath
)
Write-Host "ThisExePath: " "$ThisExePath"
start-process -FilePath $ThisExePath
}
write-host "ParamExePath: " $ParamExePath
Run-CallThisExe -ThisExePath "$ParamExePath"
Command Line String
Here is the command line string being run from the PowerShell script's parent folder:
powershell -command .\Untitled1.ps1 -NonInteractive -ParamExePath "C:\path with spaces\myapp.exe"
Output
Here is what is output after running the script
ParamExePath: C:\path
ThisExePath: C:\path
start-process : This command cannot be run due to the error: The system cannot
find the file specified.
At C:\sample\Untitled1.ps1:11 char:5
+ start-process -FilePath $ThisExePath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
Just change this:
powershell -command .\Untitled1.ps1 -NonInteractive -ParamExePath "C:\path with spaces\myapp.exe"
To This:
powershell -file .\Untitled1.ps1 -NonInteractive -ParamExePath "C:\path with spaces\myapp.exe"
The -Command Parameter used to execute commands for example {Get-Date}
The -File Parameter used to Run .ps1 Script File
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.
Type Powershell /? to get full details on each Parameter
A couple of other ways to call it:
powershell -command .\Untitled1.ps1 -NonInteractive "-ParamExePath 'C:\path with spaces\myapp.exe'"
powershell -command ".\Untitled1.ps1 -ParamExePath 'C:\path with spaces\myapp.exe'" -NonInteractive
Note that if you pass a folder path to Powershell that has a trailing backslash it cannot handle it. e.g. -ParamFolder "C:\project folder\app\bin debug\". The parameter string ends up with a double quote at the end. So when you try to append the name of a file to it you end up with something like C:\project folder\app\bin debug"Filename.txt. In this case you have to send in a second backslash at the end.
I'm trying to write and execute a .cmd script in powershell. The code I have for this is:
$script = #'
#echo off
SETLOCAL
CALL something here
'#
Invoke-Expression -Command: $script
This is based off this link which explains the here string in powershell. It's at the bottom of the link. Here's the related msdn.
Here's another related link to someone trying to do the same thing.
I keep getting an error that has to do with including the '#' operator within the string:
Invoke-Expression : At line:1 char:7
+ #echo off
+ ~~~
Unexpected token 'off' in expression or statement.
At line:1 char:1
+ #echo off
+ ~~~~~
The splatting operator '#' cannot be used to reference variables in an expression. '#echo' can be used only as an argument to a command. To reference variables in an expression use '$echo'.
I've tried escaping the '#' symbol, and a plethora of other things. I'd like to know why it seemed to work for them in the third link, but throws this error in my case.
Edit:
Writing to a .bat file then running the bat file resulted in the same error:
$batchFileContent = #'
#echo off
c:\windows\system32\ntbackup.exe backup "C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Windows NT\NTBackup\data\chameme.bks" /n "1file.bkf1 created 06/09/2013 at 09:36" /d "Set created 06/09/2013 at 09:36" /v:no /r:no /rs:no /hc:off /m normal /j chameme /l:s /f "\\fs1\Exchange Backups$\1file.bkf"
'#
$batchFileContent | Out-File -LiteralPath:"$env:TEMP\backup.cmd" -Force
Invoke-Expression -Command:"$env:TEMP\backup.cmd"
Remove-Item -LiteralPath:"$env:TEMP\backup.cmd" -Force
As Bill Stewart pointed out, I should write the content of the .cmd script in powershell.
Edit:
This
$script = #'
cmd.exe /C "#echo off"
cmd.exe /C "SETLOCAL"
cmd.exe /C "CALL something here"
'#
Invoke-Expression -Command: $script
Seems to work.
This happens because Invoke-Expression interprets your string with PowerShell. PowerShell allows you to run shell commands, but it interprets things as PowerShell first. The # character is the splatting operator in PowerShell.
You should save the commands in a batch file, and then execute that.
Or you can execute single line commands by shelling out to cmd.exe:
Invoke-Expression "cmd.exe /c #echo something"