Skip to content

Instantly share code, notes, and snippets.

@yano3nora
Last active January 19, 2020 09:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yano3nora/0ed9c0d9f5b16191695fc6007a4a143a to your computer and use it in GitHub Desktop.
Save yano3nora/0ed9c0d9f5b16191695fc6007a4a143a to your computer and use it in GitHub Desktop.
[win: Windows PowerShell] Windows command-line shell and scripting language built on .NET. #powershell #win #cs

OVERVIEW

PowerShell Documentation - docs.microsoft.com - 公式マニュアル
PoserShell Reference - docs.microsoft.com - コマンドとかはここで検索できる
PowerShellの基本
PowerShell 使い方メモ

従来のコマンドプロンプトは MS-DOS:16bit のエミュレータ → 様々な拡張機能を有する Windows シェルという位置づけだったが、パワーシェルは .NET で駆動する ( シェル操作を引き継いだ ) ターミナルである。

Windows 10 環境なら Win + R > powershell で起動できる。管理者権限つきで起動する場合は Win アイコンを右クリックから「Windows PowerShell ( 管理者 ) 」を選択。

文字列を UTF8 で扱いたい

Using PowerShell v6 for charactor encoding

# インストール
$ choco install powershell-core --version=6.2.1 -y

# PowerShell 6 の実行
$ pwsh.exe

COMMANDS

PowerShell の「コマンド」は Get-Help など、動詞+名詞の形になっている。コマンドの入力途中で Tab を押下するとコマンドを補完してくれるので便利。また、コマンドプロンプトと同等のコマンドは「エイリアス」という形で旧コマンドのままでも利用できる ( cddir 等 ) 。その他 複数行にわたるコマンドを記述をしたいときは Shift + Enter で改行ができる

# touch 的なやつ
PS> ni .gitignore

返り値

旧コマンドプロンプトでは、コマンドの返り値は単純な文字列だったので、パイプ先のコマンドを工夫 ( 正規表現使ったり ) する必要があった。しかし PowerShell では返り値が PSObject と呼ばれる .NET オブジェクトのインスタンスになっているため、文字列に比べてより柔軟な処理が可能になっている。

PS> $result = Get-Date
PS> echo $result
PS> $result.GetType()

パイプ処理

PS> コマンド A | コマンド B のように記述すると「パイプ処理」により、コマンド A の戻り値を、パイプ | の次に書いた コマンド B に引き渡せる。

特殊変数 $_

特殊変数 $_ はそのコマンド内でのみ有効の「前コマンドの返り値が自動的に格納される変数」で $_.Length のように利用する。返り値は基本オブジェクトなので . アクセス演算子でプロパティやメソッドにアクセス可能。

Where-Object と 比較演算子

Where-Object
Where-Objectのスクリプトブロックで複数の文を使いたいとき

渡されたオブジェクトから要素を抽出する。エイリアスは where または ? 。ブロックの中で比較演算子を用いて真偽値を返却することで条件にマッチする要素を抽出することができる。

PS> Get-Service | where Status -eq "Stopped"

# {} ( Script Block ) で true / false 返却による判定もできます
PS> Get-Process | Where-Object { $_.ProcessName -Match "^p.*" }

# 利用可能な比較演算子
-eq	等しい(=)	$_.Name -eq "wga.log"
-ne	等しくない(≠)	$_.Name -ne "wga.log"
-gt	より大きい(>)	$_.Length -gt 1MB
-ge	以上(≧)	$_.Length -ge 1MB
-lt	未満(<)	$_.Length -lt 1MB
-le	以下(≦)	$_.Length -le 1MB
-like	ワイルドカード	$_.Name -like "*.log"
-match	正規表現検索	$_.Name -match "[a-z]{1,}\.log"
-in	含む(..)	$_.Length -le 1MB

# 文字列比較で大文字/小文字を区別する場合には「c」、しない場合には「i」を演算子の先頭に付ける。例えば「-ieq」などとする

ForEach-Object による反復処理

ForEach-Object - docs.microsoft.com
ForEach-Objectとforeachは違う?

渡されたイテレータブルなオブジェクトについて反復処理を行う。エイリアスは foreach または % だが、似たような foreach () {} ステートメントも存在するので注意。コマンドの方は内部でバッチ処理的に「要素ごとにメモリ上に展開」するのに対してステートメントは「全要素をメモリに一括展開」する。

PS> 30000, 56798, 12432 | ForEach-Object -Process {$_/1024}

29.296875
55.466796875
12.140625

Select-Object

Select-Object

