てんこ製作

Tenco Works

PowerAutomateでPlannerに定期タスクを投入したい(作成編)

Plannerに定期的にタスクを作りたいというリクエストがあったので、方法を考えてみました。

今回は作ってみる編。

最終的なフロー

作ろうとしている流れは次のような感じです。

実際作ってみて考慮が足りてなかった部分も足したりしています。

  1. OneDrive上のExcelファイルの内容を一旦クリアする(Officeスクリプト)
  2. リストからアイテムを読み取る(PowerAutomate)
  3. リストの内容をExcelファイルに保存する(PowerAutomate)
  4. 保存したアイテムの中から本日対象のタスク情報を抽出する(Officeスクリプト)
  5. 3.の処理結果を読み取る(PowerAutomate)
  6. PowerAutomateからPlannerにタスクを投入する(PowerAutomate)

事前準備

SharePoint上のリスト

まずSharePointo上にリストを作ります。

項目名 種類 その他オプション
タスクルール名 1行テキスト
選択肢 1〜31 と"月末"
タスク名 1行テキスト
担当者 ユーザまたはグループ 複数選択を許可

あと適当にテストデータもいくつか突っ込んでおきます。

TeamsのPlannerでタスク登録先

Teams上でPlannerのプランを一つ作成しておきます。

プランを作成したチーム名とプランの名前は後で使うので覚えておきましょう。

詳細処理用Excelファイル

Officeスクリプトで処理させるためのExcelファイルを用意します。

  • OneDrive上に配置する
  • ShaerPointのリストを格納するテーブルを作る(作成する列はSharePointのリストに合わせて4列)
  • Officeスクリプトで対象を絞り込んだ結果を書き込むテーブルを作る(タスク名、期限、担当者の3列)

Officeスクリプトの準備

Officeスクリプトを2つ作ります。一つは「テーブルをクリア」、もう一つは「本日該当のタスク抽出」です。

まずはテーブルクリアの方から。

function main(workbook: ExcelScript.Workbook)
{
  // テーブル取得
  let tb1 = workbook.getTable("テーブル1");
  let tb2 = workbook.getTable("テーブル2");
  // オートフィルタークリア
  tb1.getAutoFilter().clearCriteria();
  tb2.getAutoFilter().clearCriteria();
  // 行削除
  if (tb1.getRowCount() > 0) {
    tb1.deleteRowsAt(0, tb1.getRowCount())
  }
  if (tb2.getRowCount() > 0) {
    tb2.deleteRowsAt(0, tb2.getRowCount())
  }
}

テーブルには名前がつけられます。ここではデフォルトの「テーブル1」「テーブル2」にしてます。

このあとの処理でオートフィルターをかけたりしているので、まず最初の段階でオートフィルターをクリアして、存在する行数分だけ削除してます。

もう一つは本日該当タスクの抽出。

このフローを毎日起動して、その日に該当するタスクだけを処理するので、この処理が必要になります。

function main(workbook: ExcelScript.Workbook)
{
  // 日付取得(本日・翌月・翌月末)
  let nowdate = new Date();
  // フィルター値と次月同日の作成(今日が月末なら月末キーワードも処理する)
  let cond:string[];
  let nextdate:Date;
  if(isEndOfMonth(nowdate)){
    //月末の場合
    cond = [String(nowdate.getDate()),"月末"];
    nextdate = MakeNextMonthEndDate(nowdate);
  }
  else{
    //月末以外の場合
    cond = [String(nowdate.getDate())];
    nextdate = MakeNextMonth(nowdate);
  }
  // テーブル1/2の取得
  let tb1 = workbook.getTable("テーブル1");
  let tb2 = workbook.getTable("テーブル2");
  // フィルター取得
  let af = tb1.getAutoFilter()
  // フィルター設定
  af.apply(tb1.getRange(), 1, {
    filterOn: ExcelScript.FilterOn.values,
    values: cond
  });
  // 行の読み取り
  let datarows = tb1.getRangeBetweenHeaderAndTotal().getVisibleView().getValues();
  //console.log(datarows);
  // テーブル2への転記
  if(datarows[0].length != 0){  //テーブルが空っぽでも要素数が1になるようなので。
    let taskdata: string[] = [];
    for (const item of datarows) {
      taskdata.push(String(item[2]));
      taskdata.push(String(nextdate.toISOString()));
      taskdata.push(String(item[3]));
      tb2.addRow(-1, taskdata);
    }
  }
}

//指定日付の1ヶ月後を返す
function MakeNextMonth(nowdate: Date): Date{
  //今月の月数を取得
  let nowMonth = nowdate.getMonth();
  //翌々月の0日(翌々月の1日の前日)=翌月の月末日をセット
  //let nextdate = new Date(nowdate.getFullYear(),nowdate.getMonth()+2,0);
  let nextdate = MakeNextMonthEndDate(nowdate);
  //もし今月の日が来月の最終日の日より小さければ、今月の日を来月にもセット(翌月の最終日のほうが小さいならキープ)
  if(nowdate.getDate() < nextdate.getDate()){
    nextdate.setDate(nowdate.getDate());
  }
  return nextdate;
}

