2016/12/20

この記事はPowerShell Advent Calendar 2016の20日目です。

はじめに

前々回はASTの概要について述べ、最後にAST.FindAllメソッドを使って、ASTから指定のASTノードを検索する方法について説明しました。

前回はASTを再帰的に検索して、木構造を視覚化してみました。

今回もASTを検索する話なのですが、静的解析機能を実装するためのAST Visitorを用いる方法について説明します。が、あらかじめお断りしておきますが、静的解析の実装までは今回はたどり着きません。静的解析ツールをどう作るかorどう作られているか、ということを雰囲気で味わっていただければと。

Visitorパターン

AST Visitorの説明をする前に、まず、Visitorパターンについて簡単に。

Visitorパターン[Wikipedia]というのは、オブジェクト指向言語におけるデザインパターンの1つで、対象オブジェクトを巡回する「訪問者」クラスを定義するものです。Visitorクラスでは、対象クラスごとに行う処理を、個別にvisitメソッドをオーバーロードさせることで定義します。共通のVisitor抽象クラスを継承することで、異なる機能を持ったVisitorクラスを作ることができます。

一方、処理対象クラスには、Visitorオブジェクトを引数に受け取る、acceptメソッドを定義します。acceptメソッドでは、引数として受け取ったVisitorオブジェクトのvisitメソッドを呼ぶことで、処理を実行させます。

なお、処理対象クラスが子要素クラスを持つ場合には、acceptメソッド内で、子要素クラスのacceptメソッドを呼ぶようにします。こうしておくことで、Visitorは処理対象を再帰的に巡回できるようになります。

このように処理対象クラスから、実際に処理を行う機能をVisitorクラスとして分離することで、処理対象クラスに手を加えることなく、Visitorクラスを追加して、処理内容を増やしたりすることが可能になります。

AST Visitorの呼び出し

Visitorパターンを念頭において、AST Visitorの呼び出し方を見ていきましょう。Ast抽象クラスには、以下の2つのVisitメソッドが定義されています。

説明に入る前に注意点。メソッド名は"Visit"となっていますが、Visitorパターンでいうところの"accept"メソッドのことです。なぜメソッド名がAcceptじゃないのかは不明ですが…。

ともかく、AstクラスのVisitメソッドは、AstVisitor抽象クラスを継承したクラスのオブジェクトか、ICustomAstVisitorインターフェースを実装したクラスのいずれかを引数に取ることで、ASTに対する処理を実施します。

AstVisitor抽象クラスを継承、もしくはICustomAstVisitorインターフェースを実装することで、ASTの種類に応じた巡回処理を行うクラスを、自分で定義していきます。

AstVisitor抽象クラス

AstVisitor抽象クラスは、Visitorとしての基本的な機能があらかじめ実装されています。具体的には既に以下の機能は用意されています。

  • ASTの種類に応じたVisitメソッドの定義
    すべての種類のASTに対応するVisitメソッド(50個以上)がVirtualメソッドとして定義されています(※)。例えば、IfStatementAstに対する処理を行うための、VisitIfStatementメソッドがあります。

    ※一般的なVisitorパターンでは、Visitメソッドを対象クラス分オーバーロードさせますが、PowerShellのAstVisitorは対象クラスに応じた別名のメソッドを定義する方式です。これも理由は分かりませんが、オーバーロードにするには多すぎるからかもしれません。

  • 子ノードの再帰的な巡回
    各Visitメソッドには、ASTの子ノードに対し、再帰的にVisitメソッドを呼ぶ仕掛けがあらかじめ備わっています。
  • ノード巡回の停止
    各VisitメソッドはAstVisitAction列挙型を返却します。以下のように返却する値によって、ノード巡回の継続、停止を制御できます。
    • Continue:ノード巡回を継続(デフォルト)
    • SkipChildren:子ノードの巡回を行わない
    • StopVisit:巡回を終了する
カスタムAstVisitorクラスを作成する

以上の基本的な機能を踏まえて、AstVisitor抽象クラスを実装したカスタムVisitorクラスを作ります。C#で書くのが一般的ですが、せっかくなのでPowerShell v5で追加された、クラス構文を使って書いてみましょう。

