🍗 Wiki

PowerShell

PowerShell

PowerShell is open source cross-platform shell program that supports powerful commands.

It is installed in Windows by default. But PowerShell is cross platform shell program, so it can be installed in MacOS and Linux. Even though it is different from normal Linux shell like Bash, but you can use most of 'commands' and features of normal Linux Bash shell scripting.

You might be confused, these commands like Get-Content and Select-String are called cmdlets in PowerShell.

1. (Quite) Equivalent command of GNU/Linux tools and commands

Pipes(|), and redirections(>, >>) work as same as *nix commands.

The lines start with PS > indicates that it is taking an inputs from standard input. The rest, without PS > at the beginning of lines, are results of the commands. So, if you’re trying to copy and paste the command, you should aware of the indications.

1.1. cat

Get-Content or gc.

PS > Get-Content flag.txt
flag{You_l34rn_h0w_2_use_PwSH}
PS > gc flag.txt
flag{You_l34rn_h0w_2_use_PwSH}

1.2. touch to create a new empty file

New-Item or ni.

ps > New-Item hello.txt
ps > ni hello.txt

Will do the same.

1.3. touch to update the access and modification times of a file

There is no equivalent command of touch in *nix. You should combine cmdlets to make it.

Get-Date to get current time. Get-ChildItem to get a .NET object of a file.

PS > gci light-me-up.exe

    Directory: /tmp

UnixMode         User Group         LastWriteTime         Size Name
--------         ---- -----         -------------         ---- ----
-rwxr-xr-x    ch1keen ch1keen     2/19/2024 12:01            0 light-me-up.exe

PS > (Get-ChildItem .\light-me-up.exe).LastWriteTime = Get-Date
PS > gci light-me-up.exe

    Directory: /tmp

UnixMode         User Group         LastWriteTime         Size Name
--------         ---- -----         -------------         ---- ----
-rwxr-xr-x    ch1keen ch1keen     2/28/2025 00:03            0 light-me-up.exe

1.4. date

Get-Date

PS > Get-Date
Friday, February 27, 2025 08:42:46 PM

1.5. hexdump or xxd

Format-Hex or fhx

PS > fhx ./flag.txt

   Label: /tmp/flag.txt

          Offset Bytes                                           Ascii
                 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
          ------ ----------------------------------------------- -----
0000000000000000 66 6C 61 67 7B 59 6F 75 5F 6C 33 34 72 6E 5F 68 flag{You_l34rn_h
0000000000000010 30 77 5F 32 5F 75 73 65 5F 50 77 53 48 7D 0A    0w_2_use_PwSH}ďż˝

You can try certutil if you only have to use cmd.exe.

> certutil ./flag.txt

1.6. grep

Select-String

PS > Get-Content ./example.txt
line one
line two
line three
flag{Y0u_0xF0und_th4t!!}
line four
line five
PS > Get-Content ./example.txt | Select-String flag

flag{Y0u_0xF0und_th4t!!}

With -Path option, there is no need to use a pipe (|).

PS > Select-String -Path ./example.txt flag

example.txt:4:flag{Y0u_0xF0und_th4t!!}

With -Pattern option, you can search strings with regular expressions.

1.6.1. grep -r or ripgrep

This is another alternative of grep -r or ripgrep; you should use both Get-ChildItem and Select-String.

PS > Get-ChildItem -Pattern "*.txt" | Select-String -Pattern "secret|s3cr3t"

1.7. head and tail

Select-Object with -First option or -Last option.

Print first five strings:

PS > Get-Content ./example.txt | Select-Object -First 5
line one
line two
line three
line four
line five

Print last five strings:

PS > Get-Content ./example.txt | Select-Object -Last 5
line 76
line 77
line 78
line 79
line 80

You can use -Skip option to skip first several lines:

PS > Get-Content ./example.txt | Select-Object -Skip 5 -First 5
line 6
line 7
line 8
line 9
line 10

1.8. more or less, whatever paginators of output

Pipe to Out-Host -Paging will do that.

PS > Get-Content ./example.txt | Out-Host -Paging
line one
line two
line three
line four
line five
line 6
line 7
<SPACE> next page; <CR> next line; Q quit

It looks like a more command, isn’t it?

1.9. find

Get-ChildItem or gci with -Recurse.

