Powershellで、テキストファイルからコマンドを読み込んで、処理実行する

## 簡単なコマンド実行のエラー判定をやってくれたり、Get-xxxxコマンドを、CSV出力するPowershell

</br>
</br>

* テキストに実行コマンドと対象ホストと、出力ファイル名を書いておき、読み込ませて使います

</br>
</br>



```ps1
###### スクリプトの概要 #########################################################################

# テキストファイルに書いたコマンドリストを対象サーバーで実行し、ログを出力する

    # コマンドを記載したテキストファイルを用意する
      # CSV出力するコマンドは、GetCSV.txtにコマンド記載しておく
      # 実行系(CSV出力しない)コマンドは、DoCommand.txtにコマンド記載しておく



      # コマンドの記載方法は、タブ区切りで、
          # 1フィールド目:【コマンドの結果として出力されるCSVファイル、またはログファイルの名前になる文言】 ※空白可能
          # 2フィールド目:【コマンド】※空白不可
          # 3フィールド目:【ホスト名】※コマンド実行時判定用　　


        # 例：
        　# GetCSV.txt
          # get-commandでコマンド取得	get-command	hostAAAA

        　# DoCommand.txt
          # 自ホストにPING_10回	ping 127.0.0.1 -n 10	hostAAAA



# 引数を以下にして実行する

    # 第一引数は作業名      "全ホストにPing"
    # 第二引数は作業フォルダ "X:¥xxx¥"
　　   # ※DoCommand.txt と GetCSV.txt は、事前にここにおいてください




        # 指定しない場合は、作業名="構築作業"、作業フォルダ=C:\work となる
        Param($WORKNAME = "構築作業" , $WORKDIR = "c:\work")



################################################################################################












############ 初期変数セット #################################################################################################

# エラー時分岐あり設定
$ErrorActionPreference = "Stop"

# ホスト名取得
$HOSTNAME = Invoke-Expression -Command hostname

# 開始日時取得
$TODAY = Get-Date -Format "yyyy-MMdd-HHmm"

# 作業名
$CONTENT = "$WORKNAME"

# 作業フォルダ
$OUTDIR = "$WORKDIR"

    # 上で指定した作業フォルダ配下に「日付_ホスト名_作業名」のフォルダが出来ます。
    # ※コマンドの結果として出力されるCSVと、ログファイルの入るフォルダになります
    $OUT = "${OUTDIR}\${TODAY}_${HOSTNAME}_${CONTENT}"


# 実行してCSV出力させるコマンドを記載したテキストファイル読み込み
$COMMANDCSV = &{gc "${OUTDIR}\GetCSV.txt"}

# CSV出力させずに実行するコマンドを記載したテキストファイル読み込み
$COMMANDSET = &{gc "${OUTDIR}\DoCommand.txt"}



##############################################################################################################












######## 関数定義 ###########################################################################################

# 通常サブルーチンは一番下に定義しますが、私のいるインフラの現場ではPowershellの実行が禁止されてる場合が多く、
# コピー＆ペーストで実行させることがあるため、先に読み込ませるように上に書いています








# csv出力用コマンド読み込み関数
function csvget {

# テキストファイルをタブ区切りで1～3フィールド読み込む($a～$c)
  foreach ($i in $COMMANDCSV) {
  $a = $i.split("`t")[0]
  $b = $i.split("`t")[1]
  $c = $i.split("`t")[2]

# CSV出力コマンド実行関数に引数渡して実行
  excsv "$a" "$b" "$c"
  }

}




# 通常実行コマンド読み込み関数
function jikkou {

# テキストファイルをタブ区切りで1～3フィールド読み込む($a～$c)
  foreach ($i in $COMMANDSET) {
  $a = $i.split("`t")[0]
  $b = $i.split("`t")[1]
  $c = $i.split("`t")[2]

# 通常コマンド実行関数に引数渡して実行
  docom "$a" "$b" "$c"
  }

}




# CSV出力コマンド判定&セット関数
function excsv {
param($param1,$param2,$param3)

  if ($param3 -eq $HOSTNAME){
  
  $DESCRIPT = "【${param1}】"

  $COMMANDNAME = ${param2}

  $COMMANDLINE = {& {Invoke-Expression -Command ${COMMANDNAME}} | Export-Csv -Encoding UTF8 ${OUT}\${HOSTNAME}_${DESCRIPT}.csv}

  main ${COMMANDLINE} ${DESCRIPT}

  }

}




