スポンサーリンク

GooglaAppScriptでSlackにメール通知してみる(応用編)

こんにちわ。ヤスムラです。

前回メール本文をSlackに通知するGASを作ってみましたが、今回は応用編でメール本文から必要な部分だけを抜き取ってSlackに投稿してみたいと思います。

この記事はこんな方にオススメ

Slackを利用している方
Gmailを使用している方
メール内容をSlackに通知したい方

基本編を見ていない方は以下からお読み下さい。

必要な部分のみ抽出する方法

今回は正規表現を使って本文から必要な単語だけ抽出します。正規表現を使えば文字列のパターンマッチングを使って該当する文字列を抽出することが出来ます。使い方については以下サイトを参考にさせて頂きました。特に正規表現をチェックするサイトがとても役に立ちました。

【GAS 基礎】正規表現を扱うRegExpオブジェクト・Stringオブジェクト
正規表現を扱うRegExpオブジェクト正規表現とは正規表現とは、文字列のパターンを表現するための方法です。以前にスプレッドシートのクエリ関数の記事でも紹介させてもらったことがありますが、a~Z、0~9などの通常の文字と、[]や{}などの特殊
正規表現チェッカー | WWWクリエイターズ

今回通知するメール

今回はMicrosofot Defender for Endpoint(以下MDfE)から通知される脆弱性情報のメールを分解してSlackに通知されるようにしたいと思います。

MDfEから脆弱性情報を通知させる方法は以下記事を参考にして下さい。

Microsoft Defender for Endpointを使ってクライアントPCの脆弱性を通知してみた|ヤスムラ
最終更新日:2021-12-23 MDMを使って会社の端末を管理している方が多いと思います。弊社もMDMを導入していますがアプリケーションの完全な自動更新までまだ手を回っておらず、せめて緊急度の高い脆弱性だけでも把握できる様にしたいと思い設...

使用するGAS

今回使用するGASはこちらです(☆の部分は適宜変更して下さい)

function myFunction(){

    const labelname = 'complete' //☆ラベル名(事前に同じラベルを作成)
    const subject = "New vulnerabilities notification from Microsoft Defender for Endpoint" //☆件名
    let query = 'subject:' + subject  + ',-label:' + labelname;

    //対象メールの二次元配列を取得&Slack通知
    let gmail = getGmail(query,labelname);  
}

