博客 / 詳情

返回

Y 分鐘速成 powershell

源代碼下載: LearnPowershell-cn.ps1

PowerShell 是 Windows 平台下的腳本語言同時也是配置管理框架,它是建立在微軟 .Net Framework 之上,Windows 7 以及之後版本都內置 Poweshell。下面的示例中都是 PoweShell 腳本的一部分或者直接能夠在 Shell 交互窗口中執行。

與 Bash 最大的不同是你大部分操作的東西是對象而不是普通的文本。

延伸閲讀

如果你不確定你的環境,執行如下操作:

Get-ExecutionPolicy -List
Set-ExecutionPolicy AllSigned
# Execution Policy 包含以下:
# - Restricted: 不會運行腳本。
# - RemoteSigned: 只會運行受信任的發行商下載的腳本。
# - AllSigned: 運行需要被信任發行商簽名的腳本。
# - Unrestricted: 運行所有腳本
help about_Execution_Policies # 查看更多信息

# 當前 PowerShell 版本
$PSVersionTable

獲取幫助

# 查找命令
Get-Command about_* # 別名: gcm
Get-Command -Verb Add
Get-Alias ps
Get-Alias -Definition Get-Process

Get-Help ps | less # 別名: help
ps | Get-Member # 別名: gm

Show-Command Get-EventLog # GUI 填充參數

Update-Help # 管理員運行

接下來是教程

# 正如你看到的,每一行開頭是 # 都是註釋

# 簡單的 Hello World 實例
echo Hello world!
# echo 是 Write-Output (cmdlet) 的別名
# 大部分 cmdlet 和函數都遵循 "動詞-名詞" 命名規則。

# 每個命令都從新的一行開始或者是一個分號
echo 'This is the first line'; echo 'This is the second line'

# 聲明一個變量如下:
$aString="Some string"
# 或者像這樣:
$aNumber = 5 -as [double]
$aList = 1,2,3,4,5
$anEmptyList = @()
$aString = $aList -join '--' # 也包含 join 方法
$aHashtable = @{name1='val1'; name2='val2'}

# 使用變量:
echo $aString
echo "Interpolation: $aString"
echo "$aString has length of $($aString.Length)"
echo '$aString'
echo @"
This is a Here-String
$aString
"@
# 注意 ' (單引號) 不是變量的一部分
# 在這裏字符串也可以是單引號

# 內置變量:
# 下面是一些有用的內置變量,比如:
echo "Booleans: $TRUE and $FALSE"
echo "Empty value: $NULL"
echo "Last program's return value: $?"
echo "Exit code of last run Windows-based program: $LastExitCode"
echo "The last token in the last line received by the session: $$"
echo "The first token: $^"
echo "Script's PID: $PID"
echo "Full path of current script directory: $PSScriptRoot"
echo 'Full path of current script: ' + $MyInvocation.MyCommand.Path
echo "FUll path of current directory: $Pwd"
echo "Bound arguments in a function, script or code block: $PSBoundParameters"
echo "Unbound arguments: $($Args -join ', ')."
# 更多的內置類型: `help about_Automatic_Variables`

# 內聯其他文件 (點操作符)
. .\otherScriptName.ps1


### 控制流
# 下面是條件判斷結構
if ($Age -is [string]) {
    echo 'But.. $Age cannot be a string!'
} elseif ($Age -lt 12 -and $Age -gt 0) {
    echo 'Child (Less than 12. Greater than 0)'
} else {
    echo 'Adult'
}

# Switch 語句比其他語言更強大
$val = "20"
switch($val) {
  { $_ -eq 42 }           { "The answer equals 42"; break }
  '20'                    { "Exactly 20"; break }
  { $_ -like 's*' }       { "Case insensitive"; break }
  { $_ -clike 's*'}       { "clike, ceq, cne for case sensitive"; break }
  { $_ -notmatch '^.*$'}  { "Regex matching. cnotmatch, cnotlike, ..."; break }
  { 'x' -contains 'x'}    { "FALSE! -contains is for lists!"; break }
  default                 { "Others" }
}

# 經典的 For 循環
for($i = 1; $i -le 10; $i++) {
  "Loop number $i"
}
# 或者可以更簡潔
1..10 | % { "Loop number $_" }

# PowerShell 還提供其他循環方式
foreach ($var in 'val1','val2','val3') { echo $var }
# while () {}
# do {} while ()
# do {} until ()

# 異常處理
try {} catch {} finally {}
try {} catch [System.NullReferenceException] {
    echo $_.Exception | Format-List -Force
}


### Providers
# 列出當前目錄下的文件和子目錄
ls # 或者 `dir`
cd ~ # 回到主目錄

Get-Alias ls # -> Get-ChildItem
# 這些 cmdlet 有更加通用的名稱,因為它不僅僅只操作當前目錄,這一點和其他腳本語言不同。
cd HKCU: # 跳轉 HKEY_CURRENT_USER 註冊表中的值

# 獲取當前會話中的提供者
Get-PSProvider


### 管道
# Cmdlets 中的參數用來控制它們的行為:
Get-ChildItem -Filter *.txt -Name # 獲取所有 txt 文件名。
# 需要輸入足夠多的參數來確保沒有歧義。
ls -fi *.txt -n # -f 是不可以的因為 -Force 同樣存在。
# 使用 `Get-Help Get-ChildItem -Full` 來查看全部參數。

# 之前 cmdlet 獲取的結果輸出可以作為一下個輸入。
# `$_` 指代當前管道處理的對象。
ls | Where-Object { $_.Name -match 'c' } | Export-CSV export.txt
ls | ? { $_.Name -match 'c' } | ConvertTo-HTML | Out-File export.html

