How to run a Powershell script from the command line and pass a directory as a parameter - powershell

PowerShell -Command .\Foo.ps1
Foo.ps1:
Function Foo($directory)
{
echo $directory
}
if ($args.Length -eq 0)
{
echo "Usage: Foo <directory>"
}
else
{
Foo($args[0])
}
Despite Foo.ps1 being in the directory from where I am calling Powershell, this results in:
The term '.\Foo.ps1' 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.
EDIT: Wasn't working because PowerShell was changing directory due to profile.ps1 containing cd C:\
I then tried to call it specifying the full path to the script file, but no matter what I try, I can't get it to work. I believe I have to quote the path because it contains whitespaces, as does the file name I need to pass in an argument to the script.
Best guess so far:
PowerShell -Command "'C:\Dummy Directory 1\Foo.ps1' 'C:\Dummy Directory 2\File.txt'"
Outputs error:
Unexpected token 'C:\Dummy Directory 2\File.txt' in expression or statement.
At line:1 char:136.

try this:
powershell "C:\Dummy Directory 1\Foo.ps1 'C:\Dummy Directory 2\File.txt'"

you are calling a script file not a command so you have to use -file eg :
powershell -executionPolicy bypass -noexit -file "c:\temp\test.ps1" "c:\test with space"
for PS V2
powershell.exe -noexit &'c:\my scripts\test.ps1'
(check bottom of this technet page http://technet.microsoft.com/en-us/library/ee176949.aspx )

Using the flag -Command you can execute your entire powershell line as if it was a command in the PowerShell prompt:
powershell -Command "& '<PATH_TO_PS1_FILE>' '<ARG_1>' '<ARG_2>' ... '<ARG_N>'"
This solved my issue with running PowerShell commands in Visual Studio Post-Build and Pre-Build events.

Add the param declation at the top of ps1 file
test.ps1
param(
# Our preferred encoding
[parameter(Mandatory=$false)]
[ValidateSet("UTF8","Unicode","UTF7","ASCII","UTF32","BigEndianUnicode")]
[string]$Encoding = "UTF8"
)
write ("Encoding : {0}" -f $Encoding)
result
C:\temp> .\test.ps1 -Encoding ASCII
Encoding : ASCII

Change your code to the following :
Function Foo($directory)
{
echo $directory
}
if ($args.Length -eq 0)
{
echo "Usage: Foo <directory>"
}
else
{
Foo([string[]]$args)
}
And then invoke it as:
powershell -ExecutionPolicy RemoteSigned -File "c:\foo.ps1" "c:\Documents and Settings" "c:\test"

you have type and hit enter :
PowerShell -Command

Related

Wrong encoding with powershell shell command

I setup my powershell so I can drag and drop files on .ps1 files and start the script with the file paths as arg parameters.
I set a default key to
\HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\Open\Command
Default key
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File "%1" %*
But this command can't handle files with cyrillic or japanese characters.
For example, create a test.ps1 file:
foreach ($arg in $args) {
Write-Host "$arg"
}
pause
and I start this script like this:
powershell -File test.ps1 "ダーク" "Олег"
I get this result:
PS C:\Users\...\Desktop> powershell -File test.ps1 "ダーク" "Олег"
???
????
Is there an alternative command I can set to start a script or is there a way to force an encoding for this command?

When I start the PowerShell script from the CMD this is not setting the variables well

If I start the command from PowerShell it works perfectly instead of CMD this happens:
Imgur Image
PowerShell -NoLogo -NoProfile -Command "$MangaPage=Invoke-WebRequest -Uri %MangaLink%; $MangaName=$MangaPage.ParsedHtml.querySelector('#top-in > div.top-title > span.hideM0 > a').innerText; Write-Host $MangaName; $ChapterNumber=$MangaPage.ParsedHtml.querySelector('#combobox > option.selected').innerText; Write-Host $ChapterNumber; $PageNumber=$MangaPage.ParsedHtml.querySelector('#pageSelect > option.selected').innerText; Write-Host $PageNumber; $URLImage=$MangaPage.ParsedHtml.querySelector('#mainImg').src.replace('about:', 'https:'); Write-Host $URLImage; $FileExtension=$URLImage.SubString($URLImage.lastIndexOf('.')+1); Write-Host $FileExtension; $FileName='$.ChapterNumber'+'_'+'$PageNumber'+'_'+'$MangaName'+'.'+'$FileExtension'; $Folder=('$MangaName\$ChapterNumber'); If(!(Test-Path $Folder)) { New-Item -ItemType Directory -Force -Path $Folder }; Invoke-WebRequest $URLImage -OutFile $Folder\$FileName"
About PowerShell.exe
When the value of Command is a string, Command must be the last
parameter specified because any characters typed after the command are
interpreted as the command arguments.
The Command parameter only accepts a script block for execution when
it can recognize the value passed to Command as a ScriptBlock type.
This is only possible when running PowerShell.exe from another
PowerShell host. The ScriptBlock type may be contained in an existing
variable, returned from an expression, or parsed by the PowerShell
host as a literal script block enclosed in curly braces {}, before
being passed to PowerShell.exe.
In cmd.exe, there is no such thing as a script block (or ScriptBlock
type), so the value passed to Command will always be a string. You can
write a script block inside the string, but instead of being executed
it will behave exactly as though you typed it at a typical PowerShell
prompt, printing the contents of the script block back out to you.
A string passed to Command will still be executed as PowerShell, so
the script block curly braces are often not required in the first
place when running from cmd.exe. To execute an inline script block
defined inside a string, the call operator & can be used:
console
"& {}"
PowerShell -NoLogo -NoProfile -Command "&{ $MangaPage=Invoke-WebRequest -Uri %MangaLink%; $MangaName=$MangaPage.ParsedHtml.querySelector('#top-in > div.top-title > span.hideM0 > a').innerText; Write-Host $MangaName; $ChapterNumber=$MangaPage.ParsedHtml.querySelector('#combobox > option.selected').innerText; Write-Host $ChapterNumber; $PageNumber=$MangaPage.ParsedHtml.querySelector('#pageSelect > option.selected').innerText; Write-Host $PageNumber; $URLImage=$MangaPage.ParsedHtml.querySelector('#mainImg').src.replace('about:', 'https:'); Write-Host $URLImage; $FileExtension=$URLImage.SubString($URLImage.lastIndexOf('.')+1); Write-Host $FileExtension; $FileName='$.ChapterNumber'+'_'+'$PageNumber'+'_'+'$MangaName'+'.'+'$FileExtension'; $Folder=('$MangaName\$ChapterNumber'); If(!(Test-Path $Folder)) { New-Item -ItemType Directory -Force -Path $Folder }; Invoke-WebRequest $URLImage -OutFile $Folder\$FileName}"

Invoke .cmd file using variable name

The current PowerShell script invokes a .cmd file as follows:
cd $pathToCmdFile
.\Xyz.Web.deploy /y
I would like to change this so that Xyz is used as a variable, something like:
$webAppName = "Xyz"
cd $pathToCmdFile
.\$webAppName.Web.deploy /y
I've already tried
$cmd = ".\$webAppName.Web.deploy /y"
Invoke-Expression $cmd
Shows
The term '.\Xyz.Web.deploy' is not recognized as the name of a cmdlet, function, script file or operable program...
I've also tried Invoke-Command, Invoke-Item but none seem to work. I have also tried putting an ampersand ($cmd = "& .\$webAppName.Web.deploy /y"), but that didn't work either.
The proper way of doing what you want is to use the call operator (&). You must not include the operator or command arguments in the command string, though.
This should work:
$webAppName = "Xyz"
cd $pathToCmdFile
& ".\${webAppName}.Web.deploy.cmd" /y
I strongly recommend to always specify commands/scripts with their extension.
So Invoke-Expressions should work:
test.cmd
set
test.ps1 calls test.cmd
cd .
$webAppName = "Test"
Invoke-Expression ".\\$webAppName.cmd"
So now you run the powershell script
> .\test.ps1
ALLUSERSPROFILE=C:\ProgramData
ANSICON=234x1000 (234x47)
ANSICON_DEF=7
...
Or you could do this so you can pass a parameter to the powershell script
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$webAppName
)
cd .
Invoke-Expression ".\\$webAppName.cmd"

