HN 日本語サマリー

← 一覧へ戻る
プログラミング

PowerShellがこんなに良いなんて信じられない

I can't believe PowerShell is good (spacebar.news)

46 pointsby corbindavenport39 コメント

要約

著者は当初、Microsoft製品への懐疑心からPowerShellに注目していませんでしたが、PowerShell 7(PowerShell Core)が驚くほど強力で汎用性の高いスクリプティングおよび自動化ツールであることを発見しました。Bashスクリプトと比較して、PowerShellは組み込み機能、オブジェクト指向性、クロスプラットフォーム対応に優れており、システム管理タスクやデータ処理に役立つことを実例を挙げて説明しています。

全文翻訳

PowerShellがこんなに良いなんて信じられない

Microsoftは、プライマリメールアプリがウェブビューラッパーであることから常に表示されるCopilotボタンに至るまで、多くの良くないソフトウェアを作っています。そのため、Microsoftの製品が私の生活を何らかの形で改善してくれると、特にWindows由来のものである場合、いつも驚かされます。

私は、2006年に初めて登場し、Windows 7のリリースと同時にバンドルアプリケーションとなったコマンドラインシェルおよびスクリプティングツールのPowerShellには、あまり注意を払っていませんでした。私がWindowsをメインのデスクトップオペレーティングシステムとして使用していた時期は、より複雑なタスクには、コマンドプロンプトとバッチスクリプト、あるいはWSLのBashやPythonを使用していました。PowerShellの最新バージョンはクロスプラットフォームであり、MacやLinuxにもインストールできます。

今年の初め、あるWindows関連のプロジェクトでPowerShellスクリプティングを学ぶ必要があり、Macでも数回試してみました。それはすぐに、自動化やスクリプティングのための私のお気に入りのツールの1つになりました。これまでNode.js、Shortcuts、macOS Automator、あるいは恐ろしいことにBashスクリプトでやろうとしていたような作業を引き受けてくれます。

今ならわかります。PowerShellは、たとえシェルとして使用していなくても、たとえMacやLinuxを使っていても、素晴らしいツールです。

壁に頭をぶつける

Linux、macOS、その他のUnixベースの環境で一連のコマンドを実行する最も一般的な方法は、Bashスクリプトを使用することです。これらはシェルスクリプトとも呼ばれますが、厳密には同じものではありません。なぜなら、Z Shell(zsh)のような他のシェルでも使用されるからです。

メディアURLを入力させ、yt-dlpアプリケーションを使用してそれをデスクトップフォルダにMP3オーディオファイルとして保存するBashスクリプトの例を以下に示します。

#!/bin/bash

echo -e "Enter a URL: "
read url
cd ~/Desktop
yt-dlp -x --audio-format mp3 "$url"
echo "Done!"

Bashスクリプトは、単に一連のコマンドを実行するだけなら問題ありません。変数やループを使用でき、繰り返し使用するコードは関数にまとめることができ、配列のようなデータ型も限定的にサポートされています。また、さまざまなハードウェアやオペレーティングシステムで時々動作することもあります。

少しでも複雑なことになると、Bashスクリプティングは最悪です。「組み込み」関数はほとんどなく、ファイル操作やテキスト解析のような一般的なタスクにはPOSIXコマンドを使用することになっています。それ以上のことは、Webコンテンツの取得にはcURLやWgetのような外部ツール、クリップボードへのアクセスにはいくつかの 異なる アプリケーション、JSONデータの読み取りにはjqに依存します。また、オプションとパラメータを解析するための定型コードが必要になる場合もあります。

さらに、他の人のコンピューターで確実に動作するBashスクリプトを作成するのは驚くほど困難です。スクリプトを、スクリプトの解釈方法が異なる別のシェルで実行しようとする人もいるかもしれません。そのため、Homebrewのインストールコマンドは、bashシェルを明示的に呼び出すことから始まります。他の多くのツールも同様のトリックを使用します。誰かがWebコンテンツを取得するためにcURLしかインストールしていないか、Wgetしかインストールしていないか、あるいは両方、あるいはどちらもインストールしていないかもしれません!すべてのシステムに同じ基本的なPOSIXコマンドセット、あるいは数ヶ月前に学んだようにsudoコマンドさえも搭載されているとは限りません。

