PowerShell とは、Microsoft 社のオペレーティングシステムで作動する各種プログラムを、 コマンドラインで作成・参照・更新・削除できるしくみである。
コマンドラインを起動するには、すべてのアプリから、Windows PowerShell を選ぶ。Windows 10 では、 (x86) があるものとないもの、ISE がついているものとついていないものとで計4種類の組み合わせがあるが、 どちらもついていないものを選べばよい。
そのほか、Windows Terminal をインストールして起動することもできる。
コマンドプロンプトが出ている画面で、単に $PSVersion と打ち込み、Enter キーを押せばよい。 下記は私の Windows 10 の環境である。
PS C:> $PSVersionTable Name Value ---- ----- PSVersion 5.0.10586.122 PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.10586.122 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
次のような CSV ファイルがあるとしよう。
番号 ,年月日 ,緯度, 経度, マグニチュード, 1,日本語名称1 , 2,英語名称 , 3, 日本語別称 404 ,1995-01-17 ,34.6, 135.0, 7.3, 1, 兵庫県南部地震, 2, Kobe earthquake, 3, 阪神・淡路大震災 411 ,2001-03-24 ,34.1, 132.7, 6.7, 1, 芸予地震 414 ,2003-09-26 ,41.8, 144.1, 8.0, 1, 十勝沖地震 415 ,2004-10-23 ,37.3, 138.9, 6.8, 1, 新潟県中越地震 418 ,2007-03-25 ,37.2, 136.7, 6.9, 1, 能登半島地震 419 ,2007-07-16 ,37.6, 138.6, 6.8, 1, 新潟県中越沖地震 420 ,2008-06-14 ,39.0, 140.9, 7.2, 1, 岩手・宮城内陸地震 423 ,2011-03-11 ,38.1, 142.9, 9.0, 1, 東北地方太平洋沖地震, 2, Tohoku earthquake, 3, 東日本大震災
CSV ファイルを取り込むコマンドレット Import-CSV がある。これを使おう。
PS C:\Users\username> Import-CSV .\earthquake.csv -Encoding Default
すると次のように出力される。
番号 | : 404 |
年月日 | : 1995-01-17 |
緯度 | : 34.6 |
経度 | : 135.0 |
マグニチュード | : 7.3 |
1 | : 1 |
日本語名称 | : 兵庫県南部地震 |
2 | : 2 |
英語名称 | : Kobe Earthquake |
3 | : 3 |
日本語別称 | : 阪神・淡路大震災 |
(中略) | |
番号 | : 423 |
年月日 | : 2011-03-11 |
緯度 | : 38.1 |
経度 | : 142.9 |
マグニチュード | : 9.0 |
1 | : 1 |
日本語名称 | : 東北地方太平洋沖地震 |
2 | : 2 |
英語名称 | : Tohoku earthquake |
3 | : 3 |
日本語別称 | : 東日本大震災 |
このように1レコードずつ清書されて出てくる。このように、第1行目を列の属性(アトリビュート)として解釈してくれる。
1レコードあたりの処理を行なうには、次のような分解ができる。
Import-Csv 'servers.csv' | ForEach-Object { $_."列の属性" }
PS C:\Users\username> Import-CSV .\earthquake.csv -Encoding Default | ForEach-Object{ >> $_."年月日" +$_."1"+ $_."日本語名称1"+"`n"+ $_."年月日" + $_.3 + $_."日本語別称" } 1995-01-17 1兵庫県南部地震 1995-01-17 3阪神・淡路大震災 2001-03-24 1芸予地震 2001-03-24 2003-09-26 1十勝沖地震 2003-09-26 2004-10-23 1新潟県中越地震 2004-10-23 2007-03-25 1能登半島地震 2007-03-25 2007-07-16 1新潟県中越沖地震 2007-07-16 2008-06-14 1岩手・宮城内陸地震 2008-06-14 2011-03-11 1東北地方太平洋沖地震 2011-03-11 3東日本大震災
PowerShell を使って、複数の Excel ファイルから固定シートの固定セルの値を拾って読むことを考える。 「平成 27 年」という名前のフォルダーに複数の Excel ファイル(ブック)がある。1ブックにつきシートは1枚だけで、次のような表になっている。
utsunomiya.xlsx
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
1 | 月 | 日 | 日出h | 日出m | 日入h | 日入m |
2 | 1 | 1 | 6 | 52 | 16 | 42 |
これは、都市 utsunomiya (宇都宮)の1月1日の日の出が 6 時 52 分であり、日の入りが 16 時 35 分であることを表している (理科年表 平成 27 年 暦 40 より)。 このようなブックで1月1日の日の出の時間を PowerShell表示する。
# hinode.ps1 param($file) # 引数に使う $file = (Get-ChildItem $file).FullName # オープンのためにフルネームにする $excel = New-Object -ComObject Excel.Application # Excel を扱うための準備をする $excel.Visible = $false # Excel を非表示 $book = $excel.Workbooks.Open($file) # フルネームで指定したブックを開く $sheet = $excel.Worksheets.Item(1) # 1 番目のシートを選択する $line = 2 # 第 2 行を選択する $hinodeh = $sheet.Cells.Item($line,3).Text # 第 2 行の第 3 列を選択する $hinodem = $sheet.Cells.Item($line,4).Text # 第 2 行の第 4 列を選択する Write-Host "$file : $hinodem " 時 "$hinodeh" 分 # 取得した情報を表示する $excel.Quit()
> .\hinode.ps1 .\utsunomiya
このシステムではスクリプトの実行が無効になっているため……
というエラーが表示され、実行されないようになっている。 これは PowerShell のポリシーである。
Set-ExectionPolicy RemoteSigned
実行ポリシーの変更 実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies のヘルプ トピック (http://go.microsoft.com/fwlink/?LinkID=135170) で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか? [Y] はい(Y) [A] すべて続行(A) [N] いいえ(N) [L] すべて無視(L) [S] 中断(S) [?] ヘルプ (既定値は "N"):
ここで何もせずに Return のみを押してしまうと、変更が反映されない。したがって確実に Y をクリックしよう。
さて、実行した結果は次の通りだ。
PS > .\hinode.ps1 utsunomiya.xlsx
C:\users\username\documents\powershell\utsunomiya.xlsx : 6 時 52 分
では次に、都市 hiroshima (広島)の日の出と同時に出してみよう。 広島は、1月1日の日の出が 7 時 16 分であり、日の入りが 17 時 11 分であることを表している (理科年表 平成 27 年 暦 34 より)。 hiroshima.xlsx に同じようなデータを作ってみたらどうだろうか。
PS > .\hinode.ps1 hiroshima.xlsx
C:\users\username\documents\powershell\hiroshima.xlsx : 7 時 16 分
環境変数すべてを表示する
Get-ChildItem env:
環境変数 Path を表示する
Get-ChildItem env:Path
新たに環境変数 RUST_LOG を作り、値として debug を設定する
$env:RUST_LOG="debug"
上のいくつかのページで見たように、幅が足りない場合には折り返しがされず、途中が省略され、切れてしまう (キレるのは、若者だけでも、老人だけでもないようだ)。 その場合には、Format-Table コマンドレットに -Autosize -Wrap オプションを付ける。
Get-ChildItem env:Path | Format-Table -Autosize -Wrap
私のような老人は、Unix だったらできるのに PowerShell だとできないと考えてしまう。 だから、Unix のコマンドと PowerShell のコマンドを関連付けることを試みた。
PowerShell では Get-Command である。 私が作った自作のバッチファイル webserver.bat の場所を探したいとする。
> Get-Gommand webserver CommandType Name Version Source ----------- ---- ------- ------ Application webserver.bat 0.0.0.0 C:\Users\username\documents\bin\webserve...
私の Windows 10 Home Edition では PowerShell のバージョンは 5 であり、 Source の欄にパスも表示されている。 パスが表示されない場合は、Format-List を後続に使う。
> Get-Gommand webserver | Format-List Name : webserver.bat CommandType : Application Definition : C:\Users\username\documents\bin\webserver.bat Extension : .bat Path : C:\Users\username\documents\bin\webserver.bat FileVersionInfo : File: C:\Users\username\documents\bin\webserver.bat InternalName: OriginalFilename: FileVersion: FileDescription: Product: ProductVersion: Debug: False Patched: False PreRelease: False PrivateBuild: False SpecialBuild: False Language:
echo は引数を順に表示するコマンドである。
>echo Je pense, donc je suis. Je pense, donc je suis.
これをまねてみる。
>cat echo.ps1 [string] $s = "" foreach ($s in $args) { Write-Output $s }
>./echo.ps1 Je pense, donc je suis. Je pense, donc je suis.
カンマでは分離されないのですね。ワイルドカードはどうだろう。
>./echo.ps1 *.ps1 *.ps1
あれ、ワイルドカードを展開してくれない。どうしよう。
PoweShell のコマンドレットはワイルドカードを展開してくれる。
>./Convert-Path *.ps1 C:<absolute-path>\echo.ps1 C:<absolute-path>\resize.ps1
>./Get-ChildItem -Name *.ps1 echo.ps1 resize.ps1
では、バッチファイルではこうかな。
>cat echo.ps1 $strs = Get-ChildItem -Name $args foreach ($s in $strs) { Write-Output $s }
>./echo.ps1 *.ps1 echo.ps1 resize.ps1
やれやれ。
Windows のコマンドプロンプト画面は、昔は DOS 窓とか DOS プロンプトなどと呼ばれていた。 今はコマンドプロンプト画面はすべて PowerShell に置き換えられていると思ったが、 思ったよりそうでもないようだ。実際私が作業するときも、PowerShell で作業するよりコマンドプロンプト画面で作業する場合が多い。なぜだろう。
たとえば、PowerShell 画面でコマンドを打つと、こんなエラーが出ていらいらする。
PS C:> wget --help wget : リモート名を解決できませんでした。: '--help' 発生場所 行:1 文字:1 + wget --help + ~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest]、WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand PS C:> wgetコマンド パイプライン位置 1 のコマンドレット Invoke-WebRequest 次のパラメーターに値を指定してください: Uri:PS C:> $PSVersionTable Name Value ---- ----- PSVersion 5.1.22621.963 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.22621.963 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
わけがわからない。しかし、同じ PowerShell でも、コマンドプロンプトと同じようにうまくいくことがある。 PowerShell のバージョンの違いのようだ。
PS C:> wget --help GNU Wget 1.15, a non-interactive network retriever. Usage: wget [OPTION]... [URL]... Mandatory arguments to long options are mandatory for short options too. (中略) PS C:> wget wget: missing URL Usage: wget [OPTION]... [URL]... Try `wget --help' for more options. PS C:> $PSVersionTable Name Value ---- ----- PSVersion 7.2.9 PSEdition Core GitCommitId 7.2.9 OS Microsoft Windows 10.0.22621 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0
コマンドプロンプトの時代から、Windows で標準出力と標準エラー出力を同一のファイルに一緒に出力する方法として、
LINUX などの UNIX 系 OS では次の記法が知られている。
$ command >file 2>&1
参考
https://www.itmedia.co.jp/help/tips/linux/l0388.html
この記法 2>&1 という記法は Windows のコマンドプロンプトでも有効だ。では、PowerShell ではどのように記述するのだろう。マイクロソフトの、 リダイレクトについて(learn.microsoft.com) から引用する。
例 1: エラーと出力をファイルにリダイレクトする dir 'C:\', 'fakepath' 2>&1 > .\dir.log エラー ストリームを成功ストリームにリダイレクトし>、結果の成功ストリームを呼び出されたファイルに送信するために使用2>&1されます。dir.log
何をいっているのかわからない。英語で読んでみよう。
PowerShell dir 'C:\', 'fakepath' 2>&1 > .\dir.log It uses 2>&1 to redirect the Error stream to the Success stream, and > to send the resultant Success stream to a file called dir.log
これならまだ意味がわかる。「2>&1 (という書き方)を使って、エラーストリームを成功ストリームにリダイレクトし、 (リダイレクトされた)結果の成功ストリームを dir.log ファイルに書き出す」。 ここでは、'C:\' という確実に存在するフォルダの内容と、'fakepath' という、実際に存在しないフォルダの 2 つを同時に表示してその結果を dir.log に書き込む、 という意図がある。もちろん、dir を 'C:\' に 適用した結果は成功ストリームに送られ、dir を 'fakepath' に 適用した結果はエラーストリームに送られる。 2>&1 のおかげでエラーストリームは成功ストリームとマージされ、無事 dir.log に両方の結果が入る。なんだ、UNIX と同じでいいのか。
数十個の JPEG ファイルがある。これらの画像をまとめて縮小する(リサイズする)必要が生じた。 どうすべきか。 プログラマならプログラムを書くだろう。さて、どの言語で書けばよいか。 せっかくだから PowerShell を使うことを考えた。以下はその一例である。 もとの JPEG ファイルはすべて同じフォルダにあるものとし、 縮小したファイルは quarter というフォルダに保存されるものとする。
# ワイルドカードの展開 $strs = Convert-Path $args foreach ($s in $strs) { # アセンブリの読み込み [void][Reflection.Assembly]::LoadWithPartialName("System.Drawing") # 画像ファイルの読み込み Write-Output $s $image = New-Object System.Drawing.Bitmap("$s") # 縮小先のオブジェクトを生成 $canvas = New-Object System.Drawing.Bitmap([int]($image.Width / 2), [int]($image.Height / 2)) # 縮小先へ描画 $graphics = [System.Drawing.Graphics]::FromImage($canvas) $graphics.DrawImage($image, (New-Object System.Drawing.Rectangle(0, 0, $canvas.Width, $canvas.Height))) # 保存 $t = (Split-Path $s) + "\quarter\" + (Split-Path -Leaf $s) Write-Output $t $canvas.Save("$t", [System.Drawing.Imaging.ImageFormat]::Jpeg) # オブジェクトの破棄 $graphics.Dispose() $canvas.Dispose() $image.Dispose() }
カラー画像をグレースケール画像にしようと思った。画像の拡大縮小と同じようにできないかと探したが、 プログラムを作るか OpenCV などのライブラリを探すかしないといけない。 面倒だと思っていたら、jpeg ライブラリを使った jpegtran というプログラムがあるということを知った。 何かのついでに入れているのではないかと思ったら、 Python で Anaconda を入れたときについでに入ったようだ。 詳細は Anaconda 参照。
Elm を導入して PowerShell で実行しようとしたが、エラーが出てしまった。 原因は実行ポリシーが Restricted(制限の意味)になっているからで、これは Get-ExecutionPolicy を実行するとわかる。 対策は、実行ポリシーを変更することで、たとえば、 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process とする。 以下はその例である。
PS C:> elm
elm : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Program Files\nodejs\elm.ps1 を読み込むことが
できません。詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwlink/?LinkID=135170) を参照してくだ
さい。
発生場所 行:1 文字:1
+ elm
+ ~~~
+ CategoryInfo : セキュリティ エラー: (: ) []、PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
PS C:> Get-ExecutionPolicy
Restricted
PS C:> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
PS C:> Get-ExecutionPolicy
RemoteSigned
PS C:> elm
Hi, thank you for trying out Elm 0.19.1. I hope you like it!
-------------------------------------------------------------------------------
I highly recommend working through <https://guide.elm-lang.org> to get started.
It teaches many important concepts, including how to use `elm` in the terminal.
-------------------------------------------------------------------------------
(2022-11-22)
まりんきょ学問所 > コンピュータの部屋 > Windows 手習い > PowerShell 手習い