Execute shortcuts like programs - powershell

Example: You have a shortcut s to SomeProgram in the current directory.
In cmd.exe, you can type s and it will launch the program.
In PowerShell, typing s gives:
The term 's' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and try again.
If you type s.lnk or SomeProgram, it runs the program just fine.
How can I configure PowerShell to execute shortcuts just like programs?

You can also invoke a shortcut by using the "invoke-item" cmdlet. So for example if you wanted to launch "internet explorer.lnk" you can type the following command:
invoke-item 'Internet Explorer.lnk'
Or you could also use the alias
ii 'internet explorer.lnk'
Another cool thing is that you could do "invoke-item t.txt" and it would automatically open whatever the default handler for *.txt files were, such as notepad.
Note If you want to execute an application, app.exe, in the current directory you have to actually specify the path, relative or absolute, to execute. ".\app.exe" is what you would need to type to execute the application.

On my Vista system typing S won't launch a lnk file unless I have the environment variable PATHEXT set with .lnk in the list. When I do. S will work in cmd.exe and I have to do .\S in powershell.

After adding ;.LNK to the end of my PATHEXT environment variable, I can now execute shortcuts even without the preceding ./ notation. (Thanks bruceatk!)
I was also inspired by Steven's suggestion to create a little script that automatically aliases all the shortcuts in my PATH (even though I plan to stick with the simpler solution ;).
$env:path.Split( ';' ) |
Get-ChildItem -filter *.lnk |
select #{ Name='Path'; Expression={ $_.FullName } },
#{ Name='Name'; Expression={ [IO.Path]::GetFileNameWithoutExtension( $_.Name ) } } |
where { -not (Get-Alias $_.Name -ea 0) } |
foreach { Set-Alias $_.Name $_.Path }

I don't believe you can. You might be better off aliasing commonly used commands in a script that you call from your profile script.
Example -
Set-Alias np c:\windows\notepad.exe
Then you have your short, easily typeable name available from the command line.

For one, the shortcut is not "s" it is "s.lnk". E.g. you are not able to open a text file (say with notepad) by typing "t" when the name is "t.txt" :) Technet says
The PATHEXT environment variable
defines the list of file extensions
checked by Windows NT when searching
for an executable file. The default value of PATHEXT is .COM;.EXE;.BAT;.CMD
You can dot-source as described by others here, or you could also use the invocation character "&". This means that PS treats your string as something to execute rather than just text. This might be more important in a script though.
I'd add that you should pass any parameters OUTSIDE of the quotes (this one bit me before) note that the "-r" is not in the quoted string, only the exe.
& "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe" -r | out-null

You can always use tab completion to type "s[TAB]" and press ENTER and that will execute it.

Related

Change the default "Edit" action for .ps1 from ISE to VS Code

