I set cscript.exe as my default scripting host with the nologo option. Therefore in cmd.exe
I get, as expected:
> ftype jsfile
jsfile="C:\Windows\System32\CScript.exe" //nologo "%1" %*
> reg query HKCR\jsfile\Shell\Open\Command
HKEY_CLASSES_ROOT\jsfile\Shell\Open\Command
(Default) REG_EXPAND_SZ "C:\Windows\System32\CScript.exe" //nologo "%1" %*
> echo WScript.Echo("Test Echo"); > test.js
> test.js
Test Echo
But, moving to Powershell:
> powershell -nologo
PS > .\test.js
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.
Test Echo
It seems that CScript does not get //nologo from Powershell shell.
How can I fix this?
More use cases
It also works with:
PS > cscript.exe //nologo test.js
Test Echo
PS > cmd /c test.js
Test Echo
PS > cmd /c test
Test Echo
Copy & Paste Test
Someone suggests it can be a bug. To check if it applies to you, you can copy the following in a PS console with elevated privileges:
## Change the host to cscript nologo and store old setting
$jstype="Registry::HKEY_CLASSES_ROOT\jsfile\Shell\Open\Command"
$jsvalue=("`"$env:SystemRoot\System32\CScript.exe`"" + ' //nologo "%1" %*')
$old=(gp -Path $jstype )."(default)"
Set-Item -Path $jstype -value $jsvalue
## The output should be the same (i.e. nologo!)
echo 'WScript.Echo("Test Echo");' > test.js
cmd /c test
.\test.js
## Restore old settings
Set-Item -Path $jstype -value $old
Is cmd /c test and .\test.js output the same?
Details on the problem
It seems that Powershell has a weird behaviour with respect to file associations.
If you paste the following snippet in an elevated privilege PS shell:
$jstype="Registry::HKEY_CLASSES_ROOT\jsfile\Shell\Open\Command"
Set-Item -Path $jstype -value "cscript.exe total non sense"
echo 'WScript.Echo("Test Echo");' > test.js
cmd /c test.js
... you get the deserved error for associating jsfiles with the command string cscript.exe total non sense.
But surprisingly writing:
.\test.js
works like a charm. So it seems that PS only reads the first item of the open-command-string (here cscript.exe) and then appends to it the user string (.\test.js), totally disregarding the other elements of the open-string, here total non sense.
To confirm paste this:
Set-Item -Path $jstype -value "notepad.exe total non sense"
echo 'WScript.Echo("Test Echo");' > test.js
cmd /c test.js
cmd.exe opens the Notepad which proposes to create the file "total non sense.txt".
Now write:
.\test.js
Based on what I just said, the actual command run will be notepad.exe .\test.js and in fact the Notepad will now open .\test.js.
Solution
Whether or not this is a bug, a possible solution is to create a batch script calling the cscript.exe with the desired parameters. I will name it C:\Windows\System32\cscript.cmd.
To create the script and the related association, paste:
echo "#cscript.exe //nologo %*" | out-file -encoding ASCII C:\Windows\System32\cscript.cmd
$jstype="Registry::HKEY_CLASSES_ROOT\jsfile\Shell\Open\Command"
$jsvalue=("`"$env:SystemRoot\System32\cscript.cmd`"" + ' "%1" %*')
Set-Item -Path $jstype -value $jsvalue
As you see //nologo is moved from the registry to cscript.cmd.
Note that echo "string" > would produce a Unicode file, which cmd.exe dislikes, hence the ASCII filter.
Print your new .js opening command:
cmd /c ftype jsfile
That is: jsfile="C:\Windows\System32\cscript.cmd" "%1" %*.
Now both:
cmd /c test
.\test
will produce:
Test Echo
without the banner, and note that in both cases you don't need to specify the .js extension.
For simplicity I set cscript.cmd to run cscript.exe straight. You might want to specify its full path.
Related
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?
Here is what I currently do, file 1:
powershell.exe -command "Start-Process cmd -ArgumentList '/c cd C:\ && DiskZero.cmd'-Verb runas"
And file 2 "DiskZero.cmd":
#echo off
(echo rescan
echo sel disk 1
echo cle all
echo cre part prim
echo for fs=ntfs quick label=Intenso
echo assign letter=E
) | diskpart
pause
It works as intended, however, there is two files, what I want to do is make it so there's only one file.
I can't manage to find how to input multiple lines of code into a new elevated command prompt with only one script, so instead I'm trying to do it with powershell:
start cmd -nonewwindow works
start cmd -ver runas works
however start cmd -nonewwindow -ver runas doesn't work
What I was hoping to do was this in powershell:
start cmd -nonewwindow -ver runas
#echo off
(echo rescan
echo sel disk 1
echo cle all
echo cre part prim
echo for fs=ntfs quick label=Intenso
echo assign letter=E
) | diskpart
pause
Can anyone help me solve the start cmd -nonewwindow -ver runas issue OR input multiple lines of code into a new elevated command prompt with only one file, please?
Can anyone help me solve the start cmd -nonewwindow -verb runas issue
Unfortunately, there is no solution: Windows fundamentally does not allow you to run an elevated process (run as admin, requested with -Verb RunAs) directly in a non-elevated process' console window - that is why Start-Process syntactically prevents combining -NoNewWindow with -Verb RunAs.
OR input multiple lines of code into a new elevated command prompt with only one file, please?
While there is a solution, it'll be hard to maintain:
You can pass the lines of your second batch file (the one you want to eliminate) to cmd /c on a single line, joined with &:
Note: To facilitate side effect-free experimentation, the original diskpart command was replaced with findstr -n ., which merely prints the lines received via stdin, preceded by their line number.
powershell.exe -command "Start-Process -Verb RunAs cmd '/c cd C:\ && (echo rescan&echo sel disk 1&echo cle all&echo cre part prim&echo for fs=ntfs quick label=Intenso&echo assign letter=E) | findstr -n .&pause'"
That no space char. precedes each & is deliberate, because trailing whitespace in echo commands is significant, i.e. it becomes part of the output; however, it should be fine to place a space char. after each & (as well as before, if the preceding command ignores trailing whitespace).
A better solution is to create a temporary helper batch file from your batch file, pass its path to the PowerShell command, and delete it afterwards:
#echo off
:: Determine the path for a temporary batch file...
:: Note: %~snx0 uses the short (8.3) name of the batch file, so as
:: to ensure that the temp. file path has no spaces, which
:: obviates the need for complex double-quoting later.
set "tmpBatchFile=%TEMP%\~%~snx0"
:: ... and fill it with the desired commands.
:: Note how metacharacters - ( ) | ... - must be ^-escaped.
(
echo #echo off
echo ^(echo rescan
echo echo sel disk 1
echo echo cle all
echo echo cre part prim
echo echo for fs=ntfs quick label=Intenso
echo echo assign letter=E
echo ^) ^| findstr -n .
echo pause
) > "%tmpBatchFile%"
:: Now you can let the elevated cmd.exe process that PowerShell launches
:: execute the temp. batch file.
:: Note: -Wait ensures that the PowerShell call blocks until the elevated
:: cmd.exe window closes.
powershell.exe -command "Start-Process -Wait -Verb RunAs cmd '/c cd C:\ & %tmpBatchFile%'"
:: Delete the temp. batch file.
:: Note: If you do NOT use -Wait above, you'll have to defer deleting
:: the batch file until after the elevated cmd.exe window closes,
:: which you'll have to do manually.
del "%tmpBatchFile%"
I have a .bat file like this. But I can not run the SeqEdit.exe as administrator by this command. I research about Powershell but I don't know how to use it correctly. please help me to convert this command to powershell command format.
Thank you in advance.
#echo off
cd "C:\Program Files\National Instruments\TestStand 2016\Bin"
start /min "" SeqEdit.exe /runEntryPoint "Test UUTs" "C:\Peritec\111 Renesas for Oita\SLT Test System_ver109c\Sequence\SLT Test_Main_Ver2016.2.seq"
exit
You can use this:
Set-Location "C:\Program Files\National Instruments\TestStand 2016\Bin"
Start-Process -FilePath ".\SeqEdit.exe" -ArgumentList "/runEntryPoint 'Test UUTs' 'C:\Peritec\111 Renesas for Oita\SLT Test System_ver109c\Sequence\SLT Test_Main_Ver2016.2.seq'" -Verb RunAs -WindowStyle minimized
If you want to do it with cmd first create this batch file:
#echo off
echo Set objShell = CreateObject("Shell.Application") > %temp%\sudo.tmp.vbs
echo args = Right("%*", (Len("%*") - Len("%1"))) >> %temp%\sudo.tmp.vbs
echo objShell.ShellExecute "%1", args, "", "runas" >> %temp%\sudo.tmp.vbs
cscript //nologo %temp%\sudo.tmp.vbs
Now run this from another batch file:
pushd "The location of seqedit.exe"
TheFullPathAndNameOfAboveBatchFile seqedit.exe "arguments" "arguments"
I'm currently trying to run a batch file as a startup script to detect and remove whatever version of office a user has installed and then to install Office 365. I have the install working however, when I attempted to uninstall Office 2013 I received the following error:
Input Error: Can not find script file "C:\Windows\OffScrub_O15msi.vbs"
The Offscrub file is in the same location as the script, is someone able to tell me why it's looking in C:\Windows for it?
Update
Please find my current script which now works for Office 2013, I previously added the line Remove2016Installs $true when using -Command to remove Office 2016, this worked. Since using -File to work around my initial problem I've been unable to get the script to remove Office 2016 and would like some advice on how to do this, I've read that whatever command is after -File needs to be the last which I believe might be why it's failing.
My full script is below:
start "----NOTICE----" cmd.exe /t:ec /Q /k "echo OFFICE 365 IS BEING INSTALLED. THIS WINDOW WILL CLOSE WHEN COMPLETE&&prompt $h"
#echo off
pushd "%~dp0"
powershell.exe -executionpolicy bypass -NoExit -File "Remove-PreviousOfficeInstalls.ps1"
popd
reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS=32BIT || set OS=64BIT
if %OS%==32BIT "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\setup.exe" /configure "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\configuration-Office365-x86.xml"
if %OS%==64BIT "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\setup.exe" /configure "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\configuration-Office365-x64.xml"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ ----NOTICE----"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ Administrator: ----NOTICE----"
echo %date% %time% Setup ended with error code %errorlevel%. >> %LogLocation%\%computername%.txt
Update Finished
There's a line that calls the Powershell script Remove-PreviousOfficeInstalls, this is a file from GitHub that is very popular for the removal of whichever Office version you have installed.
I can run this command if say I copy these files to the desktop and amend the locations in the scripts, I'm not sure what this reference to C:\Windows is though when run from \domain\SYSVOL\domain\Policies{Policy Number}\Machine\Scripts\Startup\?
If you run a default instances of PowerShell it always starts in a certain directory. It depends on how and who it is started by. For instance an administrative PowerShell usually starts in C:\Windows\System32. If you use any paths that are not absolute they're applied relative to this directory.
To work around this you need to change the directory it's using. For instance by using cd to change the directory. My guess would be that your script Remove-PreviousOfficeInstalls.ps1 contains a relative call to the VBS.
An easy fix would be to run a script block instead of a single command and just cd to \\domain\SYSVOL\domain\Policies\'{Policy Number}'\Machine\Scripts\Startup\ prior to running the ps1.
The PowerShell help you can view by following [this] link or running powershell -h has the following information in regards to using the -Command switch.
...
Script blocks must be enclosed in braces ({}). You can specify a script block only when running PowerShell.exe in PowerShell. If you want to use a script block when running from another shell you must use the format:
"& {}"
...
The other important parameter for your use case is -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.
...
Your batch contains the following line:
powershell.exe -executionpolicy bypass -Command "\\domain\SYSVOL\domain\Policies\'{Policy Number}'\Machine\Scripts\Startup\Remove-PreviousOfficeInstalls.ps1 -Remove2016Installs $true"
What you do is run a single command to invoke a script with a parameter. The problems is that said script checks its locations based on certain function and with your invocation that location is wrongly detected.
There are multiple ways to fix this. One would be to change the directory before invoking the script. To do this you'd need to use a script block as the parameter for -Command. An example for this would be:
powershell.exe -Command "& {Write-Output 'Hello'; Write-Output 'World';}"
As you can see there are two independent Write-Output commands being run. You'd change this to a cd \\domain\SYSVOL\domain\Policies\'{Policy Number}'\Machine\Scripts\Startup\ and the invocation of your script. As a bonus you wouldn't need to put the whole path in front of the script anymore.
The other option would be to run powershell -File with your current invocation of the script. That should also mean that the script is read from the file and the corresponding parameters are populated accordingly.
If neither of these options work you will have to check what $PSScriptRoot is being populated with and/or what the return of (Get-Item -Path ".\").FullName is as those are the two commands used to determine the location of the script that's being executed. To do this you could use a script block.
thanks for your help regarding this. My resolution was to use the following bat command:
`start "----NOTICE----" cmd.exe /t:ec /Q /k "echo OFFICE 365 IS BEING INSTALLED. THIS WINDOW WILL CLOSE WHEN COMPLETE&&prompt $h"`
#echo off
pushd "%~dp0"
powershell.exe -executionpolicy bypass -File Remove-PreviousOfficeInstalls.ps1 -Remove2016Installs
popd
reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS=32BIT || set OS=64BIT
if %OS%==32BIT "\\Server\Folder\Folder\setup.exe" /configure "\\Server\Folder\Folder\configuration-Office365-x86.xml"
if %OS%==64BIT "\\Server\Folder\Folder\setup.exe" /configure "\\Server\Folder\Folder\configuration-Office365-x64.xml"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ ----NOTICE----"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ Administrator: ----NOTICE----"
echo %date% %time% Setup ended with error code %errorlevel%. >> %LogLocation%\%computername%.txt
I had to amend the Remove-PreviousOfficeInstalls powershell script to include the switch command:
[Parameter(ValueFromPipelineByPropertyName=$true)]
[switch]$Remove2016Installs = $false,
This then did exactly what I was after, it detected the current version of Office, removed it and installed the correct bit version of Office 365 for that PC\Laptop.
Thanks for all your help
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