例えば、「利用しているコマンドのリストを取得する。ただし、コマンドのパラメータ内で別コマンドを呼び出している場合は除く。」というお題を解くことを考えます。

ASTのFindAllメソッドだと、配下に含まれるすべてのCommandAstを取得してしまうので、単純にはいきません。そこでカスタムAstVisitorクラスの出番です。

このお題を実現するVisitorクラスは以下のようになるでしょう。

using namespace System.Management.Automation.Language

class GetCommandNamesVisitor : AstVisitor
{
    [string[]]$CommandNames = @()

    [AstVisitAction]VisitCommand([CommandAst]$commandAst)
    {
        $this.CommandNames += $commandAst.CommandElements[0].Extent.Text
        return [AstVisitAction]::SkipChildren
    }
}

PowerShellのクラス構文において、Virtualメソッドのオーバーライドは、単に同名のメソッドを定義するだけですので、ここではVisitCommandメソッドをオーバーライドします。

プロパティとフィールドの区別はないので、コマンド名の一覧を格納するCommandNamesプロパティは上記のような定義になります。メソッド内でクラスメンバを参照する際には$thisを用います。

作成したGetCommandNamesVisitorクラスをインスタンス化し、解析対象スクリプトブロックのASTのVisitメソッドに引数として渡します。

$scriptBlock = {
    $files = Get-ChildItem -Path (Get-Location | Split-Path -Parent) -File
    $files | 
        Sort-Object -Property LastWriteTime -Descending | 
        Select-Object -First 5
}

$visitor = New-Object GetCommandNamesVisitor
$scriptBlock.Ast.Visit($visitor)
$visitor.CommandNames

実行すると、結果は

Get-ChildItem
Sort-Object
Select-Object

のようになるかと思います。

AstVisitorクラスの具体的な実装については、PSReadLinePowerShellEditorServicesにありますので、参考にしてみてください。

ICustomAstVisitorの実装

前項で述べた、AstVisitor抽象クラスを継承したカスタムAstVisitorクラスの場合、基本的な処理を実装する必要はないですし、目的とするASTクラスに対するVisitメソッドだけオーバーライドすればいいので、非常に簡便です。

ただ、本格的にPowerShellの構文解析を行いたい場合、ノードの巡回順だとか、その他もろもろをもっと細かく自分で実装したいケースが出てきます。

そういった場合にはICustomAstVisitorインターフェースを実装したクラスを作って対応します。ICustomAstVisitorインターフェースも、AstVisitor抽象クラス同様、各ASTクラスに応じたVisitメソッドが定義されているのですが、各VisitメソッドはAstVisitAction列挙体ではなく、object型のオブジェクトを返します。つまり、自分で好きなオブジェクトを返すように定義できるわけです。

Ast.Visit(ICustomAstVisitor)はAstVisitor抽象クラスを引数に取る場合と異なり、objectを返却するのですが、このとき返却されるのは、最初に実行されたVisitメソッドの戻り値になります。

ICustomAstVisitorはインターフェースですので、処理はすべて自分で定義しなくてはなりません(※)。ノードの再帰的探索も、必要ならもちろん自前で実装する必要があります(前回紹介した、JSON化スクリプトのような処理になるかと思います)。

※ISEだとインターフェースの実装を一発で行うリファクタリング機能はないので、今回みたく実装すべきメンバがたくさんある場合は、こんな感じのひな形を作るスクリプトを使うと良いでしょう。

今回はICustomAstVisitorインターフェースを実装したクラスの実例まではご紹介できませんでしたが、興味のある方は、PSScriptAnalyzerで用いられているので参考にしてみてください。

まとめ

PowerShellのASTについてきちんと解説している記事が英語圏を含めてもあまりないようでしたので、3回に渡って、一通りの基礎知識をまとめてみました。

普通にPowerShellを使っている分には、滅多に使うことはないと思いますが、たとえばPSScriptAnalyzerカスタムルールを自分で作る場合には、ASTの知識は必須になってきますので、必要に応じて参考にしていただければ幸いです。

2013/02/13

