PowerShell 速成课程

2025-06-09

PowerShell 速成课程

说实话,cmd.exe糟透了。我对 MS-DOS 6.0/6.22 记忆犹新,但克服了 Linux/Unix 的学习曲线后,就很难再回去了。PowerShell 1.0 发布时,我兴奋不已;终于有了一个“真正的” Windows 命令行界面了。但我又没法真正学习它,所以一直在安装cygwinmsys

在发现 PowerShell Core支持多平台后,它又回到了我的视野中,因为它有几个用例:

  • Windows 自动化
  • 持续集成/持续交付
  • Windows OEM
    • 如果您作为 Windows OEM 许可证持有者、设备 OEM/ODM 或企业 IT 定制/自动化 Windows 操作系统设置,则几乎必须使用 PowerShell

这更像是一份速查表/快速参考/食谱,而不是教程。如果你不习惯学习新的(脚本)语言,这份指南可能没什么帮助。

Shell 键盘快捷键

显示所有快捷方式的列表:



Get-PSReadlineKeyHandler


Enter fullscreen mode Exit fullscreen mode

在 macOS/Linux 上,默认为emacs“编辑模式”。如果您使用过 emacs(或bash 的 emacs 模式),您会感觉很熟悉。在 Windows 上,默认为“编辑模式”,Windows但您可以:



Set-PSReadLineOption -EditMode Emacs


Enter fullscreen mode Exit fullscreen mode

如果您是 PowerShell 新手,我强烈建议您切换到 emacs 模式。如果您只是想熟悉一下 Bash(如果您曾经使用过 Linux 终端的话)。

日常使用的命令:



# Movement
Ctrl+a # Beginning of line
Ctrl+e # End of line
Ctrl+f # Forward one character
Ctrl+b # Back one character
Alt+f # Forward one word
Alt+b # Back one word

# Editing
Alt+. # Insert last argument of previous command
Ctrl+d # Delete character
Alt+d # Delete word
Ctrl+u # Delete to beginning of line
Ctrl+k # Delete to end of line

# Command History
Ctrl+p # Previous command
Ctrl+n # Next command
Ctrl+o # Execute command and advance to next
Ctrl+r <text> # Search command history for <text>


Enter fullscreen mode Exit fullscreen mode

Alt+.这是我在安装 Linux 的第一天就希望学到的。提示:你可以反复按下它来循环查看上次参数的历史记录。

与 相同Ctrl+o。如果您需要重做一系列命令:Ctrl+p回到开始,Ctrl+o Ctrl+o...Ctrl+n如果需要跳过一个命令,等等。

如果你使用的是 macOS/OSX 系统,并且使用默认终端AltEsc那么你可以使用Option(推荐)通过终端 > 偏好设置

基本语法

文字和变量:



$boolean = $true # or `$false`
$string = "string"
$int = 42
$array = 1, 2, 3
$array2 = @(1, 2, 3)
$array[0] = $null # Remove first item
$hash = @{first = 1
    "second" = 2; third = 3
}
# Add to hashtable
$hash += @{4 = "fourth"}
$hash["fifth"] = 5 # Key has to be quoted here
$hash[4] = $null # Remove value (but not key) from hash

# String with `PATH` environment variable
"$env:PATH ${env:PATH}: safer"
# Multi-line "here string"
@"
"Here-string" with value $env:PATH
"@
# Escape character
"literal `$ or `" within double-quotes"
# Evaluate expression
"Hello $(echo world)"

# Casting locks variable type
[int[]]$ints = "1", "2", "3"
$ints = "string" # Throws exception
# Destructuring
$first, $rest = $ints # first = 1; $rest = 2,3


Enter fullscreen mode Exit fullscreen mode

控制流:



$value = 42
if ($value -eq 0) {
    # Code
} elseif ($value -gt 1) {
} else {
}