# 如果對管道的對象感到疑惑,使用 `Get-Member` 來查看該對象的可使用的方法和屬性。
ls | Get-Member
Get-Date | gm

# ` 是行連續標識符,或者在每一行結尾添加一個 |
Get-Process | Sort-Object ID -Descending | Select-Object -First 10 Name,ID,VM `
    | Stop-Process -WhatIf

Get-EventLog Application -After (Get-Date).AddHours(-2) | Format-List

# 使用 % 作為 ForEach-Object 的簡稱。
(a,b,c) | ForEach-Object `
    -Begin { "Starting"; $counter = 0 } `
    -Process { "Processing $_"; $counter++ } `
    -End { "Finishing: $counter" }

# Get-Process 返回包含三列的表
# 第三列是使用 2 位精度數值表示 VM 屬性
# 計算出來的列也可以表示更多的信息:
# `@{name='lbl';expression={$_}`
ps | Format-Table ID,Name,@{n='VM(MB)';e={'{0:n2}' -f ($_.VM / 1MB)}} -autoSize


### 函數
# [string] 註記是可選的。
function foo([string]$name) {
    echo "Hey $name, have a function"
}

# 調用你的函數
foo "Say my name"

# 函數可以包含命名參數、參數的註記和可解析的文檔
<#
.SYNOPSIS
Setup a new website
.DESCRIPTION
Creates everything your new website needs for much win
.PARAMETER siteName
The name for the new website
.EXAMPLE
New-Website -Name FancySite -Po 5000
New-Website SiteWithDefaultPort
New-Website siteName 2000 # ERROR! Port argument could not be validated
('name1','name2') | New-Website -Verbose
#>
function New-Website() {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
        [Alias('name')]
        [string]$siteName,
        [ValidateSet(3000,5000,8000)]
        [int]$port = 3000
    )
    BEGIN { Write-Verbose 'Creating new website(s)' }
    PROCESS { echo "name: $siteName, port: $port" }
    END { Write-Verbose 'Website(s) created' }
}


### 都是 .NET
# PS 中的字符串事實上就是 .NET 的 System.String 類型
# 所有 .NET 方法和屬性都可用
'string'.ToUpper().Replace('G', 'ggg')
# 或者更加 PowerShell 一點
'string'.ToUpper() -replace 'G', 'ggg'

# 不確定這樣的話 .NET 方法如何調用
'string' | gm

# 調用靜態 .NET 方法的語法:
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')

# 注意 .NET 方法調用必須使用括號,然而 PS 函數調用不能使用括號;
# 如果你調用 cmdlet/PS 函數使用了括號,就相當於傳遞了參數列表。
$writer = New-Object System.IO.StreamWriter($path, $true)
$writer.Write([Environment]::NewLine)
$writer.Dispose()

### IO
# 從輸入讀入一個值
$Name = Read-Host "What's your name?"
echo "Hello, $Name!"
[int]$Age = Read-Host "What's your age?"

# Test-Path, Split-Path, Join-Path, Resolve-Path
# Get-Content filename # 返回字符串數組 string[]
# Set-Content, Add-Content, Clear-Content
Get-Command ConvertTo-*,ConvertFrom-*


### 有用的東西
# 更新 PATH
$env:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") +
    ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")

# 找到 Python 的 PATH
$env:PATH.Split(";") | Where-Object { $_ -like "*python*"}

# 改變工作目錄而不需要記住之前的路徑
Push-Location c:\temp # 改變工作目錄至 c:\temp
Pop-Location # 改變到之前的工作目錄
# 別名: pushd 和 popd

# 在下載之後解除目錄阻塞
Get-ChildItem -Recurse | Unblock-File

# Windows 資源管理器打開當前目錄
ii .

# 按任意鍵退出
$host.UI.RawUI.ReadKey()
return

# 創建快捷方式
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($link)
$Shortcut.TargetPath = $file
$Shortcut.WorkingDirectory = Split-Path $file
$Shortcut.Save()

配置你的 PowerShell

# $Profile 是文件 `Microsoft.PowerShell_profile.ps1` 完整路徑
# 下面所有的代碼都在 PS 會話開始的時候執行
if (-not (Test-Path $Profile)) {
    New-Item -Type file -Path $Profile -Force
    notepad $Profile
}
# 更多信息: `help about_profiles`
# 更多關於 Shell 有用的信息,確保查看下面的 PSReadLine 項目。

更多項目

  • Channel9 PowerShell 教程
  • PSGet PowerShell NuGet 包
  • PSReadLine 仿 bash 按行讀取( Window10 默認包含)
  • Posh-Git Git 命令提示 (推薦!)
  • PSake 自動構建工作
  • Pester BDD 測試框架
  • Jump-Location Poweshell 中 cd 來跳轉目錄
  • PowerShell Community Extensions (廢棄)

尚未涉及

  • WMI: Windows 管理規範 (Get-CimInstance)
  • 多任務: Start-Job -scriptBlock {...},
  • 代碼簽名
  • 遠程 (Enter-PSSession/Exit-PSSession; Invoke-Command)

有建議?或者發現什麼錯誤?在Github上開一個issue,或者發起pull request!

原著Wouter Van Schandevijl,並由0個好心人修改。
© 2022 Wouter Van Schandevijl
Translated by: Feng Gao
本作品採用 CC BY-SA 3.0 協議進行許可。

user avatar user_p5fejtxs 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.