DBのテーブルを使っているか検索するスクリプト その1

データベースに含まれる全テーブルについて、特定のフォルダに含まれるソースコードで、テーブルが使われているかを検索。保存するという代物を用意しようと考えた。

C#でという事も考えたが、横合いからPowerShellの仕事をかっさらっていくスーパープログラマもいないことなので、学習を含めてPowerShellで実装することにする。

まずはアウトラインから考えると

  • GUIをある程度使いながらの実装
  • 何度か使う事を考え、さらにデータベースへの接続変数等を保持したいので設定を保存
  • ファイルを一つ一つ検索するのも良いがWindowsSearchなどと連携できる形にした方が早くないか

という要件で進めたいと考える。

また、普段EmEditorでのファイルからの検索を利用しているので、
これと速度的にそん色のない物ができたかどうかを判定出来れば良いという結果を出したい。

設定の保存には特殊フォルダを使いたい。
Googleで調べてみると、C#環境変数呼び出しなどが記載されているが、それではPowerShellらしくない。
何かないかと調べてみるとenv:ドライブについての記述があった。
PowerShell/環境変数一覧を表示する方法・Get-ChildItem env: - Windowsと暮らす

これはPowerShellらしくて良い。早速試してみる。

PS C:\Users\yamaguchi> get-ChildItem env:

Name                           Value
----                           -----
ALLUSERSPROFILE                C:\ProgramData
APPDATA                        C:\Users\yamaguchi\AppData\Roaming
BPADir                         C:\Program Files (x86)\Microsoft Team Foundation Server 2010 Power Tools\Best Practic...
CLIENTNAME                     Y****T****-n
CommonProgramFiles             C:\Program Files\Common Files
CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
CommonProgramW6432             C:\Program Files\Common Files
COMPUTERNAME                   Y****T****-PC
ComSpec                        C:\WINDOWS\system32\cmd.exe
ESET_OPTIONS                                                                                                        ...
HOMEDRIVE                      C:
HOMEPATH                       \Users\y****
LOCALAPPDATA                   C:\Users\y****\AppData\Local
LOGONSERVER                    \\Y****-PC
NUMBER_OF_PROCESSORS           8
OneDrive                       C:\Users\y****\OneDrive - 株式会社ぼん家具
OPENSSL_CONF                   C:\OpenSSL-Win64\bin\openssl.cfg
OS                             Windows_NT
Path                           D:\app\y****\product\11.2.0\client_1\bin;C:\Program Files (x86)\Intel\iCLS Client...
PATHEXT                        .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL
PROCESSOR_ARCHITECTURE         AMD64
PROCESSOR_IDENTIFIER           Intel64 Family 6 Model 94 Stepping 3, GenuineIntel
PROCESSOR_LEVEL                6
PROCESSOR_REVISION             5e03
ProgramData                    C:\ProgramData
ProgramFiles                   C:\Program Files
ProgramFiles(x86)              C:\Program Files (x86)
ProgramW6432                   C:\Program Files
PSModulePath                   C:\Users\y****\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerS...
PUBLIC                         C:\Users\Public
SESSIONNAME                    RDP-Tcp#80
SystemDrive                    C:
SystemRoot                     C:\WINDOWS
TEMP                           C:\Users\Y****~1\AppData\Local\Temp
TFSPowerToolDir                C:\Program Files (x86)\Microsoft Team Foundation Server 2010 Power Tools\
TMP                            C:\Users\Y****~1\AppData\Local\Temp
USERDOMAIN                     Y****-PC
USERDOMAIN_ROAMINGPROFILE      Y****-PC
USERNAME                       y****
USERPROFILE                    C:\Users\y****
VS100COMNTOOLS                 C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\
windir                         C:\WINDOWS

オブジェクト・配列ではなく、文字列として$path_app_dataに値を放り込むため&1行で記述したいがためにパイプ+カッコで囲んだうえでValueを取る。

念のためAPPDATA2などという無いキーで取った場合でもエラーは出ないのを確認。

2つ以上、要素があった場合にはエラーになるか予期しない処理になりそうだが、
今回はあくまでキー固定なのでこれで取得することにする。

PS C:\Users\yamaguchi> $path_app_data = (get-ChildItem env: | Where-Object {$_.Name -eq "APPDATA"} | Select-Object Value
).Value
PS C:\Users\yamaguchi> $path_app_data
C:\Users\yamaguchi\AppData\Roaming
PS C:\Users\yamaguchi> $path_app_data = (get-ChildItem env: | Where-Object {$_.Name -eq "APPDATA2"} | Select-Object Valu
e).Value
PS C:\Users\yamaguchi> $path_app_data
PS C:\Users\yamaguchi>

考え通りに取得できた。次はこれのエラー処理を含めてps1ファイルに記述を移す。

次はフォルダの存在確認チェック処理。
Test-Path

Test-Path -Path $path_app_data
で行けそうだが、これだとフォルダであろうがファイルであろうが、Trueを返してくる。

  • PathType オプションでContainerを選べば他の要素を含むもの、すなわちディレクトリであるかレジストリであればキーと認識する模様。(Leafであれば枝葉、ファイルなどを指すようだ)これで、

