Powershell

Tips and Tricks

Updated: 02 October 2023

Modify Prompt

Based on this

Open Powershell and type

Terminal window
1
notepad $profile

If the file does not exist you will be asked to create it, then paste the following

Terminal window
1
function prompt {
2
$p = Split-Path -leaf -path (Get-Location)
3
"$p > "
4
}

You can replace the $p > part with anything you’d like to be displayed in your shell

Alternatively, if you would like to see the full path, and the command on the next line you can use

Terminal window
1
function prompt {
2
$p = Get-Location
3
"$p
4
>"
5
}

Adding Aliases

Based on this

We can add persistent aliases in our profile by defining functions for them, we can open our Powershell Profile

Terminal window
1
notepad $profile

Then we can define a function to navigate to our Repo directory by adding the following to the profile

Terminal window
1
function repo {
2
set-location c:\Users\NabeelValley\Documents\DevEx\Repos
3
}

View File Tree

You can view the folder and file tree in powershell using the tree command.

To view the Folders only in the current directory:

Terminal window
1
tree

Which will output something like:

1
C:.
2
└───main

Or from another directory you can use:

Terminal window
1
tree ./path/to/dir

To refer to the current directory you can use tree without any directory, or tree . to refer to the current directory. Both ways are almost identical in terms of the output. Note that including the directory in the command results in the full directory path being written in the command’s output

And to view the tree with files included, you can use:

Terminal window
1
tree /f

Which will output something like:

1
C:.
2
└───main
3
data.txt

And for another directory:

Terminal window
1
tree ./path/to/dir /f

Symlinks

Support for mklink only exists on newer versions of Windows, otherwise you may need to use New-Item

Creating symlinks can be done with the mklink command which is an alias for the New-Item -ItemType SymbolicLink command

Using the base New-Item version, a symlink can be created with the below command where data.txt is the linked file we want to create and `./main/data.txt/ is the path to the existing file:

Terminal window
1
New-Item -ItemType SymbolicLink -Name data.txt -Target ./main/data.txt

Which creates a file called data.txt which is linked to ./main/data.txt

The mklink version of this is:

Terminal window
1
mklink data.txt ./main/data.txt

For more info see [this page](https://superuser.com/questions/1307360/how-do-you-create-a-new-symlink-in-windows-10-using-powershell-not-mklink-exe_

Git Status for Sub-Directories

Check which folders have modified files (only goes one level deep)

Terminal window
1
$notGit = "`nNot Git Repositories"
2
Get-ChildItem -Directory | ForEach-Object {
3
Set-Location $($_.Name);
4
$status = (git status) 2>&1
5
if ($status -like "*fatal*") {
6
$notGit += "`n-$($_.Name)"
7
}
8
else {
9
Write-Host "$($_.Name)" -ForegroundColor yellow;
10
}
11
if ($status -like "*nothing to commit*") {
12
Write-Host " All Good" -ForegroundColor green;
13
}
14
if ($status -like "*Changes to be committed*") {
15
Write-Host " Uncomitted Files" -ForegroundColor DarkRed;
16
}
17
if ($status -like "*modified*") {
18
Write-Host " Modified Files" -ForegroundColor DarkMagenta;
19
}
20
if ($status -like "*Untracked*") {
21
Write-Host " Untracked Files" -ForegroundColor Red;
22
}
23
if ($status -like "*pull*") {
24
Write-Host " Behind Origin" -ForegroundColor DarkGreen;
25
}
26
Set-Location ..
27
}
28
29
Write-Host $notGit;

Zip and Unzip a File

Terminal window
1
Compress-Archive .\DirectoryToZip .\NewFileName.zip
2
Expand-Archive .\FileToUnzip.zip .\DestinationDirectoryName

Copy and Paste Files

Copy the current directory with:

Terminal window
1
Get-ChildItem * | Set-Clipboard

Copy a single file with:

Terminal window
1
Get-Item '.\FileToCopy.png' | Set-Clipboard

Paste Item with:

Terminal window
1
Get-Clipboard -Format FileDropList | Copy-Item

Send an Email

From this StackOverflow Answer

Terminal window
1
Function Send-EMail {
2
Param (
3
[Parameter(`
4
Mandatory=$true)]
5
[String]$EmailTo,
6
[Parameter(`
7
Mandatory=$true)]
8
[String]$Subject,
9
[Parameter(`
10
Mandatory=$true)]
11
[String]$Body,
12
[Parameter(`
13
Mandatory=$true)]
14
[String]$EmailFrom="myself@gmail.com", #This gives a default value to the $EmailFrom command
15
[Parameter(`
16
mandatory=$false)]
17
[String]$attachment,
18
[Parameter(`
19
mandatory=$true)]
20
[String]$Password
21
)
22
23
$SMTPServer = "smtp.gmail.com"
24
$SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
25
if ($attachment -ne $null) {
26
$SMTPattachment = New-Object System.Net.Mail.Attachment($attachment)
27
$SMTPMessage.Attachments.Add($SMTPattachment)
28
}
29
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
30
$SMTPClient.EnableSsl = $true
31
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($EmailFrom.Split("@")[0], $Password);
32
$SMTPClient.Send($SMTPMessage)
33
Remove-Variable -Name SMTPClient
34
Remove-Variable -Name Password
35
36
}

Troubleshooting Path Commands

If a command is not running the application/version of the application you’d expect you can try the following steps:

  1. Refresh your path and try the command again, it may just not be up-to-date. You can use the following function to do that:
Terminal window
1
function refresh {
2
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
3
}
  1. If you command is just generally being weird in some way it may be because it is defined/part of another path than the one you expect

To see where a command is being run from, you can try the following:

Terminal window
1
Get-Command <command>

e.g. for node:

Terminal window
1
Get-Command node

e.g my node command was being problematic because it was running the one in my Anaconda path entry (because apparently Anaconda comes with Node)

  1. In order to ensure that the correct application/command takes precedence move it higher up your path

Create Drive Aliases

On Windows you can alias specific folders as virtual drives (for easy reference or to get around file length restrictions)

To view your aliases/drives you can run:

1
> subst
2
R:\: => C:\repos

To create a new drive you can use:

1
> subst X: C:\path\to\folder

Where X is the drive you would like to map to. Be sure not to have the trailing \ in your folder name

The path to the folder can also be relative: .\my\rel\path

To remove a drive run the following command:

1
> subst R: /D

What Process is Using a Port

To view what process is using a specific port you can run the following command:

Terminal window
1
Get-Process -Id (Get-NetTCPConnection -LocalPort 5000).OwningProcess

You can also use the following command:

Terminal window
1
netstat -ano | findstr : 8000

Killing Process by ID

If you have the PID, for example using one of the above commands, you can kill us using taskkill, for example for killing PID 1234

Terminal window
1
taskkill /PID 1234 /F

Zipping Files

To zip all the files in a directory you can use the following:

Terminal window
1
Compress-Archive -Path ./* -DestinationPath ./output_file.zip

To zip a directory, including the root directory in the Zip use the following:

Terminal window
1
Compress-Archive -Path ./dir_to_zip -DestinationPath Compress-Archive -Path ./* -DestinationPath ./output_file.zip

Search for Devices on Network

To view the IP’s of the different devices that are currently connected to your network you can use the following command:

Terminal window
1
arp -a

Connect to RDP

To use an RDP file you can make use of the mstsc command with a path to the RDP file you want to connec with:

Terminal window
1
mstsc ./my-cool-server.rdp

Which will then open the RDP file

Switch to Home Directory

You can switch to your home directory on Powershell with cd ~, the ~ directory represents the user’s home, same as in other OS’s and shells

My Current $PROFILE

Yout Powershell is a script that runs whenever you open a new powershell instance, the functions available in it become part of your session so you can just call them from the terminal. The path to this file is stored in every Powershell instance as the $PROFILE variable

To open your $PROFILE in notepad you can run:

Terminal window
1
notepad $PROFILE

My current profile which has some common commands is here:

Terminal window
1
# POWERSHELL CONFIGURATION FUNCTIONS
2
# ==================================
3
# THESE ARE CALLED BY POWERSHELL ITSELF
4
5
# SETS CUSTOM PROMPT, THIS FUNCTION GETS CALLED ON PS SETUP
6
function prompt {
7
$p = Get-Location
8
"$p
9
!"
10
}
11
12
# ENVIRONMENT FUNCTIONS
13
# =====================
14
# CONFIGURE ENVIRONMENT
15
16
# REFRESH SESSION ENVIRONMENT VARIABLES
17
function _refresh {
18
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
19
}
20
21
# GENERAL UTILITIES
22
# =================
23
24
# NAVIGATION
25
# ^^^^^^^^^^
26
27
# CD TO MY REPOSITORIES
28
function _repo {
29
Set-Location c:\repos
30
}
31
32
# CD TO MY DOCS
33
function _docs {
34
Set-Location C:\repos\PersonalSite\static\content\docs
35
}
36
37
# GIT
38
# ^^^
39
40
# MERGE GIT "DEVELOP" TO "MASTER"
41
function _quickmerge {
42
git push
43
git checkout master
44
git merge develop
45
git push
46
git checkout develop
47
}
48
49
# COMMIT ALL SUBMODULE'S FILES AND RUN SAME COMMIT ON PARENT REPO
50
# FOR THE UPDATED SUBMODULE. RUN FROM SUBMODULE DIRECOTRY
51
function _updatesub {
52
param(
53
[string]$commitMessage
54
)
55
56
$submoduleFolder = Split-Path (Get-Location) -Leaf
57
58
git add .
59
git commit -m $commitMessage
60
git push
61
cd ..
62
git add $submoduleFolder
63
git commit -m $commitMessage
64
git push
65
cd $submoduleFolder
66
}
67
68
# FILE MANIPULATION
69
# ^^^^^^^^^^^^^^^^^
70
71
# COPY SOMETHING TO YOUR CLIPBOARD
72
function _copy {
73
param(
74
[string]$fileToCopy
75
)
76
77
Get-Item $fileToCopy | Set-Clipboard
78
}
79
80
# PASTE WHAT'S ON YOUR CLIPBOARD
81
function _paste {
82
Get-Clipboard -Format FileDropList | Copy-Item
83
}
84
85
# RENAME A FILE
86
function _rename {
87
param(
88
[string]$currentFile,
89
[string]$newName
90
)
91
92
Rename-Item -Path $currentFile $newName
93
}
94
95
# COPY AND RENAME FILE
96
function _dupe {
97
param(
98
[string]$currentFile,
99
[string]$newName
100
)
101
$tempDir = ".temp_nvdupe"
102
103
nvcopy $currentFile
104
mkdir $tempDir
105
cd $tempDir
106
nvpaste
107
nvrename $currentFile $newName
108
nvcopy $newName
109
cd ..
110
nvpaste
111
rm -r $tempDir
112
}