Capturing different streams in file

I'm trying to capture the Verbose, Error and other streams of a PowerShell script in a file. This to monitor the output of my script.
The following code works fine:
$LogFile = 'S:\ScriptLog.log'
$ScriptFile = 'S:\TestieScript.ps1'
powershell -Command $ScriptFile *>&1 > $LogFile
However, the moment I try to put a space in one of the file paths, it's no longer working. I tried a lot of things, like double quotes, single quotes, .. but no luck.
To illustrate, the following code doesn't work:
$LogFile = 'S:\ScriptLog.log'
$ScriptFile = 'S:\Testie Script.ps1'
powershell -Command $ScriptFile *>&1 > $LogFile
One person in this thread has the same issue.
Thank you for your help.
You're trying to run a file whose name contains a space as a command without proper quoting, so you're most likely getting an error like this in your log:
The term 'S:\Testie' is not recognized as the name of a cmdlet, function, script file, or operable program.
Either add proper quoting (and the call operator &, because your path is now a string):
powershell -Command "& '$ScriptFile'" *>&1 > $LogFile
or (better) use the -File parameter, as #CB. already suggested:
powershell -File $ScriptFile *>&1 > $LogFile
which has the additional advantage that the call will return the actual exit code of the script.
Edit: If you want to run the command as a scheduled task you'll need to use something like this:
powershell -Command "& 'S:\Testie Script.ps1' *>&1 > 'S:\ScriptLog.log'; exit $LASTEXITCODE"
because the redirection operators only work inside a PowerShell process.
try using -file parameter:
powershell -file $ScriptFile *>&1 > $LogFile