function getGmail(query,labelname) {

  //☆Slack通知用Webhook
   const webhookurl = 'https://hooks.slack.com/hogehoge';

  //Gmailの履歴からマッチするメールを一覧化
   let threads = GmailApp.search(query); 
   //let gmailInfo = new Array();  

  //一覧化したメールの件数分繰り返し 
   threads.forEach(function(thread) {

    // スレッド内のメール一覧を取得
    let messages = thread.getMessages();


    // 対象メールに処理済ラベルを追加(次回以降通知させないようにするため)
    const label = GmailApp.getUserLabelByName(labelname);
      for (let n in messages) {
        thread.addLabel(label);
      }

    //メールを一つずつ取り出す
      messages.forEach(function(message) {

    //メール本文
      let plainBody = message.getPlainBody();
      Logger.log(plainBody);

      // メール本文からCVEを抽出
        let cve = plainBody.match(/Vulnerability Name: (.*)/g);
        let cve_allStaffs = cve.join("\n");   //配列を改行させる
        let cve_replace = cve_allStaffs.replace(/Vulnerability Name: /g, ""); //不要な文字を除去
        Logger.log(cve_replace)
      
      //配列の数を取得
        const counta = cve.length
        let severity_cvss = plainBody.match(/Severity: ([\s\S]*?)Exposed devices/g);
        let severity_cvss_array = severity_cvss.map((value) => {return value.replace(/Severity:/g, "").replace(/CVSS:/g, " / ").replace(/Exposed devices/g, "").replace(/\s/g, "")});
        let severity_cvss_array_join = severity_cvss_array.join("\n");   //配列を改行させる
        Logger.log(severity_cvss);

      // メール本文からcvssを抽出
        let cvss = plainBody.match(/CVSS: ([\s\S]*)Exposed devices/g);
        Logger.log(cvss);

      // メール本文から対象デバイス数を抽出
        let device = plainBody.match(/Exposed devices: (.*)/);
        Logger.log(device);

      // メール本文からソフトウェア名を抽出
        let software = plainBody.match(/Affected products: (.*)/);
        Logger.log(software);

      // メール本文からMicrofostDefenderのリンクURLを取得[対象ユーザの確認]
        let executionuser = plainBody.match(/View recommendations >>([\s\S]*)Go to related vulnerabilities/s);
        Logger.log(executionuser);

      //Slackの投稿メッセージ作成
        let blocks = [
           {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "[脆弱性情報]\n以下脆弱性に該当する社内PCが検知されました\n社内IT担当は影響度と利用者を確認の上、必要に応じて対応願います\n\n"
            }
          },
          {
            "type": "section",
            "fields": [
              {
                "type": "mrkdwn",
                "text": "*ソフトウェア名*\n" + software.splice(1)  + "\n"
              },
              {
                "type": "mrkdwn",
                "text": "*対象デバイス数*\n" + device.splice(1) + "\n"
              },
              {
                "type": "mrkdwn",
                "text": "*CVE番号*\n" + cve_replace
              },
              {
                "type": "mrkdwn",
                "text": "*驚異/脆弱性スコア*\n" + severity_cvss_array_join
              }
            ]
          },
           {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "IT管理者は以下リンクから詳細確認願います\n" + executionuser[1] + "\n"
            }
          },
        ];
        let payload    = {'blocks': blocks};
        let options    = {'method' : 'POST', 'payload': JSON.stringify(payload)};

       //Slack投稿
        UrlFetchApp.fetch(webhookurl, options);
    });
  });
   return(gmailInfo);
}

スクリプトの内容を簡単に説明するとまず以下の部分でメール本文をプレーンテキストで抽出します。


次に抽出した本文から使いたい部分を正規表現で抽出します。

あとは抽出した文字をSlackに通知させるように配置して完了です。

手順

スクリプトの内容以外は基本編と同じなのでそちら参考にGASとSlackを設定して下さい。うまくいけば以下のような通知BOTを作れるはずです。

画像に alt 属性が指定されていません。ファイル名: image-14-1024x419.png

注意点

当然ですがメール本文の内容が少しでも変わってしまうと、スクリプトが正しく動かなくなってしまうのでそこだけ注意です。あと今回のMDfEのアラートであればPower Automateでも似たようなことが出来るようです。あいにく当方は検証していませんが気になる方は以下参考にしてみて下さい。

Power Automate コネクタを使用してイベントのフローを設定する方法
Microsoft Defender for Endpoint Flow コネクタを使用して、テナントで新しいイベントが発生するたびにトリガーされるフローを作成します。

まとめ

API連携でSlack通知できればそれが一番確実なんですが、どうしてもメール通知しか出来ないサービスはあります。またSlack標準のメール機能だと「本文全体が通知される」&「折りたたんだ状態で表示される」ので見にくいんですがこの方法なら必要な情報だけ表示させることが出来ます。

このやり方を理解すれば、いろんなメールに応用出来るのでぜひ色々試してみて下さい。

最後に、当方は副業情シスとして活動もしています。以下サイトに詳細記載しておりますので、もしご興味がある方いればお気軽にお問い合わせ(またはDM等)ご連絡お待ちしております。

Corporate-Engineer

また本記事について質問や・誤り等あればご連絡いただければ幸いです。

ヤスムラ

◇基本情報
▶IT業界で働くアラフォー
▶一児の父

◇経歴/実績
▶2020年スタートアップに情シスとして転職

▶2021年に副業(情シス x ITコンサル)を開始して初年度売上100万円達成
▶2022年ITフリーランス向け副業コミュニティ(Slack)開設
▶2022年に副業売上300万円達成
▶2023年に副業売上600万円達成

ヤスムラをフォローする
Google情シス自動化
スポンサーリンク
ヤスムラをフォローする
ITでお金を豊かにするブログ

コメント

タイトルとURLをコピーしました