//翌月の月末日を返す
function MakeNextMonthEndDate(nowdate:Date):Date{
  //翌々月の0日(1日の前日)=翌月の末日
  let rtn = new Date(nowdate.getFullYear(),nowdate.getMonth()+2,0);
  return rtn;
}

//月末日かどうかをチェックする
function isEndOfMonth(nowdate:Date):boolean{
  //翌月の0日(1日の前日)=今月末日
  let eom = new Date(nowdate.getFullYear(),nowdate.getMonth()+1,0);
  //年と月と日が同じだったらnowdateは月末日
  if((nowdate.getFullYear()==eom.getFullYear())&&
    (nowdate.getMonth()==eom.getMonth())&&
    (nowdate.getDate()==eom.getDate())){
    return true;
  }
  else{
    return false;
  }
}

テーブルを2つ用意して、今日処理対象になるアイテムだけ抜き出すようなことをしています。

PowerAutomateでフローを作成する

では準備ができたので、フローの作成に入ります。

繰り返し
繰り返し
変数を初期化する
変数を初期化する
1日
1日
名前:email
種類:文字列
値:(空)
名前:email...
スコープ
スコープ
場所:OneDrive for Business
ドキュメントライブラリ:OneDrive
ファイル:スクリプトを仕込んだExcelファイル名
スクリプト:テーブルのクリア
場所:OneDrive for Business...
(Excel)スクリプトの実行
(Excel)スクリプトの実行
待ち時間
待ち時間
20秒
20秒
(ShaerPoint)複数の項目の取得
(ShaerPoint)複数の項目の取得
サイトのアドレス:リストがあるアドレス
リスト名:スケジュールタスク
サイトのアドレス:リストがあるアドレスリスト名:スケジュールタスク...
Apply to each
Apply to each
以前の手順から出力を選択
以前の手順から出力を選択
(SharePoint)value
(SharePoint)value
変数の設定
変数の設定
名前:email
値:半角空白1文字
名前:email...
Apply to each
Apply to each
以前の手順から出力を選択
以前の手順から出力を選択
(SharePoint)担当者
(SharePoint)担当者
文字列変数に追加
文字列変数に追加
名前:email
値:(SharePoint)担当者Email ;
名前:email...
場所:OneDrive for Business
ドキュメントライブラリ:OneDrive
ファイル:スクリプトを仕込んだExcelファイル名
テーブル:テーブル1
タスクルール名:(SharePoint)タスクルール名
日付:(SharePoint)日 value
タスク名:(SharePoint)タスク名
担当者:(変数)email
場所:OneDrive for Business...
(Excel)表に行を追加
(Excel)表に行を追加
スコープ
スコープ
場所:OneDrive for Business
ドキュメントライブラリ:OneDrive
ファイル:スクリプトを仕込んだExcelファイル名
スクリプト:本日該当のタスク抽出
場所:OneDrive for Business...
(Excel)スクリプトの実行
(Excel)スクリプトの実行
待ち時間
待ち時間
30秒
30秒
場所:OneDrive for Business
ドキュメントライブラリ:OneDrive
ファイル:スクリプトを仕込んだExcelファイル名
テーブル:テーブル2
場所:OneDrive for Business...
(Excel)表内に存在する行を一覧表示
(Excel)表内に存在する行を一覧表示
Apply to each
Apply to each
以前の手順から出力を選択
以前の手順から出力を選択
(Excel) value
(Excel) value
グループID:プランを作成したチーム名
プランID:作成背板プラン名
タイトル:(Excel)タスク名
バケットID:To Do
期限日時:(Excel)期限
割り当てられたユーザー:(Excel)担当
グループID:プランを作成したチーム名...
(Planner)タスクを作成する
(Planner)タスクを作成する
Viewer does not support full SVG 1.1

以下気になったポイント。

リストの担当者情報

リストの担当者の項目は「ユーザまたはグループ」という種類で「複数選択を許可」としています。アイテムの内容にもよるんでしょうけど、複数の人の情報がこの中に入ることになります。

PowerAutomateの画面上で普通に「担当者Email」を使おうとすると、PowerAutomateが勝手に「Apply to each」を自動挿入してしまいます。中身が複数のデータを想定してるのでそうするのでしょうねきっと。

幸いPlannerのタスクを作成するときの担当者の項目は、セミコロン区切りのメールアドレスでいいようです。なので、変数を一個用意して、そこにメールアドレスをセミコロンつなぎで足し込んでいく部分を作って、それをExcelに保存する処理にしました。

Officeスクリプトの実行待ち

PowerAutomateのフローからOfficeスクリプトを起動できますが、どうも実行完了待ちはしてくれない模様。Officeスクリプトの完了を待つ方法も調べてみたのですが結局わからず。しょうがないので、無条件で数十秒のウエイトだけ入れました。

ちゃんと完了を待つ方法が見つかったら処理を差し替える予定。

今後やりたいこと

  • できれば全部PowerAutomateで実現したい
  • 日付指定をもっと柔軟にしたい
  • タスク作成先も選べるようにしたい

今回はここまで。