Bashスクリプティングの制限により、厳密には必要ないタスクでさえ、実際のプログラミング言語に頼ることが多くなっていました。Pythonは最良の代替手段かもしれませんが、波括弧がないのが悲しいです。私は多くのJavaScriptコードを書いているので、Node.jsも選択肢ですが、システム操作のためにどこにでもawait演算子を配置する必要があり、より多くの依存関係が必要な場合にマルウェアをインストールしていないことを願うしかありません。

こんにちは、PowerShell

Microsoftの他の多くの製品(およびGoogle)と同様に、PowerShellは実際には似た名前の2つの異なるものです。使用すべきは、.NET Coreをベースにした最新のクロスプラットフォームバージョンであるPowerShell 7、別名PowerShell Coreです。もう一つは、.NET Frameworkをベースにしており、積極的に開発されていないWindows PowerShell(v5.1以下)です。Windows 11には、PowerShell 7ではなく、依然としてWindows PowerShellしか含まれていません。

PowerShell 7は、Windows、Mac、Linuxで無料ダウンロードできます。私のMacコンピューターでは、Homebrewを使用してインストールしました。そして、ターミナルでpwshと入力して実行できます。

[画像: ZSHとPowerShellでechoコマンドを実行しているターミナルウィンドウ]

PowerShellスクリプトの基本的な考え方は、Bashスクリプトとそれほど変わりません。シェルまたは基盤となるシステムによって提供されるコマンドのリストであり、必要に応じて追加の関数やキーワード(if、foreach、try/catchなど)を使用できます。

PowerShellには「cmdlet」(「コマンドレット」と発音)と呼ばれる多くの組み込みコマンドがあり、さらにインストールすることも、独自のcmdletを作成することもできます。ほとんどのcmdletの名前は、POSIXのcdの代わりにSet-Location、clsの代わりにClear-Host、rmの代わりにRemove-Itemのような動詞-名詞のペアになっています。

ここで、先ほどのMP3ダウンローダーをPowerShellスクリプトとして示します。

Param(
    [Parameter(Mandatory = $true)][uri]$url
)

Set-Location -Path ~\Desktop

yt-dlp -x --audio-format mp3 "$url"
Write-Host "Done!"

このスクリプトのクールな部分はParamブロックで、これはPowerShellの組み込みパラメータサポートを使用して、「url」を必須のURI入力として定義しています。PowerShellはスクリプト開始時にそのURLを尋ねてきますが、これはBashの例と同様であり、代替の入力方法としてスクリプトに-urlパラメータを指定することもできます。

PowerShellの組み込みGet-Helpコマンドをスクリプトで実行することもできます。これにより、組み込みコマンドのGet-Helpと同様に、データ型を含むパラメータのリストが表示されます。

[画像: スクリプトをさまざまな方法で実行しているターミナルスクリーンショット]

Bashでこの同じ機能を実現するには、getparamsとさまざまなif文を使った多くの定型コードが必要になります。PowerShellはそれらをすべて処理してくれます。

お気づきかもしれませんが、Unixスタイルの~/Desktopパスは、すべてのプラットフォームのPowerShellで機能します。Windowsはシステムレベルではバックスラッシュのパスを使用しますが、PowerShellは必要に応じてそれらを変換できます。ただし、ネイティブのシステムコマンドは、まずConvert-Pathcmdletを使用しない限り、そうしないかもしれません。Bashと同様に、チルダ(~)文字はホームディレクトリのエイリアスです。または、すべてのプラットフォームでPowerShellがサポートする$HOME変数を使用することもできますPowerShellはすべてのプラットフォームでサポートしています。

PowerShellは、整数、文字列、配列、ハッシュテーブルのネイティブサポートを備えています。これは、Web APIからコンテンツを解析する際に特に役立ちます。なぜなら、PowerShellはJSONに変換したり、JSONから変換したりできるからです。また、完全にオブジェクト指向であり、必要に応じてカスタムオブジェクトを作成することも、.NET関数を呼び出すこともできます。

Bashと同様に、PowerShellスクリプトの作成には任意のテキストエディタを使用できます。Visual Studio Codeを使用している場合は、PowerShellの構文補完、定義追跡、リンティングサポートなどが提供されます。

