CLIベースのファイル操作を行っているとその動作の素早さから離れにくくなる。コマンドをつぶさに覚えて、身に付けたほうが圧倒的に楽なことを体感できる。ただ、これを身に付けるとなると一朝一夕にはいかない。

コマンド辞書Get-Help -onlineを活用しよう

ヘルプの作法を真っ先に身に付けておけば、知らないコマンドに遭遇した際の理解、実践へと進みやすくなる。オンライン/オフラインを問わず語学を学習する際に辞書が欠かせないのと同じだ。PowerShellの場合、Get-Help。とりわけ、-onlineパラメータを使うとMicrosoftの公式リファレンスをブラウザが開くのだが、これが重宝する。

Get-Help 対象コマンド -online

Get-Help自体のオンラインヘルプを開くには

Get-Help Get-Help -online

と入力してやる。すると、規定ブラウザが立ち上がり、公式リファレンスを開く。

筆者のワークエリアではPowerShell 7.6を利用するるが、ここで上記コマンドを入力すると日本語のpowershell-7.6のヘルプが表示される。このコマンドを覚えておけば環境ごとに詳細なヘルプを随時確認できる点が良い。PowerShellにおいては、公式辞書のようなものだ。

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/get-help?view=powershell-7.6

PowerShellでテキストブラウザライクな運用をしてみたい

PCにおいて日常的に扱うツールが"ブラウザ"という人は多い。SaaSやクラウドのようにログインしないといけない作業や動画、ニュースなどの情報収集とブラウザが無いと業務が成立しない。それだけにシェルでのCLIベースのWeb閲覧の運用、たとえばササっと更新状況を確認したり、リンクを抽出したりといったことをコマンド化しておきたい。そう思った。PowerShellではInvoke-WebRequestがその役割を担う。

Get-Help Invoke-WebRequest -online

としてオンラインリファレンスを覗くと、そのまま使えそうなサンプルコードがある。これをそのままURLを置き換えて試すと

(Invoke-WebRequest -Uri "https://news.mynavi.jp").Links.Href

すると指定したURLにあるリンクを画面上に抽出する。

絶対パスで抽出されたリンクはCtrl+クリックでブラウザを開けるので使えるのだが、相対パスで抽出されたリンクはクリッカブルには機能しない。そこで、相対パスで記述されている場合に絶対パスを追加させる処理を加えることで、パラメーターでURLを指定できるlinksコマンドとした。コマンドライン上でパラメーターを指定しない際は、paramに設定したサイトを抽出する。

function links{
param(
    [string]$Site = "https://news.mynavi.jp"
)

$r = Invoke-WebRequest $Site
$r.Links |
Where-Object { $_.href } |
ForEach-Object {
    if ($_.href -like "http*") {
        $url = $_.href
    }
    else {
        $url = "$Site$($_.href)"
    }
    "$url"
}
}

パラメーターで受けたWebサイトのURLをInvoke-WebRequestで取得し、Linksプロパティがもつ複数のコレクションからURLを格納する.hrefをWhere-Objectでフィルタリング、ワイルドカード比較演算子の-likeで相対パスの場合に絶対パスを補完する。さきほどの問題は解決するが、相対パスの形がプレーンな階層でなければNotFoundの架空のリンクを作ってしまう。

  • スラッシュやディレクトリ名の重複など意図しないURLが作られてしまう

    スラッシュやディレクトリ名の重複など意図しないURLが作られてしまう

そこで、.NETのUriクラスを活用してみる(about_Classes)。/./や/../などのシーケンスを圧縮し、階層 URI のパスを正規化するなどURLを取り扱う際の便利な機能を提供する。

function links {

param(
    [string]$Site = "https://news.mynavi.jp"
)

$r = Invoke-WebRequest $Site

$r.Links |
Where-Object { $_.href } |
ForEach-Object {

    if ($_.href -like "http*") {
        $url = $_.href
    }
    else {
        $url = ([uri]::new($Site, $_.href)).AbsoluteUrii
    }

    "$url"
}
}

  • いくつかのWebサイトで試してみたが、インデックスの最新情報や重要なリンクは取れているようだ

    いくつかのWebサイトで試してみたが、インデックスの最新情報や重要なリンクは取れているようだ

いくつかのWebサイトで試してみたが、インデックスの最新情報や重要なリンクは取れているようなので、とりあえずはコマンドとして実装し"サッと見"には適しているように思う。またUriクラスやInvoke-WebRequestコマンドレットの多様な機能からしてカスタマイズの幅は広そうである。