オブジェクトからプロパティ名や行数を指定して選択する。

PS> Get-Process | Sort-Object -Property WS | Select-Object -Last 5

Measure-Object

Measure-Object

対象オブジェクトについて min / max / sum / avg などお馴染みの数値演算を行う。

PS> Import-Csv ./serviceyrs.csv | Measure-Object -Property years -Minimum -Maximum -Average

SCRIPTS

C# リファレンス - docs.microsoft.com - C# 関連の検索はこっち
.NET API ブラウザー - .NET API に関しての検索はここ
PowerShellスクリプティングの第一歩
powershell チートシート

内部的には .NET で動かすことになるので、PowerShell の文法に加えて C# でのプログラミングができる。スクリプトの拡張子は .ps1 。Windows 初期状態では、セキュリティの観点から PowerShell のユーザスクリプト実行は禁止されている。利用する場合は以下コマンドで変更しておくこと ( 要管理者権限 ) 。

PS> Get-ExecutionPolicy // 確認
PS> Set-ExecutionPolicy RemoteSigned

また PowerShell はファイル実行の際にカレントディレクトリを自動探索してくれないので、PATH を通してない場合は PS> ./script.sh1 のように「現在ディレクトリを相対パス・絶対パスで指定する」必要があるのに注意。

シンタックス

About If - docs.microsoft.com
About ForEach - docs.microsoft.com

function main
{
  foreach ($file in Get-ChildItem)
  {
    if ($file.length -gt 100KB)
    {
      Write-Host $file
    }
  }
}

データ型

