PowerShell alias syntax for running a cmd.exe builtin function? - powershell

As I have only recently switched to PowerShell from cmd.exe, I often find it convenient to do little things in a familiar way by calling cmd to do them. For instance, to do a 'bare' file listing this works great:
PS> cmd /c dir /b
dir1
dir2
file1.txt
I'd like to make an alias for this but I can't figure out the right syntax. So far I've tried:
PS> Set-Alias dirb cmd /c dir /b # error (alias not created)
PS> Set-Alias dirb "cmd /c dir /b" # fail (alias doesn't work)
PS> Set-Alias dirb "cmd `"/c dir /b`"" # fail (alias doesn't work)
Any suggestions? I'm looking for a general solution to calling builtin cmd.exe commands (such as dir). I'd also like to know how to produce bare output the right way using PowerShell cmdlets, but that's a secondary concern at the moment. This question is about the proper syntax for calling cmd.exe from an alias.

I believe what you want is a function, not an alias. For instance:
function dirb {
cmd /c dir $args[0] /b
}
From a PS prompt, run notepad $profile, paste that into your profile and then it will load automatically when you open a PS console and you can do this:
dirb c:\somedir
See get-help about_functions for more information about functions.

Aliases are not designed for this kind of tasks. An alias is just another name of a command. Use the function instead.
function dirb { cmd /c dir /b }

Aliases in powershell don't take parameters unfortunately - you need to define a function for this. For more info,
get-help aliases

Why on earth would you use powershell to open the command prompt? That seems to be defeating the purpose.
The Alias I prefer to list out files is simply ls

Related

Trying to run a headless executable command through Powershell that works on cmd line

I am trying to run an executable through powershell to run headless, to install a program onto a VM/LocalHost machine. I can get the wizard to open, but for whatever reason I cannot get it to run headless. Here is the cmd line that I run that works:
start /WAIT setup.exe /clone_wait /S /v" /qn"
This is my attempts in powershell
Start-Process .\setup.exe /S -Wait -PassThru
Start-Process .\setup.exe /S /v /qn -Wait -PassThru
Start-Process setup.exe -ArgumentList '/clone_wait /S /v /qn' -Wait
In the cmd line instance the application installs without issue - in the powershell instance the wizard opens and is on the first "Next" prompt. Any help would be appreciated!
I also attempted to add the additional parameters "/v" and "/qn" which return an error : Start-Process : A positional parameter cannot be found that accepts argument '/v'
The bottom attempt runs but it's not waiting for the installation to complete
You may be overthinking it. Remember that PowerShell is a shell. One of the purposes of a shell is to run commands that you type.
Thus: You don't need Start-Process. Just type the command to run and press Enter.
PS C:\> .\setup.exe /clone_wait /S /v /qn
Now if the executable (or script) you want to run contains spaces in the path or name, then use the call/invocation operator (&) and specify the quotes; for example:
PS C:\> & "\package files\setup.exe" /clone_wait /S /v /qn
(This behavior is the same no matter whether you are at the PowerShell prompt or if you put the command in a script.)
This worked for me. You need to quote the whole argumentlist, plus embed double quotes to pass what you want to /v.
start-process -wait SetupStata16.exe -ArgumentList '/s /v"/qb ADDLOCAL=core,StataMP64"'
Running the command normally and then using wait-process after might be a simpler alternative, if you're sure there's only one process with that name:
notepad
wait-process notepad
To follow-up to all that you have been given thus far. Running executables via PowerShell is a well-documented use case.
PowerShell: Running Executables
Solve Problems with External Command Lines in PowerShell
Top 5 tips for running external commands in Powershell
Using Windows PowerShell to run old command-line tools (and their
weirdest parameters)
So, from the first link provides more validation of what you've been given.
5. The Call Operator &
Why: Used to treat a string as a SINGLE command. Useful for dealing with spaces.
In PowerShell V2.0, if you are running 7z.exe (7-Zip.exe) or another command that starts with a number, you have to use the command invocation operator &.
The PowerShell V3.0 parser do it now smarter, in this case you don’t need the & anymore.
Details: Runs a command, script, or script block. The call operator, also known as the "invocation operator," lets you run commands that are stored in variables and represented by strings. Because the call operator does not parse the command, it cannot interpret command parameters
Example:
& 'C:\Program Files\Windows Media Player\wmplayer.exe' "c:\videos\my home video.avi" /fullscreen
Things can get tricky when an external command has a lot of parameters or there are spaces in the arguments or paths!
With spaces you have to nest Quotation marks and the result it is not always clear!
In this case it is better to separate everything like so:
$CMD = 'SuperApp.exe'
$arg1 = 'filename1'
$arg2 = '-someswitch'
$arg3 = 'C:\documents and settings\user\desktop\some other file.txt'
$arg4 = '-yetanotherswitch'
& $CMD $arg1 $arg2 $arg3 $arg4
# or same like that:
$AllArgs = #('filename1', '-someswitch', 'C:\documents and settings\user\desktop\some other file.txt', '-yetanotherswitch')
& 'SuperApp.exe' $AllArgs
6. cmd /c - Using the old cmd shell
** This method should no longer be used with V3
Why: Bypasses PowerShell and runs the command from a cmd shell. Often times used with a DIR which runs faster in the cmd shell than in PowerShell (NOTE: This was an issue with PowerShell v2 and its use of .Net 2.0, this is not an issue with V3).
Details: Opens a CMD prompt from within powershell and then executes the command and returns the text of that command. The /c tells CMD that it should terminate after the command has completed. There is little to no reason to use this with V3.
Example:
#runs DIR from a cmd shell, DIR in PowerShell is an alias to GCI. This will return the directory listing as a string but returns much faster than a GCI
cmd /c dir c:\windows
7. Start-Process (start/saps)
Why: Starts a process and returns the .Net process object Jump if -PassThru is provided. It also allows you to control the environment in which the process is started (user profile, output redirection etc). You can also use the Verb parameter (right click on a file, that list of actions) so that you can, for example, play a wav file.
Details: Executes a program returning the process object of the application. Allows you to control the action on a file (verb mentioned above) and control the environment in which the app is run. You also have the ability to wait on the process to end. You can also subscribe to the processes Exited event.
Example:
#starts a process, waits for it to finish and then checks the exit code.
$p = Start-Process ping -ArgumentList "invalidhost" -wait -NoNewWindow -PassThru
$p.HasExited
$p.ExitCode
#to find available Verbs use the following code.
$startExe = new-object System.Diagnostics.ProcessStartInfo -args PowerShell.exe
$startExe.verbs

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

How to call msys2 find command from PowerShell with correct shell escape characters?

I'm wondering how can I escape the following command from PowerShell so that it works?
PS C:\Users\buster\Documents\> find -name \*.c
PowerShell says: error not found *.c
PS C:\Users\buster\Documents\> find -name *.c
PowerShell says: error not found *.c
If you used find like that (without the full path) you most likely used the find.exe that ships with Windows (C:\Windows\system32\find.exe), which is more akin to grep than to Unix find. You get that behavior because Windows searches all directories in $env:PATH for files with the given name (and one of the extensions listed in $env:PATHEXT if no extension was specified), and executes the first match. Since %windir%\system32 is usually at the beginning of the PATH, executables from there take precedence.
You could add C:\msys64\msys64\usr\bin to the beginning of the PATH (before %windir%\system32), although I wouldn't recommend that. A better way would be to define an alias for the command:
New-Alias -Name 'find' -Value 'C:\msys64\msys64\usr\bin\find.exe'
Aliases take precedence over files. You could put the alias definition in your PowerShell profile so that it's automatically loaded whenever you start PowerShell.
Or you could simply use ls -r -fi '*.c' (short for Get-ChildItem -Recurse -Filter '*.c'), which would be the PowerShell way.
Ok false alarm..
Apparently its a case of windows having an executable with the same name as msys2's find.exe under c:\windows\system32 and the windows command getting higher priority in the path list. After explicitly typing out the full path to the msys64 version of find.exe it works.
PS C:\Users\buster\Documents\> C:\msys64\msys64\usr\bin\find -name \*.c
Also, Turns out there's a better way to find *.c files native to cmd.exe that you can call from powershell like this:
PS C:\Users\buster\Documents\> cmd /c dir /S /B *.v

How can I detect whether or not I am in powershell from a command line?

I am creating a standard windows BAT/CMD file and I want to make an IF statement to check whether or not this CMD file is run from PowerShell. How can I do that?
Edit: My underlying problem was that test.cmd "A=B" results in %1==A=B when run from CMD but %1==A and %2==B when run from PowerShell. The script itself is actually run as an old Windows Command line script in both cases, so checking for Get-ChildItem will always yield an error.
One way, it to see what your process name is, and then check its attributes:
title=test
tasklist /v /fo csv | findstr /i "test"
As long as you use a unique name in place of Test, there should be little room for error.
You will get back something like:
"cmd.exe","15144","Console","1","3,284
K","Running","GNCID6101\Athomsfere","0:00:00","test"
When I ran the above code from a bat file, my output was:
"powershell.exe","7396","Console","1","50,972
K","Running","GNCID6101\Athomsfere","0:00:00","
A potentially simpler approach that may work for you. If not, it may be suitable for others.
Create 2 separate script files: test.ps1 and test.cmd
Don't include extension when calling the script. I.e. call as <path>\test (or just test if folder is in the path environment variable.
This works because CMD prioritises which script to execute as: .bat > .cmd, whereas Powershell prioritises: .ps1 > .bat > .cmd.
The following is the output of a CMD session:
C:\Temp>copy con test.cmd
#echo cmd^Z
1 file(s) copied.
C:\Temp>copy con test.ps1
Write-Output "ps1"^Z
1 file(s) copied.
C:\Temp>.\test
cmd
C:\Temp>
And calling test from Powershell:
PS C:\Temp> .\test
ps1
PS C:\Temp>
Couldn't you try to execute a Get-ChildItem and then check %ERRORLEVEL% to see if it returns an exe not found?
http://ss64.com/nt/errorlevel.html

Trouble creating symlink with semicolon in it from powershell

So i normally use this syntax to create as symbolic link from powershell.
PS C:\> cmd /c mklink LinkName TargetFolder
However there I'm getting this error when I'm trying to create a symlink with a
semicolon in it.
PS C:\> cmd /c mklink "link;name" "C:\Folder\file;name"
The syntax of the command is incorrect.
If I call it from the cmd application it works fine
C:\>mklink "link;name" "C:\Folder\file;name"
symbolic link created for link;name <<===>> C:\Folder\file;name
Echo args also seems to be working fine when called from cmd via powershell
PS C:\> cmd /c echoargs "link;name" "C:\Folder\file;name"
Arg 0 is <link;name>
Arg 1 is <C:\Folder\file;name>
So why am I not able to create that symlink from powershell. That syntax works with every other legal character, even unicode. Any help would be much appreciated.
Try this:
cmd /c 'mklink "link;name" "C:\Folder\file;name"'