# 通常コマンド判定&セット関数
function docom {
param($param1,$param2,$param3)

  if ($param3 -eq $HOSTNAME){
  
  $DESCRIPT = "【${param1}】"

  $COMMANDNAME = ${param2}

  $COMMANDLINE = {& {Invoke-Expression -Command ${COMMANDNAME}} | Out-File ${OUT}\${TODAY}_${HOSTNAME}_${DESCRIPT}.log}

  main ${COMMANDLINE} ${DESCRIPT}

  }

}



# コマンド実行&エラー判定関数　※メイン
function main {
param($param1,$param2)

try {
& ${param1}
$RESULT = "${param2}：正常終了"

} catch [Exception] {
$RESULT = "${param2}：異常終了"

} finally {
write ${RESULT}
write ${RESULT} | Out-File ${OUT}\${TODAY}_${HOSTNAME}_${CONTENT}.log -Append
}

}


###########################################################################################################












#### 処理実行 ##############################################################################################################

# 作業ディレクトリ作成
try {
mkdir ${OUT}
$RESULT = "作業ディレクトリ作成：正常終了"

# 作成に失敗したら処理終了
} catch [Exception] {
$RESULT = "作業ディレクトリ作成：異常終了"
exit 100

# ログに結果を出力　異常終了してないので正常終了のログ
} finally {
write ${RESULT}
write ${RESULT} | Out-File ${OUT}\${TODAY}_${HOSTNAME}_${CONTENT}.log
}




# 関数実行
csvget
jikkou





# 終了
exit 0
##############################################################################################################################


```
###関数をまとめると以下になる

```ps1
###############################################################################################

# CSV出力するコマンドは、GetCSV.txtにコマンド記載しておく
# CSV出力しないコマンドは、DoCommand.txtにコマンド記載しておく


    # テキストはタブ区切りで、
        # 1フィールド目:【コマンドの結果として出力されるCSVファイル、またはログファイルの名前になる文言】 ※空白不可
        # 2フィールド目:【コマンド】※空白可能
        # 3フィールド目:【ホスト名】


        # 例：
          
        　# GetCSV.txt
          # get-commandでコマンド取得	get-command	hostAAAA

        　# DoCommand.txt
          # 自ホストにPING_10回	ping 127.0.0.1 -n 10	hostAAAA



# 引数を以下にして実行する

    # 第一引数は作業名
    # 第二引数は作業フォルダ。DoCommand.txt と GetCSV.txt は、事前にここにおいてください
       
      # 指定しない場合は、作業名="構築作業"、作業フォルダ=C:\work となる
        Param($WORKNAME = "構築作業" , $WORKDIR = "c:\work")


################################################################################################




############ 初期変数セット ####################################################################

# エラー時分岐
$ErrorActionPreference = "Stop"

# ホスト名取得 
# Invoke-Expression -CommandはLinuxのevalと同じ意味 hostnameを文字列でなくコマンドとして解釈
$HOSTNAME = Invoke-Expression -Command hostname

# 開始日時取得
$TODAY = Get-Date -Format "yyyy-MMdd-HHmm"

# 作業名取得
$CONTENT = "$WORKNAME"

# 作業フォルダ取得
$OUTDIR = "$WORKDIR"

    # 上で指定した作業フォルダ配下に「日付_ホスト名_作業名」のフォルダが出来ます。
    # ※コマンドの結果として出力されるCSVと、ログファイルの入るフォルダになります
    $OUT = "${OUTDIR}\${TODAY}_${HOSTNAME}_${CONTENT}"





# 実行してCSV出力させるコマンドを記載したテキストファイル読み込み　
    # &{} でコマンドを変数格納　gcはLinuxでいうcat
$COMMANDCSV = &{gc "${OUTDIR}\GetCSV.txt"}

# CSV出力させずに実行するコマンドを記載したテキストファイル読み込み
$COMMANDSET = &{gc "${OUTDIR}\DoCommand.txt"}



###############################################################################################












######## 関数定義 ###########################################################################################


