Wrong encoding with powershell shell command - powershell

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?

Related

Process files dragged to BAT file in PowerShell

I trying to create a script that will convert Markdown files that are dropped on a processing script.
To accomplish this, I created a (process.bat) that would pass the names of the dropped files to a PowerShell script:
powershell.exe -NoProfile -File "./process.ps1" -Document %*
#pause
The PowerShell file (process.ps1) would process each file individually:
[parameter(Mandatory=$true)]
[String[]]$Document
Write-Host $args[1]
$Document | ForEach-Object {
Write-Host "Document: $_"
# convert Markdown to Html
pandoc -o ($_ -Replace '.md', '.html') -f markdown -t html $_
}
When I drop two files on the batch file:
C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown>powershell.exe -NoProfile -File "./process.ps1" -Document "C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown\FOO.md"
"C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown\BAR.md"
C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown\BAR.md
Document:
Press any key to continue . . .
The documents are not being processed.
What's the recommended approach to passing the batch file's file list %* to PowerShell?
When powershell.exe, the PowerShell CLI, is called from the outside with the -File parameter, it doesn't support arrays - only individual arguments.[1]
(Additionally, you neglected to wrap your parameter definition in a param(...) block, which effectively caused it be ignored.)
The simplest solution is to define your parameter with the ValueFromRemainingArguments option so that it automatically collects all positional arguments in the parameter variable:
param(
[Parameter(Mandatory, ValueFromRemainingArguments)]
[String[]] $Document
)
Then invoke your script via the PowerShell CLI without -Document:
powershell.exe -NoProfile -File "./process.ps1" %*
As an alternative to using a helper batch file, you can:
define a shortcut file (*.lnk) that explicitly invokes your PowerShell script as powershell.exe -File \path\to\your\script.ps1 (without additional arguments)
and then use that as the drop target.
Note: The reason that you cannot use a PowerShell script (*.ps1) directly as a drop target is that PowerShell script files aren't directly executable - instead, opening (double-clicking) a *.ps1 file opens it for editing.
You'd then need to add pause (or something similar, such as Read-Host -Prompt 'Press Enter to exit.') to your PowerShell script, to prevent it from closing the window instantly on finishing.
Alternatively, leave the script as-is and use -NoExit (placed before -File) to keep the PowerShell session open.
[1] The same applies to the PowerShell Core CLI, pwsh.

How can I associate a file type with a powershell script?