Like the person in this question, it is frustrating that such obvious things have no clear answers (I've looked at 20 pages and found nothing yet).
The default right-click "Edit" action in Windows for .ps1 files is to open with PowerShell_ISE. ISE is an ancient and bloated relic of a bygone age, and incredibly slow to open, so when you accidently do right-click > Edit, it is tortuous watching ISE slowly open.
How can we programmatically alter the default "Edit" action for .ps1 / .psm1 etc such that they will point to VS Code instead of ISE?
Alternatively, if we can't alter it, can we completely remove it (so that "Edit with VS Code" is the only option left)?
This is actually pretty easy to do in PowerShell, or by tweaking the registry by hand.
Here's a script that will change things over.
Because you're going to be changing HKEY_CLASSES_ROOT, you're going to need to be running as administrator:
# This a "provider qualified" path to the edit command
$editRegistryPath = 'Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\SystemFileAssociations\.ps1\Shell\Edit\Command'
# This is how we will get the default value
$defaultEdit = Get-ItemProperty $editRegistryPath -Name '(default)'
# If we couldn't get it, something's wrong, so return
if (-not $defaultEdit) {
return
}
# Get the path to code.cmd (this must be in $env:PATH)
$codePath = Get-Command code -CommandType Application | Select-Object -First 1 | Select-Object -ExpandProperty Source
# Change the property. Make sure we quote our command name and our arguments.
Set-ItemProperty -Path $editRegistryPath -Name '(default)' -Value "`"$($codePath)`" `"%1`""
You simply need to change the exe path to vs code in the following registry key
Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\.ps1\Shell\Edit\Command
Double click the default property and replace the ISE path with the path to your vscode.exe

How to save function in powershell?

Hi so i've tried to make my first function. A simple one that will restart powershell in windows terminal. And it's working.
function Restart-PowerShell{
Get-Process -Id $PID | Select-Object -ExpandProperty Path | ForEach-Object { Invoke-Command { & "$_" } -NoNewScope }
But when i restart powershell the function disappear, it doesn't save it. How can i save it? I've tried to look around but couldn't find any way to save
You save PowerShell functions by simply putting their definition in a file on disk:
"function Restart-PowerShell {${function:Restart-PowerShell}}" |Set-Content Restart-PowerShell.ps1
This will write it to a file Restart-PowerShell.ps1 in the current directory.
Next time you need to re-use your function, it's as simple as dot-sourcing the file:
PS ~> . .\path\to\Restart-PowerShell.ps1
PS ~> Restart-PowerShell # now the function is available in the current session
Mathias R. Jessen's helpful answer shows how to save your function's definition to a custom file that you can dot-source on demand in future sessions.
However, there is a file that is dot-sourced automatically when a PowerShell session starts (unless explicitly suppressed with -NoProfile via the PowerShell CLI): your $PROFILE file, and that's where customizations of your sessions - such as custom functions and aliases - are typically stored.
Therefore, if you add your function to your $PROFILE file, it automatically becomes available in future sessions too.
You can open $PROFILE in your text editor or, building on Mathias' technique, add the function programmatically, as follows, which ensures on-demand creation of the file and its parent directory (on a pristine machine, neither exists):
# Make sure the $PROFILE file exists.
If (-not (Test-Path $PROFILE)) { $null = New-Item -Force $PROFILE }
# Append the function definition to it.
#"
function Restart-PowerShell {
${function:Restart-PowerShell}
}
"# | Add-Content $PROFILE
Note: To reload your profile mid-session after having modified $PROFILE, use . $PROFILE.

Alternatives to invoke-expression

I have this function:
function traced()
{
write-host "$args"
invoke-expression -Command "$args"
}
and I use it in several places like traced cp "$($_.FullName)" (join-path $directory $newfile) so that I have a log of all of the places that get copied (or removed, or whatever)
But when the directory contains spaces and dashes, it results in invoke-expression throwing.
I guess I could just define traced-cp and traced-rm, but if I have a lot of functions I want to trace, what's the generic answer? I just want a function that prints, then evaluates, the exact command its given. From what I understand, the & operator isn't what I want here-- It won't work for shell builtins.
[...] so that I have a log of all of the places that get copied (or removed, or whatever)
I'd strongly recommend you use transcript logging for this!
You can start a transcript interactively with the Start-Transcript cmdlet, but if you want to keep a transcript of every single instance of PowerShell you launch by default, I'd suggest turning it on by default!
Open the local policy editor (gpedit.msc) on your Windows box and navigate to:
Computer Configuration
> Administrative Templates
> Windows Components
> Windows PowerShell
Select the policy setting named "Turn on PowerShell Transcription", set it to Enabled, and optionally configure your preferred output directory (defaults to your home folder).
This way, you'll always have a full transcript of your interactions in PowerShell :)
Consider using argument splatting to build your command instead of building a string-based command with Invoke-Expression. I also don't know where you heard that & doesn't work with shell built-ins but it works with both commands and cmdlets.
Here is the official Microsoft documentation on splatting in Powershell.
This approach also eliminates the difficulty in crafting a command string correctly, having to escape characters, and dealing with path spaces - using splatting with named or positional arguments takes care of most of this for you.
I would suggest using -verbose with copy-item or remove-item, and also -passthru with copy-item.

How do I call a DOSkey Alias from Powershell?

I have DOSKey Alias that I setup like so (Aliases in Windows command prompt) calling it from the registry, and I'd like to be able to run it from powershell; is there some way to do this? All it really does is add something to the %PATH% environment variable.
If you don't have to use DOSKey and would just like to alias a command, you can use the built-in Set-Alias command like so:
Set-Alias -Name np -Value notepad++
That will, while the current powershell window is open, alias np to notepad++. Which also lets you open files with np temp.txt.
If you'd like to persist that, you could add it to your profile. You can do that by editing your Microsoft.PowerShell_profile.ps1, a shorthand is:
notepad $profile
Feel free to use notepad++ or any other editor you might have in your PATH. You can add the Set-Alias line to the bottom of the file and save and close it.
When you then open another powershell instance, it will have the example np alias available.
Below is code that will copy your DOSKEY macros into PowerShell aliases. This might or might not make sense for some commands which already have PowerShell aliases or do not work in the same way in PowerShell.
Note that you must source the command into the current shell.
PS C:\src\t> type .\Get-DoskeyMacros.ps1
& doskey /MACROS |
ForEach-Object {
if ($_ -match '(.*)=(.*)') {
Set-Alias -Name $Matches[1] -Value $Matches[2]
}
}
PS C:\src\t> . .\Get-DoskeyMacros.ps1
NOTES: (ht mklement0)
This code presumes that the doskey aliases have already been defined, which is not likely in a normal PowerShell session. However, you can start the PowerShell session from a cmd session that has them defined or run a batch file from PowerShell that defines them.
A potential translation-to-alias problem is that doskey macros support parameters (e.g., $*), whereas PowerShell aliases do not.
#lit's script didn't work for me.
Below is a script that worked. It copies the generated Set-Alias commands to the $profile script.
doskey /MACROS |
ForEach-Object {
if ($_ -match '(.*)=(.*)') {
echo ('Set-Alias -Name '+$Matches[1]+' -Value '+$Matches[2])
}
} > $profile
Notes:
Like the original script, this must be executed in a PowerShell session started from a cmd session.
The $profile file didn't exist for me. I first had to create it, along with the containing folder.

Trying to view the contents of a text file in powershell. Getting "more.com" is not recognized as the name of a cmdlet

I'm using this tutorial. The exercises shows the basic use of less and more.
Except from link
> more ex12.txt
[displays file here]
>
When i try to use the 'more' command, i get the error:
the term 'more.com' is not recognized as the name of a cmdlet,
functoin, 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.
I'm not sure what is going on and would appreciate any help!
There must be something wrong with your PC's configuration because more.com should work just fine in PowerShell e.g.:
PS C:\> more.com .\foo.ini
foo=this is foo section
bar=this is the bar section
In fact, PowerShell does use more.com. Take a look at the definition of the more function (which the help function pipes into). In the more function you will see these two lines:
Get-Content $file | more.com
...
$input | more.com
So when you execute "more" you are executing a PowerShell function that invokes more.com. Have you tried more.com ex12.txt?
Also, more.com comes in 32-bit and 64-bit flavors:
PS C:\> Get-PEHeader c:\windows\system32\more.com
Type : PE64
LinkerVersion : 11.0
Get-PEHeader is from PSCX.
powershell doesn't use more.com, it's a 16 bit binary which I believe is no longer included in x64 based windows. on 32bit yes we may find one. However in powershell you can pipe the output to out-file -paging cmdlet and it should do the job
get-content .\pylongcode.py | out-host -Paging
You probably need to set your path variable.
to check the path variable you can type PS>> echo $env:path
If you do not see a very long string of C:\Windows.... separated by ";" that is a problem I would recommend you resolve with MS support if you are not able to get help from here or your computer manufacturer.
A simple way to set your path is
PS>> ${NewFileName.txt} = $env:path
PS>> NewFileName.txt
File should open in notepad add new paths
[notepad] C:\WINDOWS\system32;C:\WINDOWS;
Save
PS>> $env:path = ${NewFileName.txt}
PS>> $env:path
Double Check that the path now has the contents of that file. You can then delete the file as it is only used to aid in editing the path variable. There are other ways to do this I prefer this way because I prefer using a text editor for editing over a terminal. Having those two entries will get less and more working.