# ①コマンド実行関数
function jikkou {


    # ②テキストファイルをタブ区切りで1～3フィールド読み込む($a～$c)
    foreach ($i in $COMMANDSET) {


    # split("文字列") で行を分割 `t はタブの正規表現　[n]でフィールド番号指定
  
    # タブ区切りの1フィールド目
    $DESCRIPT = $i.split("`t")[0]

    # タブ区切りの2フィールド目
    $COMMANDNAME = $i.split("`t")[1]

    # タブ区切りの3フィールド目
    $HOST_NAME = $i.split("`t")[2]



        # ③テキストの3フィールド目に書かれたホスト名が、冒頭の「変数セット」でコマンド取得したホスト名と一致したら・・・
        if (${HOST_NAME} -eq $HOSTNAME){
 
        # 出力ファイル名になる2フィールド目の文字列に【】を追加　出力ファイル名をわかりやすくするため
        $DESCRIPT = "【${DESCRIPT}】"

        # 1フィールド目のコマンドを、Invoke-Expression -Commandで、コマンドと解釈させる　(Linuxでいうeval)
        # パイプで渡してutf8でログ出力
        $COMMANDLINE = {& {Invoke-Expression -Command ${COMMANDNAME}} | Out-File -Encoding utf8 ${OUT}\${TODAY}_${HOSTNAME}_${DESCRIPT}.log}


            # ④try {} catch {} finally {} 構文でエラー判定

            # 実行
            try {

            # コマンド実行
            & ${COMMANDLINE}

            # 結果を変数格納
            $RESULT = "${DESCRIPT}：正常終了"


            # エラーの場合
            } catch [Exception] {

            # 結果を変数格納
            $RESULT = "${DESCRIPT}：異常終了"


            # 後処理
            } finally {
            
            # 結果を標準出力
            write ${RESULT}

            # 結果をログ出力
            write ${RESULT} | Out-File ${OUT}\${TODAY}_${HOSTNAME}_${CONTENT}.log -Append
            

            # ④終了
            }


        # ③終了
        }

    # ②終了
    }

  # ①終了
  }



  
# CSV出力関数
function csvget {


    # ②テキストファイルをタブ区切りで1～3フィールド読み込む($a～$c)
    foreach ($i in $COMMANDCSV) {


    # split("文字列") で行を分割 `t はタブの正規表現　[n]でフィールド番号指定
  
    # タブ区切りの1フィールド目
    $DESCRIPT = $i.split("`t")[0]

    # タブ区切りの2フィールド目
    $COMMANDNAME = $i.split("`t")[1]

    # タブ区切りの3フィールド目
    $HOST_NAME = $i.split("`t")[2]



        # ③テキストの3フィールド目に書かれたホスト名が、冒頭の「変数セット」でコマンド取得したホスト名と一致したら・・・
        if (${HOST_NAME} -eq $HOSTNAME){
 
        # 出力ファイル名になる2フィールド目の文字列に【】を追加　出力ファイル名をわかりやすくするため
        $DESCRIPT = "【${DESCRIPT}】"

        # 1フィールド目のコマンドを、Invoke-Expression -Commandで、コマンドと解釈させる　(Linuxでいうeval)
        # パイプで渡してutf8でログ出力
        $COMMANDLINE = {& {Invoke-Expression -Command ${COMMANDNAME}}  | Export-Csv -Encoding UTF8 ${OUT}\${HOSTNAME}_${DESCRIPT}.csv}


            # ④try {} catch {} finally {} 構文でエラー判定

            # 実行
            try {

            # コマンド実行
            & ${COMMANDLINE}

            # 結果を変数格納
            $RESULT = "${DESCRIPT}：正常終了"


            # エラーの場合
            } catch [Exception] {

            # 結果を変数格納
            $RESULT = "${DESCRIPT}：異常終了"


            # 後処理
            } finally {
            
            # 結果を標準出力
            write ${RESULT}

            # 結果をログ出力
            write ${RESULT} | Out-File ${OUT}\${TODAY}_${HOSTNAME}_${CONTENT}.log -Append
            

            # ④終了
            }


        # ③終了
        }

    # ②終了
    }

  # ①終了
  }





#### 処理実行 ##############################################################################################################

# 作業ディレクトリ作成
try {
mkdir ${OUT}
$RESULT = "作業ディレクトリ作成：正常終了"

# 作成に失敗したら処理終了
} catch [Exception] {
$RESULT = "作業ディレクトリ作成：異常終了"
exit 100

# ログに結果を出力　異常終了してないので正常終了のログ
} finally {
write ${RESULT}
write ${RESULT} | Out-File ${OUT}\${TODAY}_${HOSTNAME}_${CONTENT}.log
}




# 関数実行
csvget
jikkou





# 終了
exit 0
##############################################################################################################################