I have a very powershell script that works perfectly and does:
Param(
[string]$fileName
)
echo "Woo I opened $fileName"
When I run it on the command line, it works:
my-script.ps1 .\somefile
Returns:
Woo I opened somefile
I would like to associate my-script.ps1 with a particular file type. I am attempting to do this via 'Open With' However:
Windows doesn't include Powershell scripts as 'Programs' (though it considers CMD and batch scripts as 'Programs')
When I pick 'All Files' instead, and pick my powershell script, Windows shows this message
How can I associate a file type with a Powershell script?
Use the proper tools for the job:
cmd /c assoc .fob=foobarfile
cmd /c ftype foobarfile=powershell.exe -File `"C:\path\to\your.ps1`" `"%1`"
Note that both assoc and ftype are CMD-builtins, so you need to run them via cmd /c from PowerShell.
For files without extension use this association:
cmd /c assoc .=foobarfile
I don't think you can do it through Windows UI.
The goal here is to associate a type with powershell.exe, arguments to which will be
The powershell script
The target filename
To do this
Launch Regedit.exe. //disclaimer: you are editing Windows registry. Here be tigers.
Go to HKEY_CLASSES_ROOT (admin access, for all users) or HKEY_CURRENT_USER\SOFTWARE\Classes
Create a key named .<extension>, e.g. if you want to associate *.zbs - create a key .zbs
Set it's (default) value to something like zbsfile -- this is a reference linking your extension to a filetype.
Create a key called zbsfile - this is your filetype
Set (default) value to something readable, e.g. "This file is ZBS."
Underneath create a tree of keys (examples are all around):
zbsfile
shell
open
command
Under command, set (default) value to e.g.
powershell.exe -File "C:\path\to your\file.ps1" "%1"
where %1 means the file user clicked
That should work.
EDIT:
or (crazy idea), create a bat file doing just powershell.exe -File "C:\path\to your\file.ps1" "%%1" and select it in Windows UI...
For those like me who got here looking for general file types associations, I ended up using this function:
Function Create-Association($ext, $exe) {
$name = cmd /c "assoc $ext 2>NUL"
if ($name) { # Association already exists: override it
$name = $name.Split('=')[1]
} else { # Name doesn't exist: create it
$name = "$($ext.Replace('.',''))file" # ".log.1" becomes "log1file"
cmd /c 'assoc $ext=$name'
}
cmd /c "ftype $name=`"$exe`" `"%1`""
}
I struggled with proper quoting from #Ansgar Wiechers's answer but finally got it right :)
Here's my remix of #Matthieu 's great remix of #Ansgar Weichar's great answer.
Matthieu's is set up for executables, and doesn't work for powershell scripts for the same reasons the OP describes.
Function Set-FileAssociationToPowerShellScript($extension, $pathToScript) {
# first create a filetype
$filetype = cmd /c "assoc $extension 2>NUL"
if ($filetype) {
# Association already exists: override it
$filetype = $filetype.Split('=')[1]
Write-Output "Using filetype $filetype"
}
else {
# Name doesn't exist: create it
# ".log.1" becomes "log1file"
$filetype = "$($extension.Replace('.', ''))file"
Write-Output "Creating filetype $filetype ($extension)"
cmd /c "assoc $extension=$filetype"
}
Write-Output "Associating filetype $filetype ($extension) with $pathToScript.."
cmd /c "ftype $filetype=powershell.exe -File `"$pathToScript`" `"%1`""
}
Here is a concrete answer tested under Windows 7 (but should work under 10 too). Open an administrative command shell and execute the following two lines once:
> assoc .ps1=Microsoft.PowerShellScript.1
> ftype Microsoft.PowerShellScript.1=%windir%\System32\WindowsPowerShell\v1.0\powershell.exe -File "%1"
Now PS1-files are executed by PowerShell 1.0 and not opened by Notepad anymore when double-clicked in the Explorer.
For get associate app i use [!magic] :) :
Set-Alias fa Get-AssocApp
#Get application by file extension Proto1
function Get-AssocApp ([string] $FileType) {
((cmd /c echo ((cmd /c ftype ( (cmd /c assoc $FileType) -replace "(.*=)*" ,"")) -replace "(.*=)","")).Replace('"','') -replace "\s%+.*$" ,"")
}
Out:
PS C:\Users\user> fa .txt
C:\WINDOWS\system32\NOTEPAD.EXE
PS C:\Users\user> fa .pdf
C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe
PS C:\Users\user> fa .js
C:\Windows\System32\WScript.exe

Need to call powershell script from batch file

I have a batch file which is in a folder called script. The script folder also contains folder called powershell which has a script called IE-Settings.ps1.
I want to execute the powershell script from the batch file and I am unable to give powershell script path in the command. What I tried is
call %windir%\system32\WindowsPowerShell\v1.0\powershell.exe -File "& '%~dp0IESettings\IE-Settings.ps1'"
But it doesn't recognize the path
call is for running other batch files in a way that they return to the current batch file after they terminate, and per your question the subdirectory name is powershell, not IESettings. Also, when using the parameter -File you just specify the path to the file.
powershell.exe -File "%~dp0powershell\IE-Settings.ps1"
The call operator (&) is used when running PowerShell code via the -Command parameter, e.g.:
powershell.exe -Command "& { Write-Host 'foo' }"

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('\')

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

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