Windows環境からSlackのチャンネルにWebhookでPOSTした

記事タイトルとURLをコピーする

こんにちは。マネージドサービス部MS2課の塩野です。

みなさんslack使ってますかー?

Slackのチャンネルに自動的にPOSTするBotを作りたくてWebhookのテストをしていたのですが、curlコマンドサンプル例に沿ってコマンドを実行しても動かなかったり文字化けしたりで四苦八苦してしまったので、その対応策を書きました。

Slackボット用のWebhook入手

注意点

SlackのWebhookには以下の2つの手法がありますが、カスタムインテグレーションでのIncomming Webhookは現在非推奨となっておりますのでご留意ください。

カスタムインテグレーションでのIncomming Webhook(非推奨)

以下のページからSlackのWebhook設定ができます。 slack.com

チャンネルへの投稿より通知をおこないたいチャンネルを選択し、Incomming Webhookインテグレーションの追加をクリックします。

Slack Appを作成して利用する

以下のページからSlack Appを作成ができます。 api.slack.com

1.Create an appをクリックします。

2.Form scratchをクリックします。

3.App Nameを入力し、Pick a workspace to develop your app in:の項目からワークスペースを選択し、Create Appをクリックします。

4.Featureメニューの中のIncomming Webhookを開き、Activate Incomming Webhookを有効化します。

5.項4の画面の下にあるWebhook URLs for Your Workspaceの項目より、Add New Webhook to Workspaceをクリックします。

6.配信するチャンネルを選択して許可するをクリックします。

7.WebhookのURLまたはcurlコマンドをコピーして使います。


curlコマンドについて

Windowsの場合curlコマンドを使うと、Powershellのinvoke-webrequestのエイリアスかC:\windows\system32\curl.exeのどちらかとして動作する。よりlinuxに近い挙動を求める場合はcurlではなくcurl.exe と記載する必要があります。

そしてコマンドプロンプトからcurl.exeなどでメッセージを送信した際によくおこる問題が文字化けである。Linuxなどの場合でURLエンコードで解決できる場合はcurlのオプション --data-urlencode を使用することで正常に送信できるが、Windowsの場合、OSに起因する文字コードの問題が別にあり --data-urlencode でも文字化けしてしまう。解決方法としては送信するメッセージをファイルに落として、ファイル側で文字コードを指定するという手段もあるようだが、今回は別の方法を使います。

解決策

前項でcurlはinvoke-webrequestのエイリアスになる場合があると記載していますが、Windowsの場合はinvoke-webrequestを使う方が簡単なためこちらを紹介します。

1.slackにメッセージを送る際に使用しているcurlのオプションを確認します。

curlのサンプルコマンド
curl -X POST --data-urlencode "payload={\"channel\": \"#<チャンネル名>\", \"username\": \"webhookbot\", \"text\": \"これは webhookbot という名のボットから #<チャンネル名> に投稿されています。\", \"icon_emoji\": \":ghost:\"}" <WebhookのURL>

■使われているオプション
-X :HTTPメソッドの指定。メソッドはPOST
--data-urlencode:後に続く文字列をURLエンコードし、POSTデータとする。文字列はファイルなどを指定することもできる。

使われているのはHTTPメソッドとPOSTするデータのエンコードのみでしたね。

2.curlのオプションをpowershellで表現してみます。
使われているオプションはHTTPメソッドとURLエンコードのため、Powershellでは以下のコマンドを使用します。

■URLエンコード
Add-Type -AssemblyName System.Web
[System.Web.HttpUtility]::UrlEncode("ここに文字列が入る"))

■HTTPメソッド
Invoke-WebRequest コマンドの -Method POST を使用します


3.コマンドの置き換え
以下のコマンドで送信できました。

#■モジュールの読み込み
Add-Type -AssemblyName System.Web

#■メッセージ・送信用BODYの作成
$msg="これは webhookbot という名のボットから #<チャンネル名> に投稿されています。"
$body_base='payload={"channel": "#<チャンネル名>", "username": "webhookbot", "text": "@msg-body@", "icon_emoji": ":ghost:"}'
$msg_body=$body_base.replace("@msg-body@",[System.Web.HttpUtility]::UrlEncode($msg))

#■メッセージの送信
Invoke-WebRequest -Method POST -Body $msg_body -uri "<WebhookのURL>"

注意点としては、payload=の後の \" 部分のエスケープ文字の扱いをどうするか(ここではシングルクオーテーションで省略処理している)と、URLエンコードをメッセージ本文だけに適用するの2点です。

総括

Webhookで送信テストを行う機会は多いものの、毎回Linux環境を立ち上げたりこのためにわざわざWindows Subsystem for linuxを準備するのも大変なので、Slackボット以外でWebhookを使う場合でもBody部分をちょっと書き換えたりするだけで使い道がありそうな気がします。

どなたかのお役に立てれば幸いです。

◆ 塩野 正人
◆ マネージドサービス部 所属
◆ X(Twitter):@shioccii
◆ 過去記事はこちら

前職ではオンプレミスで仮想化基盤の構築や運用に従事。現在は運用部隊でNew Relicを使ってサービス改善に奮闘中。