Pass -Include option to search with wild cards.

PS > Get-ChildItem -Recurse -Include '*.sh' -Path /home/ch1keen

1.10. time

Measure-Command.

Pass commands(cmdlets) wrapped with a pair of curly brackets after Measure-Command cmdlet.

PS > Measure-Command { Get-ChildItem -Recurse -Include '*.adoc' | Select-String -Pattern "secret|s3kr3t" }

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 12
Milliseconds      : 967
Ticks             : 129675460
TotalDays         : 0.000150087337962963
TotalHours        : 0.00360209611111111
TotalMinutes      : 0.216125766666667
TotalSeconds      : 12.967546
TotalMilliseconds : 12967.546

It took 12 seconds.

1.11. md5sum, sha1sum…​

Get-FileHash with -Algorithm option.

Unlike md5sum and sha1sum, it is not possible to get input from stdin.

PS > Get-FileHash -Algorithm MD5 ./2.png

Algorithm       Hash
---------       ----
MD5             5BE4563E7DE8A68B57FA5B220DFDC2B8

Default algorithm is SHA256.

> Get-FileHash ./2.png

Algorithm       Hash                                                                   Path
---------       ----                                                                   ----
SHA256          600C27BB71CDA28C324705AD0FF1E63CB4A100FA22212AB98ED45A42249187F2       /tmp/2.png

You can try certutil if you only have to use cmd.exe.

> certutil -Hashfile ./2.png MD5

1.12. Environment Variables

Print all environment variables defined in session:

PS > Get-ChildItem env:*
...
PS > # Short Version
PS > gci env:

Define a variable for a time:

PS > $env:Ch1keen = 'https://github.com/Ch1keen'

Then, get the environment variable by name:

PS > $env:Ch1keen
https://github.com/Ch1keen

You can also modify the PATH variable by appending a string at the end of the variable. It is useful when you don’t want to type the full path of executables.

PS > $env:Path += 'C:\Ch1keen\Temp\Dia\bin;'
PS >

1.13. tree

tree…​ but with /F option. Calling tree without any options will only show (sub)directories.

PS C:\Users\Ch1keen\Downloads\gleam-v1.9.1-x86_64-pc-windows-msvc\hello_world> tree
Folder PATH listing for volume Data
Volume serial number is DEAD-BEEF
C:.
├─.github
│  └─workflows
├─src
└─test
PS C:\Users\Ch1keen\Downloads\gleam-v1.9.1-x86_64-pc-windows-msvc\hello_world> tree /f
Folder PATH listing for volume Data
Volume serial number is DEAD-BEEF
C:.
│  .gitignore
│  gleam.toml
│  manifest.toml
│  README.md
│
├─.github
│  └─workflows
│          test.yml
│
├─src
│      hello_world.gleam
│
└─test
        hello_world_test.gleam

2. Dealing with PowerShell grammar

2.1. …​Wait, how can I get the actual value from the return object?

Since the return value of nearly every cmdlets is an object, you should unpack the object to get the real value. But we don’t have any information about the object, and its type.

You can use Get-Member to get information about the object to see defined properties and methods.

PS > Get-Location | Get-Member

   TypeName: System.Management.Automation.PathInfo

Name         MemberType Definition
----         ---------- ----------
Equals       Method     bool Equals(System.Object obj)
GetHashCode  Method     int GetHashCode()
GetType      Method     type GetType()
ToString     Method     string ToString()
Drive        Property   System.Management.Automation.PSDriveInfo Drive {get;}
Path         Property   string Path {get;}
Provider     Property   System.Management.Automation.ProviderInfo Provider {get;}
ProviderPath Property   string ProviderPath {get;}

2.2. …​How many items in the returned objects?

You can get numbers of returned values by chaining Measure and Select-Object -Property count cmdlets.

PS > Select-String -Pattern 'a...e' -Path .\eft.txt

eft.txt:1:abcde
eft.txt:2:abbbe
eft.txt:6:affde
eft.txt:7:aefee
eft.txt:8:afhhe

PS > Select-String -Pattern 'a...e' -Path .\eft.txt | Measure | Select-Object -Property count

Count
-----
    5

3. Obfuscation of Script

PowerShell is case insensitive. Despite the commands above are all capitalized, You can get same results if you do not capitalize it.

5. See Also