Files
vim-ale/pwsh-essentials/README.md

222 lines
5.2 KiB
Markdown

---
title: pwsh-essentials
homepage: https://webinstall.dev/pwsh-essentials
tagline: |
meta package for our recommended PowerShell plugins and settings
---
To update (replacing the current version) run `webi pwsh-essentials`.
## Cheat Sheet
> The tools you need to write PowerShell effectively.
This meta package will install the full set of plugins and settings we
recommended.
## Table of Contents
- Files
- Mostly Case-Insensitive
- Returns vs Pipeline Streams
- Strict, Trace, & Verbose Modes
- The Call Operator "&"
- curl vs curl.exe
- Script Policies & Preferences
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/pwsh-fix.ps1
~/.local/bin/pwsh-fmt.ps1
~/.local/bin/pwsh-lint.ps1
~/.local/opt/pwsh/
~/.local/share/powershell/Modules/PSScriptAnalyzer/
```
### Things You MUST Know
There are a few key differences to PowerShell from other scripting and
programming languages you may have used in the past.
Knowing these from the start can save you a _tonne_ of headache.
### 0. PowerShell is Case-Insenstive, Usually
Function and Commandlet names, file paths, and boolean operators are all
case-insensitive:
```pwsh
write-host "Hello, World!"
WRITE-HOST "Hello, World!"
Write-Host "HELLO, WORLD!" -eq "hello, world!"
# True
```
However, raw string and byte functions are case sensitive unless
'CurrentCultureIgnoreCase' is used:
```pwsh
"https://webi.sh".StartsWith("HTTPS://")
# False
"https://webi.sh".StartsWith("HTTPS://", 'CurrentCultureIgnoreCase')
# True
```
### 1. PowerShell Doesn't Have Return Values
There's not so much concept of a "return" as a "pipeline stream".
All values which are not assigned to a variable, such as `$Foobar` - or
`$null` - are pipelined.
- There are no _Return Values_
- The `Return` keyword only serves to exit early.
- The result of EVERY command is put into a _Pipeline_
- You can pick which _Pipeline_ a result is written to:
- `... | Write-Output` (the default)
- `... | Write-Debug`
- `... | Write-Verbose`
- `... | Write-Information`
- `... | Write-Warning`
- `... | Write-Error`
- `... | Write-Host` (forced console output, no Pipeline) \
(also, [considered "evil"](https://stackoverflow.com/a/38527767/151312))
- Results captured with a variable DO NOT enter a pipeline
- `$Foobar = ...` (captured to variable, no Pipeline)
- `$null = ...` (no Pipleline) \
(the same as `... | Out-Null`, but easier to read and _much_ faster)
#### Example
```pwsh
function Get-LotsInThePipeline ($Thing1, $Thing2) {
Write-Output "a"
1
IF ($Thing) {
$null = Write-Output "b"
$null = 2
$Thing2
Return
}
Write-Output "c"
3
}
Get-LotsInThePipeline $true 'red'
Get-LotsInThePipeline $false 'blue'
```
There are two possible outputs for this program:
```text
a, 1, "red"
a, 1, c, 3
```
When you need a limited set of pipeline values, you'll need to `$null = xxxx`...
a lot.
See <https://stackoverflow.com/q/29556437/151312>
### 2. Strict, Trace, & Verbose Modes
```pwsh
# set -e
$ErrorActionPreference = "Stop"
# set -x
Set-PSDebug -Trace 2
# DEBUG='true'
$VerbosePreference="Continue"
# if test -n "$DEBUG"; then echo "Debug 123"; fi
Write-Verbose "Debug: 123"
```
### 3. The Call Operator (`&`)
Normally you can run a command the same as a commandlet:
```pwsh
# Built-in Commandlet
Write-Host "Unpacking the tarball..."
# External Command
tar xvf foobar.tar.gz
```
However, if the command is any of:
- a script (particular that will **change its parent's variables**)
- accessed directly by it's path (i.e. it's not in `$Env:Path`)
- in a path with a space
you must use the call operator:
```pwsh
# can't write parent's variables
pwsh -ExecutionPolicy Bypass $HOME\.local\bin\_webi.ps1 xz
# can write parent's variables (same process)
& $HOME\.local\bin\_webi.ps1 xz
# not in PATH, and has space in its path
& ".\Foo Bar\foobar.exe" -baz
```
To use it with multiple arguments:
```pwsh
# this can be just the name, or the full path
$Cmd = 'curl.exe'
# mind the leading ,
$CmdArguments = , '--fail-with-body', '-sS'
& $Cmd $CmdArguments -o example.html 'https://example.com'
```
As you can see, the array of options and arguments is flattened, which makes
constructing commands with complex arrangements much easier than...
<small>posix</small> (but don't tell my friends I said that).
### 4. PowerShell's curl vs Windows' curl.exe
PowerShell has a built-in `curl` which is an alias for the `Invoke-WebRequest`
commandlet.
Never use `curl`. Always use `curl.exe`.
### 5. PowerShell Preferences and Policies
- _Execution Policy_ must be set to allow PowerShell to run scripts:
```pwsh
# from a shell
powershell -ExecutionPolicy Bypass .\foobar.ps1
```
```pwsh
# for a script, itself
Set-ExecutionPolicy Bypass -Scope Process
& .\foobar.ps1
```
- Set _Strict Mode_ (like `set -e` in Bash, etc)
```sh
$ErrorActionPreference = 'Stop'
```
- Eliminate _Progress Bars_ (they _really_ slow Windows down) \
```sh
$ProgressPreference = 'SilentlyContinue'
```
The number of progress created by `Invoke-WebRequest` during a download is so
many that it literally can't download files over a few kilobytes in a
reasonable amount of time unless this is turned off.