Test-Path -Path $path_app_data -PathType Container
にて条件分岐させる。

さて、ここでメッセージボックスを表示させたいと考えてみたものの、実際のところSystem.Windows.Formsを呼び出して処理させている模様。
いくつか当たってみたものの他に方法はなさそうで・・・
あまり好きではないが、これを実装してみる。

#特殊フォルダのパスを確認
if((Test-Path -Path $path_app_data -PathType Container) -eq False){
    # メッセージボックスの表示
    [System.Windows.Forms.MessageBox]::Show("特殊フォルダ" + $path_app_data + "が存在しないかアクセスできません", "致命的なエラー")
    exit 1
}

さあ、これでばっちりだ...と思うもののエラーが発生・・・

何故だっと検索すると
> 実は、PowerShellではブール値を先頭に$を付けて $TRUEや$FALSE と表します。
Bool値とNull値の表し方(PowerShell 入門) – PowerShell from Japan!! Blog

Oh...基礎の基礎やんか…。

if((Test-Path -Path $path_app_data -PathType Leaf) -eq $FALSE){
    # メッセージボックスの表示
    [System.Windows.Forms.MessageBox]::Show("特殊フォルダ" + $path_app_data + "が存在しないかアクセスできません", "致命的なエラー")
    exit 1
}

さあ、これでOK。一旦PathTypeをLeafに変更して実行してみる。

思いっきり文字化け...。


$OutputEncoding.EncodingNameがUS-ASCIIのために発生するのだという。
Hello, world! : PowerShellでコマンド実行時の文字化け

実際上記の出力を試してみると

PS C:\Users\y****> $OutputEncoding.EncodingName
US-ASCII

これを上記のサイトの記述と同様に変更してみる

PS C:\Users\y****> [console]::OutputEncoding


BodyName          : iso-2022-jp
EncodingName      : 日本語 (シフト JIS)
HeaderName        : iso-2022-jp
WebName           : shift_jis
WindowsCodePage   : 932
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : True
CodePage          : 932



PS C:\Users\y****> $OutputEncoding = [console]::OutputEncoding;
PS C:\Users\y****> $OutputEncoding.EncodingName
日本語 (シフト JIS)

気になるのはセッションが切れてからもずっとこれが残るのかという点。
一旦、PowerShellのウィンドウを閉じて開きなおしたときにどう変わるかを確認。

PS C:\Users\y***> $OutputEncoding


IsSingleByte      : True
BodyName          : us-ascii
EncodingName      : US-ASCII
HeaderName        : us-ascii
WebName           : us-ascii
WindowsCodePage   : 1252
IsBrowserDisplay  : False
IsBrowserSave     : False
IsMailNewsDisplay : True
IsMailNewsSave    : True
EncoderFallback   : System.Text.EncoderReplacementFallback
DecoderFallback   : System.Text.DecoderReplacementFallback
IsReadOnly        : True
CodePage          : 20127



PS C:\Users\y***> $OutputEncoding.EncodingName
US-ASCII
PS C:\Users\y***>

大丈夫戻っているようだ。処理の中にこれを入れるが、戻す処理は今回は無しで。
もし、途中でおかしな具合になるようであれば、Try-Catch-Finallyで漏れなく戻す処理にしてみよう。

さらに、ファイルがUTF-8のためSJISに変更する。
PowerShellの日本語文字コード: 私家版 ITプロフェッショナルの仕事術
こちらではSJISもしくはUTF-16という事だが、残念ながらVisualStudioCodeが対応できない模様。

さて、大分慣れてきた。
アプリケーション保存用のフォルダを作ることにする。

#このスクリプトのためのフォルダがあるかどうかを判断。
#無ければ作る
if((Test-Path -Path $path_my_app_data -PathType Container) -eq $FALSE)
{
    #アプリケーションデータの保存先フォルダを作成する
    #処理的にはIOを伴うのでtry-catchを入れる
    try{
        #フォルダを作る処理
        New-Item -Path $path_my_app_data -ItemType Directory
    }catch [Exception] {
        #タイミング的に作られていたら気にせず進む。
        #無ければ何らかのエラーなので、エラーメッセージを表示して終了
        if((Test-Path -Path $path_my_app_data -PathType Container) -eq $FALSE){
            # メッセージボックスの表示
            [System.Windows.Forms.MessageBox]::Show(
                    "アプリケーションデータ保存用フォルダ:" + 
                    $path_my_app_data + 
                    "の作成に失敗しました(" + 
                    $error +
                    ")", 
                    "致命的なエラー"
            )
            exit 1          
        }
    }
}

実行結果は

C:\Users\y****\Documents\powershell> c:\Users\y****\Documents\powershell\dbtable_search.ps1




    ディレクトリ: C:\Users\y****\AppData\Roaming

                                                                                                                                                                                                            Mode
              LastWriteTime         Length Name                                                                                                                                                             ----
              -------------         ------ ----                                                                                                                                                             d-----
       2017/05/25     13:36                DbTableSearch

作成には成功。オブジェクトが返ってくるのか。
これは今回は無視。プラス、同名のファイルがあった時の処理を考えたいところだが、今回は良いかな。


ずいぶんと長くなってきたので、次へ