PowerShellでプロセスチェック

# 背景
監視ソフトを導入できるほど予算がないけど、特定プロセスが稼働しているかどうかは簡易的にでも確認したい…そんなときに。

## プロセス起動確認の考え方
まずプロセス起動していることをどうやって確認するのか？について整理します。
シェルスクリプトで実現するとしたら、次の方針が多いんじゃないでしょうか。

A）psコマンドでプロセス一覧を表示して、grepで検索結果を絞り込み。結果が存在するかどうかをチェックする
B）プロセスファイルが存在するかチェックする

たとえばA)の場合は下記のような感じで。

```bash
ps -aux | grep <プロセス名> | grep -v grep | wc -l
```
パイプが多くて直感的に分かりづらいかもしれませんが、条件に合致するプロセス名を標準出力に表示、その行数をカウントすることで、当該プロセスが存在しているかを確認する理屈です。

これをWindowsのbatで実現してみるとこんな感じです。

```bat
tasklist | find "<プロセス名>"
IF ERRORLEVEL 1 GOTO CHECK_NG
```
findコマンドはfindstrコマンドでも良いです。findstrだとAND条件と正規表現が使えるので、便利です。
[findコマンド](https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/find)
[findstrコマンド](https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/findstr)


つづいてB)の場合です。たとえばpostgresqlだと起動中はプロセスIDファイルが作成されるので、そのファイル中内の先頭に記述されるプロセスIDをチェックして、そのプロセスIDに生存監視用のシグナルを送信して結果を確認する、という理屈です。

```bash
processFile="/var/lib/pgsql/data/postmaster.pid"
kill -0 $(head -1 processFile)
if [ $? -eq 0 ]; then
  # プロセス正常起動時のなんらかの処理
else
  # プロセス未起動時のなんらかの処理
fi
```
killコマンドはプロセスに対してシグナルを送信します。-0はそのプロセスが生存しているかどうかを判定するときに指定します。

[ ]←これは正確にはコマンドの一種のようですが、よくif文と組み合わせて使用されます。条件式を記述するのに使います。
この辺りは下記を参照すると分かりやすいかなと思います。
https://shellscript.sunone.me/if_and_test.html
>[] は /usr/bin 配下に存在する通常のコマンドである。正確には [ がコマンド本体で ] はパラメータということになる。[ の直後にスペースがないとエラーになるのはそのためでもある (ちなみに if 文自体も正確には文ではなくコマンドである)。

どちらかというとA)のほうが簡単なのですが、プロセスが実際に稼働しているかどうかはチェックできていないのが微妙ポイントです。

なので、できれば実際にアプリケーションにアクセスして応答をチェックするのが良いかと思います。いわゆるL7のチェックです。

## L7？
OS上で稼働しているアプリケーションが使用するプロトコルは、OSI参照モデルでいうレイヤ7に分類されるものがほとんどです。HTTPとかね。

OSI参照モデルの解説としては下記が好きです。
https://www.cisco.com/c/m/ja_jp/primer/osi-reference-model.html

アプリケーションが使用するプロトコルを使って、アプリケーションにアクセスを行う。その実行結果をチェックする。という流れです。

シェルスクリプトでは下記のようになります。チェックと結果表示処理を分離するのに、関数を使ってみました。

```bash
function httpProtocolConfirm () {
 # HTTPステータスコードを取得
 curl -m ${timeout} -LI ${checkURI} -o /dev/null -w '%{http_code}\n' -s
}

function httpProtocolResult () {
 # チェック結果を返却
 if [ $1 = '200' ]; then
    echo "チェックURI: [${checkURI}]"
    echo "チェック結果OK code:$1"
 else
    echo "チェックURI] [${checkURI}]"
    echo "チェック結果NG"
 fi
}

result=`httpProtocolConfirm`
httpProtocolResult $result

```
curlの-wオプションはHTTPステータスコードのみを取得するための整形が目的です。

## PowerShellでL7チェック

さきほどのcurlと似たようなことをPowerShellでやります。Invoke-WebRequestコマンドレットを使います。

curlと違ってInvoke-WebRequestはHTTP固定です。

```powershell
  try{
    # HTTPステータスコードを取得
    $response = Invoke-WebRequest -Uri $checkURI -TimeoutSec $timeout
    $statusCode=$response.StatusCode
  }catch [System.Net.WebException]{
    $statusCode=$_.Exception.Response.StatusCode.value__
  }
```
返却値のうち、HTTPステータスコード部分を取得するのに工夫しています。この辺りの工夫については、下記が参考になります。
https://stackoverflow.com/questions/19122378/powershell-web-request-without-throwing-exception-on-4xx-5xx


## try-catchでHTTPステータスコードを捕まえられるか？
try-catchが使えるなら、スローされた例外のプロパティを参照したらHTTPステータスコードが拾えるんじゃないかと考えたのですが、どうもシンプルな話ではないようです。

というのも、Invoke-WebRequestで存在しないホストにリクエストをしたときと、ホストは存在するけどURIが間違っている場合とで、発生する例外が異なるからです。
そういうものなのかな、、
具体的な例が整理出来たら、追記しようと思います。

## 参考書籍
シェルスクリプトを書くにあたって下記書籍を参考にしました。サンプルが付いてるので、後半が特に参考になります。はじめてシェルスクリプトを書く人は定石を学ぶためにもちょうど良いのではないでしょうか。
[ポケットリファレンス](https://amazon.co.jp/dp/4774124818/)