試験運用

PowerShellでの最初の本格的なプロジェクトはJust the Browserでした。これは、デスクトップWebブラウザからAI機能、トラッキング、その他の不要な機能を削除することを目的としたプロジェクトです。MacとLinuxのインストーラーはBashスクリプトなので、WindowsバージョンをPowerShellスクリプトにするのが理にかなっていました。

インストーラーの仕事は、コンピューターに存在するブラウザをチェックし、各ブラウザの「Update settings」メニュー項目を表示することです。その項目が選択されると、スクリプトはブラウザ設定を含むWindowsレジストリファイルをダウンロードしてインストールします。設定がインストールされている場合、スクリプトはメニューに「Remove settings」オプションを追加してプロセスを元に戻します。

[画像: PowerShellウィンドウ内のブラウザ選択メニュー]

これは、各リストアイテムがメニューラベルと更新/削除関数を含むオブジェクトである、.NET List<T>クラスを使用して実現されています。既にレジストリエントリが変更されているかどうかを確認するために、Test-PathおよびGet-ItemPropertycmdletを使用しました。例を以下に示します。

if (Test-Path "HKLM:\SOFTWARE\Policies\Google\Chrome") {
  $IfAiSettingExists = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Google\Chrome").AIModeSettings
}

このスニペットにはいくつかのクールな点があります。レジストリパスが、通常のWindowsレジストリ階層ではなく、「HKLM」というドライブ上のファイルパスのように見えることに気づいたかもしれません。通常のパスは次のようになります。

HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome

PowerShellはWindowsレジストリの仮想ドライブを作成し、ファイルシステムのようにレジストリキーを取得、追加、変更、クリア、削除できるようにします。同じTest-Pathcmdletは、特定のファイルがダウンロードフォルダにあるかどうかを確認するためにも機能します。ファイルの使い方とレジストリキーの使い方を別々に学ぶ必要はありません。なぜなら、PowerShellではそれらは同じものだからです。

PowerShellには、Windowsの証明書ストアのような他の仮想ドライブもあり、独自のドライブを作成することさえできます。シェルやスクリプトで長いパスを入力するのにうんざりしているなら、それにポイントする仮想ドライブを作成しましょう!好きな名前を付けることもできます。

そのスクリプトは、Webブラウザを設定するための.regファイルをダウンロードする必要もあります。Google Chromeの場合のプロセスの簡略版を以下に示します。

$GoogleChromeInstallRegistry = "https://raw.githubusercontent.com/corbindavenport/just-the-browser/main/chrome/install.reg"

Invoke-WebRequest $GoogleChromeInstallRegistry -OutFile "$env:LocalAppData\chrome.reg"

$ChromeInstall = Start-Process "reg.exe" -ArgumentList "import `"$env:LocalAppData\chrome.reg`"" -WindowStyle Hidden -Wait -PassThru

これはInvoke-WebRequestcmdletを使用して、指定されたURLからレジストリファイルをダウンロードし、一時的にユーザーアカウントのAppDataフォルダに保存します。次に、reg.exeコマンドを非表示ウィンドウで開始し、ダウンロードしたファイルをインポートするように指示し、コマンドが完了するまで待機します。PowerShellはキーを直接変更することもできましたが、手動でインポートできる別のファイルにしたかったため、これは自動インストーラーを使用したくない人もいるからです。

Invoke-WebRequestcmdletは、MacやLinuxシステム上のWgetやcURLのように機能し、スクリプト内でWebコンテンツをダウンロードできます。これは、Bashスクリプトで頻繁に必要となる、すべてのプラットフォームのPowerShellに組み込まれたもう1つの機能です。

インストーラーを古いバージョンのWindows PowerShellでも動作させ、古いPCでPowerShellバージョンをアップグレードせずに実行できるようにしたかったのです。これにはいくつかの変更が必要でした。例えば、Invoke-WebRequestを使用する前にTLS v1.2を有効にするコマンドは、以前はデフォルトで有効になっていなかったためです。

[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12

別のプロジェクトでは、古いTumblrブログを、Eleventy静的サイトジェネレーターを使用しているメインの個人ウェブサイトにマージすることを試していました。それを行う既存のツールはなかったので、[