型 (C# リファレンス) - docs.microsoft.com
PowerShell で扱える変数型備忘録

type	FullName	MinValue	MaxValue
[array]	System.Array		
[bool]	System.Boolean		
[byte]	System.Byte	0	255
[char]	System.Char		
[datetime]	System.DateTime	0001/01/01 0:00:00	9999/12/31 23:59:59
[decimal]	System.Decimal	-79228162514264337593543950335	79228162514264337593543950335
[double]	System.Double	-1.79769313486232E+308	1.79769313486232E+308
[guid]	System.Guid		
[hashtable]	System.Collections.Hashtable		
[int16]	System.Int16	-32768	32767
[int32], [int]	System.Int32	-2147483648	2147483647
[int64], [long]	System.Int64	-9223372036854775808	9223372036854775807
[nullable]	System.Nullable		
[psobject]	System.Management.Automation.PSObject		
[regex]	System.Text.RegularExpressions.Regex		
[sbyte]	System.SByte	-128	127
[scriptblock]	System.Management.Automation.ScriptBlock		
[single], [float]	System.Single	-3.402823E+38	3.402823E+38
[string]	System.String		
[switch]	System.Management.Automation.SwitchParameter		
[timespan]	System.TimeSpan	-10675199.02:48:05.4775808	10675199.02:48:05.4775807
[type]	System.Type		
[uint16]	System.UInt16	0	65535
[uint32]	System.UInt32	0	4294967295
[uint64]	System.UInt64	0	18446744073709551615
[xml]	System.Xml.XmlDocument	
# 変数のデータ型を出力
Write-Host $hoge.getType()

Array

# @(1, 2, 3, 4, 5)

$arg = @()
 
$arg += 'John'
$arg += 'Bob'
$arg += 'Jane'

Hash Tables

About Hash Tables - docs.microsoft.com

# @{ <name> = <value>; [<name> = <value> ] ...}

$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"}

引数のセット

Powershellで引数を受け取る

Powershell スクリプトでは引数は自動的に $Args[] に格納されます。

引数宣言したい場合は以下のように Param() で宣言すれば宜しい。初期値は $something = 'default' のようにセット。データ型を [String]$something のように指定したり [parameter(mandatory)] で入力を強制させたりできる。

# echo-args.ps1
# 文字列引数 something を出力するスクリプト
#
# @example PS> C:\echo-args.ps1 -something hoge
# @param   string $something - parameter(mandatory) により入力を強制
# @return  string $something
#
Param([parameter(mandatory)][string]$something)
Write-Host $something

ステータスコード返却

PowerShell での終了ステータス($?、$LastExitCode) について確認してみた

PS> echo $?  # True / False

Invoke-Expression で文字列のスクリプト評価

スクリプトに 0..50 みたいなオペレータを含む文字列を渡し、これをパースして [int[]] な配列要素にしたいようなケースでは、Invoke-Expression で文字列を評価するしかないみたい。ちなみにエイリアスは iex

$range = 0..50
$range.length  # 51

# 上記を文字列で渡される動的な引数から行いたい
# ... が以下のようにキャストはできない
$range = [int[]]'0..50'  # エラー

# よって iex ( Invoke-Expression ) で文字列を式評価
[int[]]$range = iex '0..50'
$range.length  # 51

プログレスバーの表示

PowerShellで進ちょく状況をプログレス・バーで表示する

$records = Import-Csv './import.csv' -Encoding UTF8
$counter = 1
$length  = $records.length

$records | % {
  # Do something ...
  $p = $counter / $length * 100
  Write-Progress 'Processing ... ' ([String]$p + '%') -percentComplete $p
  $counter++
}

TIPS & REFERENCES

Linux の which 相当コマンド

where.exe {command}

ファイル差分 / diff

# diff が Compare-Object のエイリアスみたい
diff (get-content ./hoge.txt) (get-content ./fuga.txt)

現在ディレクトリをスクリプト実行ディレクトリにセット

Set-Location (Split-Path $MyInvocation.MyCommand.Path -parent)

オブジェクトのプロパティ / メソッドをリスト

Get-Member

PS> Get-Service | Get-Member

TypeName: System.ServiceProcess.ServiceController

Name                      MemberType    Definition
----                      ----------    ----------
Name                      AliasProperty Name = ServiceName
Equals                    Method        System.Boolean Equals(Object obj)
GetHashCode               Method        System.Int32 GetHashCode()
GetType                   Method        System.Type GetType()
ToString                  Method        System.String ToString()
...
DisplayName               Property      System.String DisplayName {get;set;}
MachineName               Property      System.String MachineName {get;set;}
ServiceHandle             Property      System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
ServiceName               Property      System.String ServiceName {get;set;}
...

現在ディレクトリオブジェクトをリスト

PS > Get-ChildItem | Format-List *

# リスト内容が大量にありそうな時のために more に戻り値を渡して少しずつ出力
PS > Get-ChildItem | Format-List * | more

# リスト表示したいカラムを指定しても良い
PS > Get-ChildItem | Format-List Name, Length

ディレクトリの「最終更新が 6 ヶ月以上前」を抽出して削除

PS > Get-ChildItem |
>> Where-Object {$_.LastWriteTime -lt (Get-Date).AddMonths(-6)} |
>> ForEach-Object {$_.Delete()}

ファイル名の複雑なパターン変更

PS> dir | ren -newname { $_.name -replace '旧文字列','新文字列' }

ファイル内の文字列 Grep して置換する

PowerShellでgrepして置換みたいなことをしたい人生だった

# ./ 以下ディレクトリ内の *.csv の中に存在する 'Y20' を 'X20' へ置換したい

$ Get-ChildItem . -include *.csv -Recurse -Force |
>> ? { Select-String -InputObject $_ -Pattern 'Y20' -Encoding default } |
>> % { Set-Content $_.FullName ((Get-Content -LiteralPath $_) -replace 'Y20', 'X20') }

ファイル名探索したいよう!

Get-ChildItem . -Include *.txt -Recurse -Force | Select-String "たぬき" -Encoding default

# -Include *.txt で全 .txt ファイルを取得できる
# -Exclude で除外も可能
# -Recurse で再帰的にオブジェクトを取得
# -Force で隠しファイルも取得
# -encoding default で現在環境のエンコード ( 日本語 S-JIS ) を指定

sudo 的なやつ

powershell -command "Start-Process -Verb runas cmd"

コンテキストメニューに追加

http://qiita.com/xxxDATxxx/items/5a68c528d28f7a866f19

  1. Win + R > regedit
  2. HKEY_CLASS_ROOT\Directory\Background\shell へ移動
  3. 以下構成でキーを作成
    • /powershell
      • 既定: PowerShell (&S)
      • icon: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
    • /command
      • 既定: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoExit
  4. ディレクトリの背景右クリックして動作確認

CSV ファイルの取り扱い

Import-Csv / Export-Csv / ConvertTo-Csv / ConvertFrom-Csv
PowerShellのImport-CsvコマンドレットでCSVファイルを読み込む
PowerShellのExport-CsvコマンドレットでCSVファイルを出力する
PowerShell でテキストデータを CSV として読み込んでデータベースっぽく操作するメモ

PowerShell は標準で CSV ファイル操作 API がビルトインされている。

# Import
$csv = Import-Csv file.csv -Encoding Default

# Export ( SJIS )
Get-EventLog system | Export-Csv -path syslog.csv -Encoding Default -NoTypeInformation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment