2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Power AutomateでOutlookの予定表からカテゴリ別に先週の工数を自動計算する

2
Last updated at Posted at 2026-03-13

何やってたっけ? ってなっていませんか

お仕事をしていると、いろんなタスクをこなしているけれど、一日の時間を何にどれくらい費やしていたかを振り返るのってなかなか難しいですね。

工数管理が厳しい会社などだと、記録や提出が求められたりするかと思います。専用のツールもあるでしょうがいちいち入力も面倒なもの。

そこで、普段会議予定が詰め込まれがちなOutlookのカレンダーに記録された予定から、カテゴリタグの機能を使い、Power Automateで先週の工数を記録しようというのが今回の試みです。

Outlookカレンダーのカテゴリ管理機能

Outlookのカレンダーは会議予定が外部から差し込まれたりと予定を管理するだけでなく、実際に行った作業を何をしていたか忘れないように記録しておくような用途にも使います。

image.png

「カテゴリの管理」をクリックすると、既存のカテゴリの名称を変更したり、新規に追加シタリが可能となります。
image.png

今回はデフォルトのカテゴリを「自学習」と「キッティング」「説明会」に変更して使ってみます。この辺りはご自身のお仕事の性質に合わせてどうぞ。
image.png

カレンダーに記録するときにはこんな感じでカテゴリタグを付けておきます。新規イベントの真ん中中央にある荷札タグのようなアイコンから選択します。カテゴリをつかうのでイベントタイトルはシンプルにできますね。
image.png

こちらがサンプルで埋めてみた先週1週間の予定です。カテゴリをつけるとその種類によって色分けされるのがよいですね。もし他のユーザーの予定も一緒に表示されるので紛らわしいという場合は、カテゴリの色を同系色にまとめると良いかもしれません。
image.png

Teams会議にはあえてカテゴリは付けませんでした。あとでどのように分類できるか確認してみます。

Power Automateから予定表を取得

Office365 outlookカテゴリのアクションのなかに、イベントの取得が2種類ありました。せっかくなのでV4のほうをつかってみます。

image.png

設定するのはカレンダーIDだけで良さそうです。
image.png

早速テスト実行してみました。取得できたJSONは1要素が1イベントです。categoriesのところに先程名前をつけたカテゴリー名が入っています。角括弧つきなので配列担っています。1つのイベントに複数のカテゴリを付けられるということでしょうね。
image.png

やはり複数付けられます。いちおう複数のカテゴリがついていた場合に、どれが要素の先頭になるのかも確認しておきます。
image.png

表に出ているカテゴリが配列の先頭になるようです。イベント編集画面でカテゴリはあとから追加したものがメインになるようで、入れ替えはできませんでした。複数カテゴリを使って、かつメインを決めたいときには最後に設定するような小技が必要でした。
image.png

先週分の予定だけを取得するには?

取得したイベントのJSON情報を「アレイのフィルタ」にかけてもよいのですが、取得してくるイベントJSON自体を少なくしたほうが効率がよいので、ODataフィルタークエリを試してみます。

先週の予定だけを OData フィルタークエリで取得したい場合は、OData が相対日付関数をサポートしていないため、「先週の開始日時」と「先週の終了日時」 を事前に変数や式で設定して、それを OData フィルターに埋め込む必要があります。

実行日の全集の月曜日はこのように式を書きます。

先週月曜日
formatDateTime(
  addDays(
    utcNow(),
    sub(-7, mod(add(dayOfWeek(utcNow()),6),7))
  ),
  'yyyy-MM-ddT00:00:00Z'
)

同じくこちらは先週の金曜日

先週金曜日
formatDateTime(
  addDays(
    utcNow(),
    sub(-3, mod(add(dayOfWeek(utcNow()),6),7))
  ),
  'yyyy-MM-ddT23:59:59Z'
)

今月の1日以降を求めたい場合はこちら

formatDateTime(
  utcNow(),
  'yyyy-MM-01T00:00:00Z'
)

それぞれ「作成」アクションの式にいれて、適当な名前を付けておきます。
image.png

こんどは、「イベントの取得(V4)」トリガーのフィルタークエリに以下のように記載します。

先週の月曜から金曜
start/dateTime ge '@{outputs('先週月曜')}' and start/dateTime lt '@{outputs('先週金曜')}'
今月1日から先週金曜
start/dateTime ge '@{outputs('先週1')}' and start/dateTime lt '@{outputs('先週金曜')}'

image.png

JSONを分析する

こんどは取得できたデータの方を分析してみましょう。

カテゴリーがついていない場合は?

さきほどカテゴリーはどのように記録されているかは確認しました。カテゴリーが何も設定されていない場合には、空の配列になっています。
image.png

空の配列だけを抜き出すには、「アレイのフィルター処理」アクションを使って、左辺に以下の式。右辺を0
にします。length関数は配列の数を取得することができます。

左辺
length(item()?['categories'])

image.png

各イベントのendからstartの時刻をtick関数を使って引き算し、ミリ秒を分に変換するには以下のような式を書きます。これを「選択」アクションをつかってまずは配列にして確かめてみます。

工数
div(
    sub(
        ticks(item()?['end']),
        ticks(item()?['start'])
    ),
    600000000
)

image.png

結果はこんな配列になります。
image.png

配列の要素の合計を出すには?

配列の各要素の中にある数字を合計するには、もちろんループを回して足し込んでもよいのですが、ここで以前に私が記事を書いた爆速加算法が活躍します。

この方法は、Power Automateに標準ではついていない配列の要素の合計を、xmlの機能をつかって行うというものです。

まずは、先程の「選択」アクションをマップモードに切り替えます。
image.png

式以外の部分を除去します。
image.png

「作成」アクションを追加して、配列化した選択をこのようなJSONの形にします。

作成JSON
{
  "root": {
    "Numbers": @{body('選択')}
  }
}

image.png

テスト実行してこのようなJSONの形担っていればOK!
image.png

わかりにくくなる前に作成の名前を変えておいて、最後の「作成xml」には下記のように前のJSONをxml関数で囲みます。

作成XML
xml(outputs('作成JSON'))

image.png

すると、結果はHMTLのタグで囲まれた要素になります。
image.png

最後に、以下のxpath関数というのを使うと、要素の合計を一瞬で計算できるのです。

作成合計
xpath(outputs('作成XML'),'sum(/root/Numbers)')

image.png

image.png

設定したカテゴリごとの工数は?

カテゴリなしについて工数の合計を取得することができたので、他のカテゴリについてもスコープにまとめてコピーすれば、アレイのフィルタ部分を修正するだけで各カテゴリの工数合計を取得することは容易です。
image.png

でも、それでは面白くないので、用意してあるカテゴリも自動で取得してやることにしましょう。
「Outlookのカテゴリー名を取得する」というアクションがありました。
image.png

設定項目はなにも必要なく、作成済みのカテゴリが配列として返ってきました。
image.png

このカテゴリーにマッチするものをイベントの塊であるJSONからフィルターして、先程の合計計算をすればよいということになります。

繰り返しの処理をおこなうので、「それぞれに適用する」を使います。

image.png

さっき作ったスコープをApply to eachの中にコピーして再利用します。
ここからが少しトリッキーです。
スコープとフィルターの名前は相応のものに変えました。
スコープの一番上に、新たに「作成」を追加して、名前を「カテゴリー」としました。
各項目には下記の式をセットしてください。

Apply to eachの「以前の手順から出力を選択」
@{body('Outlook_のカテゴリ名を取得する')}
カテゴリー
@{items('Apply_to_each')?['displayName']}
カテゴリーフィルタ、差出人
@outputs('イベントの取得_(V4)')?['body/value']
カテゴリーフィルタ、左辺
@first(item()?['categories'])
カテゴリーフィルタ、右辺
@outputs('カテゴリ')

image.png

これでテスト実行してみると、Apply to each はOutlookで設定されているカテゴリーの数だけループします。
カテゴリーフィルターの差出人は全イベントJSONなので、そのなかのCategories配列の最初の項目と、ループ1回ごとに取り出されたカテゴリー名(作成:カテゴリを見るとそのループの回でなにかがわかります)とを比較しています。

その後の計算処理は再利用されていることが、実行してみるとわかったと思います。
image.png

結果をループごとに変数に記録していく

各カテゴリーごとの工数合計は取得できたものの、このままではどこにも記録されません。
「作成」で用意した値はみずもの。何かをためていくには変数を利用します。今回のようにカテゴリー名とその値という組み合わせを扱うには、やはり配列(アレイ)が使いやすいです。

最初の方に「変数を初期化する」を追加して適当な名前の変数を種類「アレイ」で作成します。
image.png

Apply to eachの中の合計処理のスコープの下に「配列変数に追加」アクションを追加します。

image.png

先程初期化した変数を選択したら、値には以下のような波括弧でくくったライブラリー形式を設定します。

配列変数に追加
{
"カテゴリ":@{outputs('カテゴリ')},
"工数":@{outputs('作成合計_2')}
}

追加した結果が確認できるように、デバッグ用の「作成」をループの外に置いて、カテゴリと工数合計変数をセットしておきました。
image.png

テスト実行してみると、とってもいい感じにカテゴリと工数合計の1組が配列として変数に記録されていることがわかります。
image.png

カテゴリなしスコープの結果もこの配列変数に追加すればよいですね?
image.png

カテゴリなしも配列の仲間に加わりました。
image.png

Teams会議の合計時間も知りたい

ここまでで、各カテゴリと、カテゴリが付けられていない予定の工数を合計して配列で管理できるようになりました。
全体の工数のうち、会議であった時間も管理しようと思います。
イベントの取得でとってきたJSONの中身を見れば、locationという項目を見ればTeams会議であることはわかりますが、言語によってここの文字列は変わってしまいます。

Teams会議であれば、bodyの中身に「https://teams.microsoft.com/」 という文字列が含まれているのでこれをつかって判定できそうです。

カテゴリなしスコープをコピーして、名前を適当に書き換えます。
最初のフィルター部分は、詳細設定モードでこのように記述します。

Teams会議フィルター
@equals(contains(item()?['body'], 'https://teams.microsoft.com/'), true)

最後に配列に追加する際に、カテゴリ名を「内Teams会議」というように編集しておきます。
image.png

Teamsに投稿する

これで配列変数のなかにすべてのカテゴリと、Teams会議で使った工数合計が集まりました。
Teamsチャットで自分に送信してみましょう。
image.png

あとは、配列変数を「HTTPテーブルの作成」アクションに渡して、その結果をTeamsの投稿アクションのメッセージに追加してやるだけです。期間を表示したければ「作成」として持っていますから使えます。フォーマットがイケてないのは適当に変換してやるとよいでしょう。
image.png

とりあえず、分数ではありますが、合計を投稿することができました!
image.png

時間の範囲がUTCなのはご愛嬌。
表示する際に日本時間に変換したいようでしたら、こちらを参考にしてください。

私もいつもメモ代わりに使っている記事です。
「モカ式 utc」
で検索すると出てきますので、覚えておくと便利ですよ (宣伝です)

あとは任せた!

カテゴリと合計の数が取得できているので、あとはループを回してSPOリストなり、Excelのテーブルなりに行追加してくことは簡単です。

トリガーを定期実行にしておけば、なんにも考えずに前週や一ヶ月の工数が計算できてしまいます。もちろんちゃんとカテゴリ設定をしたり、カレンダーに入力しておけばですが。それはまた別のお話。

まとめ

Outlookの予定表にあるカテゴリ機能をつかって、Power Automateで取り出すのを試してみました。

  • 合計の計算はxmlへ変換することで実行できます。ちょっとややこしいですが。
  • 今回はカテゴリの種類を取得して、それぞれをループで回してフィルタの条件にしてみました。これもちょっと複雑ですが、ループもフィルターもitem()をつかうと要素が取れるのは同じと理解していると使いどころがあります。
  • フィルターのなかで外側のループの要素をつかうには、item() ではなく、どのループの値を扱うのかを指定できるitems('ループの名前')を使うのがポイントです。
  • 配列が空であることを調べるにはlength関数を使います。配列要素の数がわかるので、比較は0とか数字になります。
  • contains関数は配列に要素が含まれているかを調べる関数で、結果はTrueかFalseになります。この関数はフィルターアクションと組み合わせると絶大な威力を発揮します。クラウドフローの爆速化には欠かせない関数です。
  • categoriesの値は配列なので、その先頭要素だけをつかうためにfirst関数も使いました。比較をする際にうまく行かない場合は、配列をそのまま比較対象にしていることが多いです。気が付かないとハマりますね。

こんな人が書いてます。

こちらの記事はランゲルハンス島のDDさんが紹介しました。ブログでクラウドフローのTIPSのようなものを書いたり、Qiita記事を書いたりしていますのでご贔屓に。
フォローやいいねいただけると嬉しいです。
関西のPowerPlatform系の勉強会にときどき出没しますので、気軽に声をかけていただけると喜びます!

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?