【改訂新版】Windows PowerShellポケットリファレンス:書籍案内|技術評論社 [表紙]【改訂新版】Windows PowerShellポケットリファレンス

というわけで、2/23に拙著「【改訂新版】Windows PowerShell ポケットリファレンス」が発売となります。初版は2008年に出版され、ご愛顧いただいていたのですが、このたびPowerShell 3.0 / Windows 8 / Windows Server 2012に対応して改訂新版として装いも新たに再登場となります。

今回はPowerShellの基礎知識や文法、リモート接続方法等を項目ごとに解説した「Part1 PowerShellの基礎」、PowerShell 3.0に含まれる全コアコマンドレットを分野別に分類し、その構文、パラメータと使用例を含め解説した「Part2 コマンドレット」、PowerShellから利用する頻度の高い.NET Frameworkクラスに含まれるメソッドとプロパティを解説した「Part3 .NETクラス」、Windows 8 / Server 2012に含まれる全モジュールとそれに含まれる全コマンドレット(2000以上!)のリスト(コマンドレットごとにも一言説明文付き)を掲載した「Part4 モジュール」の4部構成となっております。

PowerShell 1.0/2.0/3.0全対応で、2.0以上で対応の機能、3.0で対応の機能にはそれぞれ分かりやすくマークを入れてあります。

今回もいくつかサンプルスクリプトを掲載しており、それはサポートページでダウンロードできるようにする予定です。

392ページだった初版から大幅増ページで592ページとなり、ポケットリファレンスといいつつ本当にポケットに入るのか?というボリュームとなっていますが、きっと皆様のPowerShellライフのお役に立てるものと思います。書店等で見かけた際は是非、お手に取ってご覧になっていただきたいと思います。

2012/12/02

Japan SharePoint Group :: [大阪] JapanSharePointGroup 勉強会 #5(2012/12/01)で行ったセッションのスライドです。

SharePointユーザーの方が集まるイベントだったので、「SharePoint2013管理者シェル」についてと、これを利用するために必要となるPowerShellの基礎知識について解説しました。

非常に熱心に聞いていただいた印象で、嬉しく思います。やはりIT Proの方にとって、サーバー設定をするためのスクリプトをテスト環境で作成し、それを本番環境で一気に流して展開する、というシナリオは魅力的に思われるようです。

PowerShell 3.0やWindows Server 2012、そしてSharePoint2013などの各種サーバー製品の登場で、こういったシナリオが現実的なものとなりつつあり、以前に増してPowerShellへの関心が高まっているのを感じます。

2009/07/20

こんにちは、むたぐちです。

PowerShellによるWindowsサーバ管理術(永尾 幸夫、小鮒 通成、国井 傑、竹島 友理、牟田口 大介 著)という書籍が、ソフトバンク クリエイティブから2009/07/30に発売予定です。私は1章と2章を執筆させていただきました。

おそらく国内では初の、PowerShell ver.2を使ったスクリプトベースでのWindowsサーバー管理ノウハウの書籍です。ぜひ本屋さんでお手に取ってみてください!

PowerShell ver.2はまだCTP3ですが、いずれWindows Server 2008をはじめ各種OS用のモジュールが提供される予定です。Windows Server 2008 R2とWindows 7ではPSv2が標準機能となっており、現在これらは製品版に近いRC版が公開されていますが、これに含まれるPSv2はほぼ完成しています。そのため、このバージョンのPSv2でも本初収録のスクリプトは動作することを確認しています。そのため、PSv2正式版が公開されてもこの本は問題なく使用できると思います。

# ただ一点だけ、Enable-PSRemotingというコマンドレットがCTPでは関数だったりps1ファイルだったり何となくまだ仕様が謎だったので、winrm quickconfigを使ってありますw

目次はこのような感じです。

第1章 Wndows PowerShellという環境
第2章 PowerShellの基礎知識
第3章 プロセスの管理
第4章 ActiveDirectoryとユーザー管理
第5章 システム情報の管理
第6章 サービスの管理
第7章 イベントログの管理
第8章 ExchangeServerの管理

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/07/20/178462.aspx


Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー

Books

Twitter