2019-08-25に更新

お前らにプログラマーらしい Power shell のふだんの使い方を説明してやろう☆m9(^~^)<書きかけ>

読了目安:13分

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 最近は Docker がコンピューターの未来を牽引していくのか、 .NET Core が流行りだよな☆ .NET Framework 離れ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 何だぜ それ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 .NET Core は Windows から GUI を取り除いたようなやつだが、Visual Studio Code で使えるのも .NET Core だぜ☆
 例えば MessageBox のようなダイアログボックスは 基本的に使えない☆
代わりに Read-Host コマンドなどを使って、昔ながらの文字入力だぜ☆ Yes or No☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 y ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 なんで Power shell は UTF-8 with BOM なの? 頭に3バイト付けてほしくないんだけど?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ 普段の実践パターンを説明するぜ☆
クラスを使うと他の人が読めなくなるので、グローバル変数なども使うといった、実践的かつ BAD なプログラミングだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 では、 Power shell ISE を使うのは止めろだぜ☆ Visual studio code を出せだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 N・A・N・D・E?」

20190809comp1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Power shell ISE は Windows に標準搭載されているが、エディターとしては何も助けてくれない☆
二千の00年代までのエディターだぜ☆」

20190809comp2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それに比べ、 Visual studio code は エクステンションを追加できる☆ 昔でいうプラグインのことだぜ☆
もちろん Power shell も実行できる☆ 前述のとおり .NET Core なんで、 .NET Framework にできて Visual studio code でできないことはある☆」

practice-1.ps1

# Make the directory containing this script current.
Write-Host "Exit           | {$(Get-Location)}"
Set-Location $PSScriptRoot
Write-Host "Enter          | {$(Get-Location)}"

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まず最初に、 カレント・ディレクトリ がどこかを はっきりさせろだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 何だぜ それ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 カレント・ディレクトリ の話しだけで 1記事書けるので、今は飛ばすぜ☆
重要なことは 今どき カレント・ディレクトリ とか 死に機能 でバグの元、使わないで済むなら使いたくないものだぜ☆
しかし残念ながら これから CUI の人気が盛り返したら また復活するかもしらん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 叩くプログラム は 同じディレクトリにまとめて置いておく☆
叩くプログラム の先頭で カレント・ディレクトリ を実行プログラムのある場所にしておく、
必要がなければプログラムの途中で カレント・ディレクトリ は動かさない、
とだけ 覚えておけだぜ☆ なんのことだか 分からんと思うが……☆」

20190809comp3b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Power shell スクリプトのエンコーディングは UTF-8 with BOM に変えておけだぜ☆ 日本語の文字化けを防げる☆
嫌かも知らんが、 Power shell は古いシェルだからな☆」

module-1.ps1