passing \ in argument to powershell script causes unexpected escaping

This is my powershell script test.ps1:
Write-Output $args;
Now suppose I have a batch script that calls this powershell script with all kinds of paths. One of those is c:\:
powershell -executionpolicy Bypass -file test.ps1 "c:\"
The output is:
c:"
Is there any way to quote my arguments such that c:\ would actually be taken and stored as is in the $args[0] variable? I know I can solve this quick'dirty by passing "c:\\", but that's not a real solution.
EDIT: using named parameters in test.ps1 doesn't make any difference:
[CmdletBinding()]
param(
[string]$argument
)
Write-Output $argument;
EDIT2: using a batch file instead works fine.
My test.bat script:
echo %~1
I run it:
test.bat "c:\"
Returns nicely:
c:\
Are you sure this comes form powershell and not from the program which invokes your statement? The backslash is no escape code in powershell.
my test.ps1 is working, when run from ise.
this works for me:
powershell -executionpolicy Bypass -command "test.ps1 -argument 'C:\'"
(end with quote double-quote)
Help file for PowerShell.exe says:
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.
You are against Powershell.exe's command line parser, which uses "\" to escape quotes. Do you need quotes? Not in your case:
powershell -file test.ps1 c:\
prints
c:\
Similarly, this works too
powershell -file test.ps1 "c:\ "
c:\
but then your arg has that extra space which you would want to trim. BTW, Single quotes do not help here:
powershell -file test.ps1 'c:\'
'c:\'
If you need the final backlash to be passed to the command, you can use
$ArgWithABackslashTemp = $ArgWithABackslash -replace '\\$','\\'
&$ExePath $ArgWithABackslashTemp
Or, if the exe is smart enough to handle it without the trailing backslash
&$ExePath $ArgWithABackslash.trim('\')