SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

Windows11/PowerShellをバッチファイル的に使う最低限

目次

Windows11/PowerShellをバッチファイル的に使う最低限

僕は、PowerShellは・・ほぼ・・使いません

簡単な処理ならBATファイルを書きますし、使える環境ならPythonを使います。

でも、仕事でたまーにですけど、WindowsでBATファイルしか使えないけど、それだけではやりきれない程度に複雑なことをしなければならない場合があります。

そういう時、緊急避難的にPowerShellを使うのに必要な「最低限」を整理しました。

拡張子とスクリプトの実行方法

PowerShellスクリプトは拡張子「ps1」で保存するのが一般的です。

スクリプト実行は以下のようにします。

powershell.exe -ExecutionPolicy Bypass (実行ファイルパス)\実行ファイル名.ps1

ExecutionPolicyはデフォルト「Restricted」で、スクリプトは実行できなくなってます。なので、実行時にブロックされない「Bypass」にしないといけません。。

ちなみに。

タスクスケジューラに登録するときは

%Systemroot%\System32\WindowsPowerShell\v1.0\

Powershellのフルパスを指定します。

最低限の文法-変数

$を付けます。例は

$val = 1

$str = "aaaaaa"

$bool = $TRUE / $FALSE

最低限の文法-配列

@() でから配列の生成・初期化ができます。

参照は[0]のように普通に添え字でアクセスします。

$arVal = @()

$arVal2 = @(1,2,3)

$arVal += "値の追加"

$arVal[0]  # 参照

最低限の文法-連想配列

連想配列(ハッシュテーブル)の定義は @{} を使います。

$hashVal = @{one="one",two="two"}

$hashVal2 = @{}

$hashVal.three += "three"

$hashVal.two = "twotwo"

$hashVal,one # 参照

最低限の文法-コマンド実行・標準出力取り込み

外部コマンドを実行して、標準出力や標準エラーをファイルにはき、それを読み込んで、なにかの判定をする・・みたいな使い方をよくします。

引数のない外部コマンドは普通に実行できます。

結果を吐き出すのは普通にリダイレクトできます。

date > .\out.txt

date >> .\out.txt

date 2>&1 > .\out2.txt

引数のあるコマンドは、そうはいけません。

 例えば、「dir /b /s 」みたいなオプションのついたコマンドです。

Start-Processコマンドレットでリダイレクトすると、文字コードの問題で文字化けとかに苦しむことが多いからです。

なので、僕はさっさとやりたいときは。

@echo off
chcp 65001
dir /b /s %1 > .\out.txt

みたいにバッチファイルの中でリダイレクトしておいて

$psi = New-Object Diagnostics.ProcessStartInfo
$psi.FileName = "C:\boku\work\dir.bat"
$psi.Arguments = "C:\boku\excelwork"
$psi.UseShellExecute = $false
$psi.StandardOutputEncoding = [Text.Encoding]::UTF8
$psi.RedirectStandardOutput = $true
$p = [Diagnostics.Process]::Start($psi)

のようなやり方です。

つまり、PowerShellで「バッチファイル」を外部プログラムとして実行して、バッチファイルでリダイレクトしたout.txtの内容を読み込んで後続処理をするやり方です。

ポイントはバッチファイル内で「chcp 65001」・・つまり「utf8」に文字コードを変えて、Powershell内のエンコードとあわせてるとこですかね。

なお、ファイルは、Get-Contentで読み込みます。

$StdOutString = Get-Content ".\out.txt"

最低限の文法-行毎の処理・配列の全要素処理

ファイルの内容を読み込むと複数行ありますので、繰り返し処理が必要です。

foreach($Line in $StdOutString){

     # 1行ごとの処理

}

配列なんかも同じ感じでいけます。

foreach($val in $arrVal){

     # 1行ごとの処理

}

最低限の文法-IF文と画面出力

処理分岐です。

上記の続きで、標準出力を取り込んだファイルの中身に何等かの文字が存在してるかしていないか・・で分岐するというのを、僕の場合はよく使います。

上記の「$StdOutString」に「11]が含まれているか・・は

$String.Contains("11")

であればTrue、なければFalseになります。

上記のforeachと組み合わせて、一致したら「Write-Host」で画面に描きだして、breakでループから抜ける・・感じだとこうなります。

foreach($Line in $StdOutString){

     if($Line.Contains("11"){

           Write-Host $Line

           break

     }

}

あと、処理の戻り値で判定する手もあります。

上のほうの例でいえば。

$p = [Diagnostics.Process]::Start($psi)

if($p.ExitCode -eq 0) {
       # 0だった場合の処理
 }

のようなイメージです。

補足:僕が使わない理由=日本語がからむとめんどくさい

PowerShellは「日本語」を扱うと一気に面倒な代物になります。

文字化けしたり、エラーがでたり。

調べると「$PSDefaultParameterValues」とか「$OutputEncoding」とか、ここでエンコーディングを設定すれば解決しそうなパラメータがいろいろあります。

でも、それがきく処理ときかない処理があり、うまくいかないことも多いです。

前のほうでdirコマンドの結果に日本語ファイルが含まれても大丈夫なように対応してますが、あれでも結果を出力しようとすると文字化けしたりします。

このへん、僕が知らないだけでうまいやり方があるのかもしれませんが、とりあえず、PowerShellではできるだけ「日本語」は使わない。

それがストレスを避ける一番の方法だと僕は思ってます。

とりあえず、この位が僕の考える最低限です。

ではでは。