$value = "value"
# Match against each string/int/variable/expression case
switch ($value)
{
    "x" { echo "matched string" }
    1 { echo "matched int" }
    $var { echo "matched variable" }
    { $_ -gt 42 }{ echo "matched expression" }
    default { }
}
$collection = 1,2,3,4
# Matched against each element of collection. `$_` is current item. `Break` applies to entire collection
switch ($collection)
{
    1 { echo $_ 1 }
    { $_ -gt 1 } { echo "$_ Greater than 1" }
    3 { echo $_ 3; break }
}
# Output is (NB: there's no 4):
#1 1
#2 Greater than 1
#3 Greater than 1
#3 3

foreach ($val in $collection) {
}

while ($value -gt 0) {
    $value--
}


Enter fullscreen mode Exit fullscreen mode
  • 赋值:(+= -= *= /= ++ --例如++$int$int++$int += 1
  • 平等-eq -ne -gt -ge -lt -le
  • 匹配:(-like -notlike通配符),-match -notmatch(正则表达式;$matches包含匹配的字符串)
  • 收容措施-contains -notcontains -in -notin
  • 类型-is -isnot
  • 逻辑-and -or -xor -not!(例如$a -and $b-not $a!$a
  • 替换:(-replace替换字符串模式)
  • 除最后一项外,所有退货$true$false
  • 所有字符均不区分大小写。对于区分大小写的前缀,请使用c(例如-clike)
  • 如果输入是集合,则输出是匹配的集合

  • 比较运算符

必需品



# List commands containing "Path"
Get-Command -Name *path*

# Get help for `Get-Command`
Get-Help Get-Command

# List properties/methods of object
Get-Command | Get-Member

cd output/Debug
Set-Location output/Debug

# Current file/module's directory
$PSScriptRoot

ls
dir # also works which is freaky/helpful for migration
Get-ChildItem
# Pattern glob
ls *.jpg
Get-ChildItem *.jpg
# Just files
Get-ChildItem -File
# Just directories
Get-ChildItem -Directory
Get-ChildItem | ForEach-Object { $_.Name }
Get-ChildItem | Where-Object {$_.Length -gt 1024}

md tmp/
New-Item -ItemType Directory -Name tmp/ -Force | Out-Null

# Add to PATH
$env:PATH += ";$(env:USERPROFILE)" # `;` for Windows, `:` for *nix
$env:PATH += [IO.Path]::PathSeparator + $(pwd) # Any platform

# Check environment variable `GITHUB_TOKEN` is set
Test-Path Env:\GITHUB_TOKEN
# Test for file/directory
Test-Path subdir/child -PathType Leaf # `Container` for directory

pushd tmp/
popd
Push-Location tmp/
Pop-Location
cd - # Go back to previous directory

# Write to stdout, redirect stderr to stdout, send stdout to /dev/null
Write-Output "echo" 2>&1 > $null
&{
    Write-Warning "warning"
    Write-Output "stdout"
# Append warnings to tmp.txt, rest to /dev/null
} 3>> ./tmp.txt | Out-Null
# Write to stderr, redirect all, append to file
Write-Warning "oops" *>> ./tmp.txt

# Execute string
$ls = "ls"
& $ls
& $ls -l # with args
# Execute string with args
$ls_l = "ls -l"
Invoke-Expression $ls_l
# Execute file `script.ps1`
& ./script
$file = "./script.ps1"
& $file

# Execute command looking for failure text
$res = Invoke-Expression "& $cmd 2>&1"
if ($LASTEXITCODE -and ($res -match "0x800700C1")) {
    # Do something
}


Enter fullscreen mode Exit fullscreen mode

错误处理

Powershell 有终止(即异常)和非终止错误。



# Delete PathToDelete/ folder recursively ignoring all errors
Remove-Item -Force -Recurse -ErrorAction Ignore PathToDelete

# Make terminating error
Write-Error "fail" -ErrorAction Stop
throw "fail"

# Non-terminating errors are terminating
$ErrorActionPreference = "Stop"

# Handle terminating error
try {
    throw "fail"
} catch [System.Management.Automation.RuntimeException] {
    Write-Output "Throw'd: $_"
] catch [Microsoft.PowerShell.Commands.WriteErrorException] {
    Write-Output "Write-Error'd"
} catch {
    # Any error
} finally {
    # Always executes
}

# Handling non-terminating errors
if ($LastExitCode > 0) {
    # Exit code of last program >0, which might mean it failed
}
if ($?) {
    # Last operation succeeded
} else {
    # Last operation failed
}


Enter fullscreen mode Exit fullscreen mode

工作



# Start job in background (sleeps for 200 seconds)
$job = Start-Job { param($secs) Start-Sleep $secs } -ArgumentList 200
# Or
$job = Start-Sleep 200 &
# Wait for it with a timeout
Wait-Job $job -Timeout 4

# Jobs run in their own session, use -ArgumentList
$value = "hi"
Start-Job { Write-Output "value=$value" } | Wait-Job | Receive-Job
# Output: value=
Start-Job { Write-Output "value=$args" } -ArgumentList $value | Wait-Job | Receive-Job
# Output: value=hi

# Start a bunch of work in parallel
Get-Job | Remove-Job # Remove existing jobs
$MaxThreads = 2 # Limit concurrency
foreach ($_ in 0..10) {
    # Wait for one of the jobs to finish
    while ($(Get-Job -State Running).count -ge $MaxThreads) {
        Start-Sleep 1
    }
    Start-Job -ScriptBlock { Start-Sleep 2 } # Random work
}
# Wait for them all to finish
while ($(Get-Job -State Running)){
    Start-Sleep 1
}


Enter fullscreen mode Exit fullscreen mode
  • 工作
  • 如果使用相对路径,请小心:作业从$HOMEmacOS/Linux 和Documents/Windows 上启动
  • 需要Receive-Job查看 stdout/stderr
  • 来自此 SO 的并行工作片段

参数与功能

脚本的命令行参数被视为param()放置在文件顶部。



function Hello { echo Hi }
# Call the function
Hello
# Output: Hi

# Function with two named params. First with type and default (both optional)
function HelloWithParams {
    param([string]$name = "<unknown>", $greeting)
    echo "hello $name! $greeting"
}
HelloWithParams 1 2
# Output: hello 1! 2
HelloWithParams -greeting 40
# Output: hello <unknown>! 40

# Function with switch and positional parameters
function Greeting {
    param([switch]$flag)
    echo "hello $flag $args"
}
Greeting more stuff
# Output: hello False more stuff
Greeting -flag more stuff
# Output: hello True more stuff
Greeting -flag:$false more stuff
# Output: hello False more stuff


function PositionalParams {
    param(
        [parameter(Position=0)]
        $greeting,
        [string]$name,
        [parameter(Position=1)]
        $tail
        )
    echo "$greeting $name$tail"
}
PositionalParams hi "!"
# Output: hi !
PositionalParams hi -name jake "!"
# Output: hi jake!
PositionalParams hi "!" -name jake
# Output: hi jake!

function FormalHello {
    param(
        # Params default to optional
        [parameter(Mandatory=$true, HelpMessage="Initial greeting")]
        [string]$greeting,
        # If have multiple values have to use @()
        [string[]]$name = @("Sir", "<unknown>")
        )
    echo "$greeting $name $suffix"
}
FormalHello "Greetings"
# Output: Greetings Sir <unknown>
FormalHello -name sir,jake,3rd -greeting welcome
# Output: welcome sir jake 3rd


Enter fullscreen mode Exit fullscreen mode

杂项

Visual Studio 代码

  • 使用扩展名
  • 在 Windows 上,安装 PowerShell Core,然后在 Visual Studio Code 中单击“PowerShell 会话菜单”:

从出现的命令面板中选择切换到 PowerShell Core 6 (x64)

詹金斯

  • 内联 powershell 或调用脚本:


  powershell '''
      & ./script.ps1
      '''


Enter fullscreen mode Exit fullscreen mode
  • 调用脚本并处理退出代码:


  def res = powershell returnStatus: true, script: '''
      & ./script.ps1
      '''
  if (res != 0) {
      currentBuild.result = 'UNSTABLE'
  }


Enter fullscreen mode Exit fullscreen mode
鏂囩珷鏉ユ簮锛�https://dev.to/jeikabu/powershell-crash-course-3go5
PREV
第一印象:在学习 React/Redux 之后学习 Angular
NEXT
如何使用 Github 备份/同步所有点文件