Execute batch file in Powershell - powershell

I want to execute the following from a batch file:
"C:\OpenCover\tools\OpenCover.Console.exe" -register:user -target:"%VS110COMNTOOLS%..\IDE\mstest.exe" -targetargs:"/testcontainer:\"C:\Develop\bin\Debug\MyUnitTests.dll\" ... "
PAUSE
Now I would like to log the output of the process to a file for which I came across the quite handy powershell usage of
powershell "dir | tee output.log"
but this does not take my batch file as first argument (powershell "my.bat | tee output.log") because it is not the name of a cmdlet or a function or a script file.
I could change my batch file so that is says powershell "OpenCover.Console.exe..." but I would have to adapt all quotes and change escape characters and so forth.
Is there a way to make a batch file execute in powershell? Or is there a way to drop in my line unchanged from the batch after some powershell command and it all executes "like it ought to"?

Unless your batch file is in a folder in the %PATH%, PowerShell won't find it [1], so you'll have to supply an explicit file path (whether relative or absolute).
For instance, if the batch file is in the current folder, run:
powershell -c ".\my.bat | tee output.log"
Consider adding -noprofile to suppress loading of the profile files, which is typically only needed in interactive sessions.
If your batch file path contains embedded spaces, enclose it in single quotes and prepend &:
powershell -c "& '.\my script.bat' | tee output.log"
Note: I've deliberately added the -c (short for: -Command) parameter name above; while powershell.exe - Windows PowerShell - defaults to this parameter, that is no longer true in PowerShell [Core] v6+ (whose executable name is pwsh), where -File is now the default - see about_PowerShell.exe and about_pwsh
[1] More accurately, PowerShell - unlike cmd.exe - will by design not execute scripts in the current folder by their mere filename (in an interactive PowerShell session you'll get a hint to that effect). This is a security feature designed to prevent accidental invocation of a different executable than intended.

Unless you have some purpose for doing so not stated in the OP, there isn't a reason to use both Powershell and a batch script. If you want to do this solely from PS, you can create a PS script that does everything the batch file does.
To avoid the escaping issues (or alternatively to take advantage of CMD.EXE's somewhat strange escaping behavior :-) you can use --%, introduced in PS 3.0. It is documented under about_escape_characters.

Related

Powershell Script only opens as a .txt file when run

Hi I have a script on a memory stick that I want to be able to run in cmd line before a computer has windows fully installed. (the stage just after you've connected to a network).
Cmd used to run the script.
Start > Run D:\pscript\Intune.ps1
This only opens a .txt file, while researching I've found that the reason this happens is due to security, is there anyway to override this bar changing the default file type out.
Unlike batch files (.cmd, .bat) associated with cmd.exe (the legacy Command Prompt), PowerShell's .ps1 script files are by default not directly executable from outside PowerShell.
Instead, they are treated as documents that are by default associated with either Notepad or the (obsolescent) Windows PowerShell ISE, depending on the , and invoking them therefore opens them for editing, which applies to the following contexts:
Invoking a .ps1 file from cmd.exe
Invoking a .ps1 file from Start Menu's Run dialog, as in your case (which you can invoke with WinKey+R, for instance)
Opening (double-clicking) a .ps1 file from File Explorer or Desktop.
To execute a .ps1 script from outside PowerShell, you must therefore invoke it via PowerShell's CLI, powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+.
In the simplest case, using Windows PowerShell and the -File parameter, as also shown by Mathias R. Jessen in a comment; see the comments below and the linked docs for additional parameters:
# Note:
# * The effective execution policy applies; use -ExecutionPolicy Bypass to bypass.
# * Profiles are loaded; use -NoProfile to suppress.
# * The console window auto-closes when the script terminates; use -NoExit
# to keep the session open.
powershell.exe -File D:\pscript\Intune.ps1
For a comprehensive overview of PowerShell's CLI, see this post.
It is possible - though not advisable - to configure your system to execute .ps1 files by default - see this answer.

I am trying to run several PowerShell commands from a batch script, however the "%" symbol does not get transferred

I am trying to run several PowerShell commands from a batch script, however the "%" symbol does not get transferred to PowerShell.
For example, writing the following in a command prompt window:
powershell -Command "& {echo 'per%entage'}"
Will print:
per%entage
which is what I want, however if I save the same command into a .bat or .cmd file, it instead prints:
perentage
Why is it ignoring the "%" symbol? Is there a way to make it transfer properly? I'm especially confused that it works in a command prompt window, but not in a batch script. You'd think both would either work or not work.
Very unfortunately, cmd.exe's behavior differs with respect to command invocations from an interactive prompt vs. from a batch file with respect to how % characters are interpreted.
See this answer for background information.
Therefore, when calling from a batch file, a % char. that is to interpreted verbatim, must be escaped as %%:
:: From a *batch file*.
powershell -Command "'per%%entage'"
Note:
echo is a built-in alias for the Write-Output cmdlet, whose explicit use is rarely needed - see this answer for more information.
Invocation of commands (symbolized as ... here) in the form & { ... } is virtually never needed when using the PowerShell CLI - just use ... as-is.
Generally, for predictable invocation, it's worth using the -NoProfile switch as well - before the -Command parameter - so as to bypass loading of PowerShell's profile files, which are primarily meant for interactive sessions.

Powershell: attempting to run a script whose filename has embedded spaces executes a different, similarly named script instead

I am executing PS script under w2008R2 .
e.g.
Alter_all.ps1
If I make standard copy of it to keep original intact next copy is made
e.g.
Alter_all - Copy.ps1
If I try to execute new edited script Alter_all - Copy.ps1 it runs content from previous script no matter what. To resolve this I found that I need to rename script to be without spaces and only then script works with new values
e.g.
Alter_all-Copy.ps1
It seems that Powershell somehow checks name of script but stops at empty space name thinking that you are executing same script you were executing previously?
What is the reason behind this?
It's because - Copy.ps1 are passed as arguments.
Try to execute your new script using the following syntax :
& 'Alter_all - Copy.ps1'
Arnaud Claudel's helpful answer shows you how to invoke a script with embedded spaces in its path from a PowerShell console window or script.
In a later comment you state that you're not calling your script from the command line, but attempting to run it by double-clicking from File Explorer:
By default, for security reasons, double-clicking *.ps1 files does NOT run them - instead, they are opened for editing.
That double-clicking actually executes your scripts if they don't contains spaces in their paths implies two things:
Your system uses a custom configuration that overrides the default behavior.
That custom configuration is flawed, because it cannot handle file paths with embedded spaces.
Therefore, you need to fix your custom configuration, by editing the registry:
Note:
The following assumes the default configuration and overrides it at the current-user level, which doesn't require admin privileges.
If you do want to modify the machine-level configuration, substitute HKEY_LOCAL_MACHINE for HKEY_CURRENT_USER below, as noted in the comments.
The currently configured execution policy is respected, and profiles are loaded; -NoExit is used to invoke powershell.exe, which means that the windows stays open after the script exits.
These behaviors can easily be tweaked by editing the code below.
Note how the placeholder for the script file path, %1, is enclosed in \"...\" to ensure that even paths with embedded spaces are passed as a single argument to powershell.exe's -File parameter.
# Create temp. file for registry definitions.
$tmpFile = [IO.Path]::GetTempFileName()
# Change this to 'HKEY_LOCAL_MACHINE' to override
# the machine-level configuration - REQUIRES RUNNING AS ADMIN.
$rootKey = 'HKEY_CURRENT_USER'
# Create the registry definitions...
#"
Windows Registry Editor Version 5.00
[$rootKey\Software\Classes\Microsoft.PowerShellScript.1\shell\Open\command]
#="$($PSHOME -replace '\\', '\\')\\powershell.exe -NoExit -File \"%1\" %*"
"# > $tmpFile
# ... and import them.
reg.exe import $tmpFile
# Clean up.
Remove-Item -LiteralPath $tmpFile

What is the dash ("-") when used with pipe ("|") in CMD?

I wanted to create some clickable PowerShell scripts, and I found this answer that I modified slightly to be:
;#Findstr -bv ;#F %0 | powershell -noprofile -command - & goto:eof
# PowerShell Code goes here.
I understand Findstr is passing all lines that don't begin with ;#F to the right-hand side of the pipe and the dash specifies where the input should go, but what is the dash character called and where is it documented?
I found an explanation of CMD's pipe operator on Microsoft's Using command redirection operators, but it doesn't mention anything about the dash character.
I presume you mean the - that precedes the &. It has nothing to do with the pipe operator, it is a directive for powershell.
Here is a description of the -Command option excerpted from powershell help (accessed by powershell /?)
-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.
If the value of Command is "-", the command text is read from standard
input.
BTW - I did not realize FINDSTR accepted - as an option indicator until I saw your question. I've only seen and used /. Good info to know.
The - is to Powershell saying accept the command(s) from stdin rather than from arguments. This is not a feature in cmd / batch and piping. It would work with < as well.
Powershell version 2 adds a "Run with Powershell" right-click context menu item to run scripts . Here you'll find some enhanced shell extensions to run Powershell scripts with elevated privileges. However if you just want to run a Powershell script by double clicking a file, I recommend just calling the Powershell script from a batch script instead of trying to embed Powershell code in the batch script. In the batch script use this: powershell.exe -file "%~dp0MyScript.ps1" where %~dp0 expands to the current directory. This essentially creates a bootstrapper for your Powershell script that you can double click to launch your Powershell script.

Set up PowerShell Script for Automatic Execution

I have a few lines of PowerShell code that I would like to use as an automated script. The way I would like it to be able to work is to be able to call it using one of the following options:
One command line that opens PowerShell, executes script and closes PowerShell (this would be used for a global build-routine)
A file that I can double-click to run the above (I would use this method when manually testing components of my build process)
I have been going through PowerShell documentation online, and although I can find lots of scripts, I have been unable to find instructions on how to do what I need. Thanks for the help.
From http://blogs.msdn.com/b/jaybaz_ms/archive/2007/04/26/powershell-polyglot.aspx
If you're willing to sully your beautiful PowerShell script with a little CMD, you can use a PowerShell-CMD polyglot trick. Save your PowerShell script as a .CMD file, and put this line at the top:
#PowerShell -ExecutionPolicy Bypass -Command Invoke-Expression $('$args=#(^&{$args} %*);'+[String]::Join(';',(Get-Content '%~f0') -notmatch '^^#PowerShell.*EOF$')) & goto :EOF
If you need to support quoted arguments, there's a longer version, which also allows comments. (note the unusual CMD commenting trick of double #).
##:: This prolog allows a PowerShell script to be embedded in a .CMD file.
##:: Any non-PowerShell content must be preceeded by "##"
##setlocal
##set POWERSHELL_BAT_ARGS=%*
##if defined POWERSHELL_BAT_ARGS set POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%
##PowerShell -ExecutionPolicy Bypass -Command Invoke-Expression $('$args=#(^&{$args} %POWERSHELL_BAT_ARGS%);'+[String]::Join(';',$((Get-Content '%~f0') -notmatch '^^##'))) & goto :EOF
Save your script as a .ps1 file and launch it using powershell.exe, like this:
powershell.exe .\foo.ps1
Make sure you specify the full path to the script, and make sure you have set your execution policy level to at least "RemoteSigned" so that unsigned local scripts can be run.
Run Script Automatically From Another Script (e.g. Batch File)
As Matt Hamilton suggested, simply create your PowerShell .ps1 script and call it using:
PowerShell C:\Path\To\YourPowerShellScript.ps1
or if your batch file's working directory is the same directory that the PowerShell script is in, you can use a relative path:
PowerShell .\YourPowerShellScript.ps1
And before this will work you will need to set the PC's Execution Policy, which I show how to do down below.
Run Script Manually Method 1
You can see my blog post for more information, but essentially create your PowerShell .ps1 script file to do what you want, and then create a .cmd batch file in the same directory and use the following for the file's contents:
#ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%MyPowerShellScript.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%'"
Replacing MyPowerShellScript.ps1 on the 3rd line with the file name of your PowerShell script.
This will allow you to simply double click the batch file to run your PowerShell script, and will avoid you having to change your PowerShell Execution Policy.
My blog post also shows how to run the PowerShell script as an admin if that is something you need to do.
Run Script Manually Method 2
Alternatively, if you don't want to create a batch file for each of your PowerShell scripts, you can change the default PowerShell script behavior from Edit to Run, allowing you to double-click your .ps1 files to run them.
There is an additional registry setting that you will want to modify so that you can run scripts whose file path contains spaces. I show how to do both of these things on this blog post.
With this method however, you will first need to set your execution policy to allow scripts to be ran. You only need to do this once per PC and it can be done by running this line in a PowerShell command prompt.
Start-Process PowerShell -ArgumentList 'Set-ExecutionPolicy RemoteSigned -Force' -Verb RunAs
Set-ExecutionPolicy RemoteSigned -Force is the command that actually changes the execution policy; this sets it to RemoteSigned, so you can change that to something else if you need. Also, this line will automatically run PowerShell as an admin for you, which is required in order to change the execution policy.
Source for Matt's answer.
I can get it to run by double-clicking a file by creating a batch file with the following in it:
C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe LocationOfPS1File
you can use this command :
powershell.exe -argument c:\scriptPath\Script.ps1