Function Show-MyName() {
    Write-Host "むずでょ$(10+29)歳"
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ファイルを複数個に分けたいなんて、すぐに出てくるだろ☆ 最初に教えておいてやろう☆
ちなみに 関数名は好き勝手付けてもいいが、コードチェックを黙らせるような規約は存在する☆」

Approved Verbs for PowerShell Commands

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 英語のサイトの方がいいの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 英文に触れる機会を多くしておけだぜ☆
しゃべれないかもしれないが、慣れろ☆
お前らは 外国人 と出会うこともないのかもしれないが、出会うことになってから困る☆ メイクセンス☆?」

20190809comp4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 他の言語なら import 文みたいなのがあると思うが Power shell にはない☆ 代わりに ドットソース というのがある☆
これは Power shell ファイルを 上から下まで読むのと おんなじだぜ☆
Power shell は シェルだから、プログラム実行と同じだな☆ だから結局 import 文みたいな使い方ができる☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 Power shell じゃなくて、 Python を使おうぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 企業勤めをすると ホワイトリスト というのがあってな☆ 使ってもいいプログラムのリストとかなんだが、
Pythonのダウンロードはできるんだが、インストールするときに ポリシー に違反してインストールできないことがある☆
ポリシーというのは 社員のマシンに制限を与えるようなものだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 プログラマーは 核爆弾ぐらいの危険物ですからね。制限を加えるのは当然よね」

KIFUWARABE_80x100x8_01_Futu.gif
「 ホワイトリスト に Python を入れてくれるように頼めばいいじゃないか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 競合会社に利するかもしれない☆
プログラマーは 勤め先によっては シェアの奪い合いに巻き込まれて 制約を受けることがあるんだぜ☆
そんな あなたには Power shell だぜ☆
Windows を使っていて、 Microsoft と競合している勤め先にいることは あんまり ないだろ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 世界を競合相手に回す会社は コボルや フォートランとか 使ってそうよね」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、どんな感じに Power shell を利用するかなんだが☆」

20190809comp5b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Visual studio code の TERMINAL タブのところが そのまま シェルになっている☆
コマンドを打ち込めば その場で実行できる☆」

Get-Variable

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 例えば Get-Variable コマンドを打鍵すれば、グローバル変数の一覧が出てくる☆
このリストを眺めているだけでも 何ができるか ちょっと分かる☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ここで注意しておいて欲しいのは、グローバル変数というのは プログラム・ファイル の実行というような区切りでのプロセスではなく、
シェル というプロセスに ずっと残っているということだぜ☆
前の変数が残っているような挙動をし出して 怪しくなったら ゴミ箱アイコンを推して シェルを再起動しろだぜ☆」

20190809comp6.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 わたしが よく使う くそプログラム・テクニック はこれだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 連想配列ね」

KIFUWARABE_80x100x8_01_Futu.gif
「 Java Script にも Python にもあるのに……☆」

module-1.ps1

Function Show-MyName() {
    Write-Host "むずでょ$(10+29)歳"
}

Function Invoke-Example() {
    If ( $global.Options.Apple -cmatch "y") {
        Write-Host "Yes, Apple!"
    }

    If ( $global.Options.Banana -cmatch "y") {
        Write-Host "Yes, Banana!"
    }

    If ( $global.Options.Cherry -cmatch "y") {
        Write-Host "Yes, Cherry!"
    }
    ElseIf ( $global.Options.Cherry -cmatch "n") {
        Write-Host "No, Cherry!"
    }

    If ( $global.Options.Durian -cmatch "y") {
        Write-Host "Yes, Durian!"
    }
}

Write-Host "He he he!☆(^q^)"

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 別ファイルに Invoke-Example 関数を作ってみよう☆
-cmatch というのは正規表現のパターンマッチで Case sensitive だぜ☆」

practice-1.ps1

# Make the directory containing this script current.
Write-Host "Exit           | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter          | $(Get-Location)"

# Dot source.
. ".\module-1.ps1"
Show-MyName

# Hashmap, Dictionary.
$global = @{
    Options = @{
        Apple  = "y";
        Banana = "n";
        Cherry = "iy";
        Durian = "";
    }
}

Invoke-Example

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 最後に Invoke-Example コマンドを打つぜ☆ これで実行すると☆」

Exit           | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
Enter          | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
He he he!☆(^q^)
むずでょ39歳
Yes, Apple!
Yes, Cherry!

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 実行したい部分だけ 狙い撃ちで指定できるわけだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 フーン

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 昔のコンソール画面のメニューに似てるだろ☆ [F1]キーを押してくれだの、[1]キーを押してくれだの☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 プログラムを丸ごとコピー貼り付け という くそBADテクニック で けっこう スピーディーに問題に その場対応 している☆
メンテナンスとか くそくらえ だぜ☆
設定ファイルを用意するとか いろいろ あるかも知れないが、 メイン・スクリプト・ファイル1枚に全部の多値フラグ☆
ひとびとの頭は深く考えることはできない☆ マニュアルも読まない☆ ここに行きつく☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 実践的だな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 デザインも メンテナンスも へったくれも ないわね」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ここで要点は、最初に実行されるスクリプト・ファイルに ごちゃごちゃ コードを書かないことだぜ☆
書くと 読めなくなる☆ 連想配列だけ 置いておいて、 最後に 関数を呼び出せだぜ☆」

ErrorActionPreference

$ErrorActionPreference = "Stop"

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あと 言うのを忘れていたが、 $ErrorActionPreference というグローバル変数に Stop という文字列を入れておけだぜ☆
Power shell はエラーが出ても 次々と コマンドを実行していくが、
$ErrorActionPreference = "Stop" としておくだけで、エラーがあったときに シェルが止まってくれるぜ☆」

Breadcrumb

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 頭 痛~☆。 夏休みに風邪でダウンしている☆
パンくずリストは よく使うので この省は書き直そう☆」

practice-4\main.ps1

function Write-Breadcrumb([system.collections.stack]$stack) {
    $arr = "$($stack)".Split(" ")
    [array]::Reverse( $arr )
    $text = $arr -join " > "
    Write-Host "Breadcrumb      | $($text)"
}

# +
# | Example
# +
$stack = New-Object system.collections.stack


Write-Breadcrumb $stack
$stack.Push("apple")
Write-Breadcrumb $stack
$stack.Push("banana")
Write-Breadcrumb $stack
$stack.Push("cherry")
Write-Breadcrumb $stack

Output

Breadcrumb      |
Breadcrumb      | apple
Breadcrumb      | apple > banana
Breadcrumb      | apple > banana > cherry

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 例えば パンくずリストも グローバル変数に1個持っておくといいだろう☆」

$global = @{
    Breadcrumb = new-object system.collections.stack;
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 本当は パンくずリストは Push のたびに毎回 表示しない方がいい☆ 何かしたときに表示しろだぜ☆」

抜粋

Function Invoke-Example() {
    $global.Breadcrumb.Push( $MyInvocation.MyCommand )
    Write-Breadcrumb $global.Breadcrumb

    $global.Breadcrumb.Push( "Apple" )
    Write-Breadcrumb $global.Breadcrumb
    If ( $global.Options.Apple -cmatch "y") {
        Write-Host "Yes, Apple!"
    }
    $global.Breadcrumb.Pop() | Out-Null

    $global.Breadcrumb.Push( "Banana" )
    Write-Breadcrumb $global.Breadcrumb
    If ( $global.Options.Banana -cmatch "y") {
        Write-Host "Yes, Banana!"
    }
    $global.Breadcrumb.Pop() | Out-Null

    $global.Breadcrumb.Push( "Cherry" )
    Write-Breadcrumb $global.Breadcrumb
    If ( $global.Options.Cherry -cmatch "y") {
        Write-Host "Yes, Cherry!"
    }
    ElseIf ( $global.Options.Cherry -cmatch "n") {
        Write-Host "No, Cherry!"
    }
    $global.Breadcrumb.Pop() | Out-Null

    $global.Breadcrumb.Push( "Durian" )
    Write-Breadcrumb $global.Breadcrumb
    If ( $global.Options.Durian -cmatch "y") {
        Write-Host "Yes, Durian!"
    }
    $global.Breadcrumb.Pop() | Out-Null

    $global.Breadcrumb.Pop() | Out-Null
}

全体の実行結果

Exit           | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
Enter          | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
He he he!☆(^q^)
むずでょ39歳        
Breadcrumb     | Invoke-Example
Breadcrumb     | Apple Invoke-Example
Yes, Apple!
Breadcrumb     | Banana Invoke-Example
Breadcrumb     | Cherry Invoke-Example
Yes, Cherry!
Breadcrumb     | Durian Invoke-Example

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 使い方の例は むずかしいが、 Push() と表示、 Pop() の3つを使っていけだぜ☆
ちなみに Push より Pop の回数が多いと もちろん例外を吐く☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 簡単な パンくずリスト ができたな☆
スタック・トレースより仕込みに手間がかかるが、エラー経路を探すには手ごろだぜ☆」

YesNoDialog

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 基本、オプション設定で全部指定するべきなんだが コピー貼り付けのあとの修正を忘れて 大惨事になってしまうことはある☆
ファイルを削除するときに 念押し の手動操作を入れる方法も 説明しておこう☆」

practice-1.ps1 抜粋

if (Show-YesNoDialog "[!] Delete a C:\Uso\dayo.txt") {
    Write-Host "(^q^)v"
}
else {
    Write-Host "(-_-)"
}

module-1.ps1 抜粋

# +
# | Psuedo dialog.
# +
Function Show-YesNoDialog($message) {
    while (1) {
        Write-Host $message
        $res = Read-Host "(y/n)"

        # Ignore case.
        switch ($res) {
            "y" { return $True }
            "n" { return $False }
            Default { Start-Sleep -Seconds 1 }
        }
    }
}

実行結果

[!] Delete a C:\Uso\dayo.txt
(y/n):
[!] Delete a C:\Uso\dayo.txt
(y/n): c
[!] Delete a C:\Uso\dayo.txt
(y/n): Y
(^q^)v

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 No をデフォルトにしたいとかいうときは switch文のところを勝手に改造しろだぜ☆」

Power shell で .ini ファイルを読めるようにしようぜ☆?

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんで 今どき 仕様が混ぜくちゃな .ini なのか……☆ というと
プログラムの仕事をくれるのは プログラマーじゃないからだぜ☆
『どこ直せばいいの?』『ここ』 という会話以外をしたら クビになる☆」

INI file parsing in PowerShell

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 コードは Stack overflow に貼り付けてあるコードをもらっていけばいいだろう☆」

ini-parser.ps1

Function Parse-IniFile ($file) {
  $ini = @{}

  # Create a default section if none exist in the file. Like a java prop file.
  $section = "NO_SECTION"
  $ini[$section] = @{}

  switch -regex -file $file {
    "^\[(.+)\]$" {
      $section = $matches[1].Trim()
      $ini[$section] = @{}
    }
    "^\s*([^#].+?)\s*=\s*(.*)" {
      $name,$value = $matches[1..2]
      # skip comments that start with semicolon:
      if (!($name.StartsWith(";"))) {
        $ini[$section][$name] = $value.Trim()
      }
    }
  }
  $ini
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ただし、コードの出所は マイクロソフトのくせに マイクロソフトは コーディング規約に縛られないぜ☆」

Approved Verbs for PowerShell Commands

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 メソッド名は Read-IniFile ぐらいに変えておくのがいいと思う☆」

config.ini

; +
; | Example.
; |
; | Comment starts with semicolon. Not #. 
; | UTF8.
; +

Apple = 1

[Banana]

Cherry = C:\My document\Uso\800.txt

[Date]

Elderberry = The directory has been rebuild.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 どうでも良かったので 適当に書いた INIファイルだが、
わたしは 単一行コメントは # より ; を使うぜ☆
わたしの周りで セミコロンがコメントに使えたプログラムの方が多かったから そうしているだけだが☆」

practice-1.ps1

Set-Location $PSScriptRoot

. "./ini-parser.ps1"
$cnf = Read-IniFile("./config.ini")

Write-Host "Apple          | $($cnf["NO_SECTION"]["Apple"])"
Write-Host "Cherry         | $($cnf["Banana"]["Cherry"])"
Write-Host "Elderberry     | $($cnf["Date"]["Elderberry"])"

Output

Apple          | 1
Cherry         | C:\My document\Uso\800.txt     
Elderberry     | The directory has been rebuild.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 簡単だろ☆ ブーリアン型を扱うには一手間要るが 説明するのが めんどくさいので 気分が向いたときにするぜ☆」

次の記事

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント