2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PythonでTeams電話の操作を自動化してみる

Last updated at Posted at 2021-11-15

やりたいこと

やりたいことはシンプルです。
Teams通話の転送先を、出勤時に「通話グループまたは代理人」に設定し、退勤時は「ボイスメール」に戻す、というもの。
実際にはアカウント毎に各チーム分、この操作が必要になるため、それが毎日となると負担も大きいわけです。
image.png
要は留守電なので、下の動画で解説してる方法でも実現できそうですが、Teams(というかマイクロソフト製品全般)にそこまで詳しくない上に、マイクロソフトのパートナー会社に聞くこともできず、よく分かりません。

Teamsの設定をコマンドで行うなら、PowerShellから Connect-MicrosoftTeams で接続しゴニョゴニョするのが定番と思うのですが、転送先に相当するオブジェクト/プロパティが見つからないのです。探し方が悪いだけかも。

ちまちま調べるより、サーバで書いちゃった方が早そうなので、Python/Flaskベースで「Teams留守電切替アプリ」を作ってみました。

実装

サインイン

Teamsはデスクトップ版もありますが、SeleniumでWeb版Teamsにサインインします。

driver.get('https://teams.microsoft.com')
WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located)
driver.implicitly_wait(30)
driver.find_element_by_id('i0116').send_keys(user_id)  # ユーザID
driver.find_element_by_id('idSIButton9').click()       # 次へ
driver.find_element_by_id('i0118').send_keys(passwd)   # パスワード
time.sleep(3)
driver.find_element_by_id('idSIButton9').click()       # サインイン

2要素認証

2要素認証が必須のアカウントでは pyotp でワンタイムパスワードを生成します。

import pyotp

totp = pyotp.TOTP(secret_key)
driver.find_element_by_id('idTxtBx_SAOTCC_OTC').send_keys(totp.now())  # コード
driver.find_element_by_id('idSubmit_SAOTCC_Continue').click()  # 検証

エラー時の再試行

もしこんな画面になったら、再試行をクリックさせます。
image.png

oops_btn = driver.find_elements_by_class_name('oops-button')
if len(oops_btn) > 0:
	driver.execute_script('arguments[0].click()', oops_btn[0])

通話設定画面

通話設定の画面を出します。

driver.find_element_by_id('settings-menu-button').click()  # 設定
driver.switch_to.active_element.send_keys(Keys.ENTER)
driver.find_element_by_xpath('//*[@id="options-dialog-focus-default"]/div/span[text()="通話"]').click()  # 通話
driver.find_element_by_id('immediate-dropdown-btn').click()  # 転送先ドロップダウン

入力に応じて転送先を切り替えます。

if voice_flag:
	driver.find_element_by_xpath('/html/body/ul/li/a[text()="ボイス メール"]').click()  # 転送先をボイスメールに設定
	print('Switch to enable voice mail')
else:
	driver.find_element_by_xpath('/html/body/ul/li/a[text()="' + forward + '"]').click()  # 転送先を通話グループ/代理人に設定
	print('Switch to disable voice mail')

例外処理

何か異常があれば、スクリーンショットを取り、スタックトレースの文字情報を重ね合わせた上でフロントエンドに返します。
再試行するか手動で操作するかは、ユーザがWebアプリケーションから応答します。
画像の加工は opencv-python で行いました。

import cv2
import traceback

except Exception as e:
	driver.save_screenshot(screenshot_file)
	img = cv2.imread(screenshot_file)
	exc = traceback.format_exc()
	for i, line in enumerate(exc.split('\n')):
		cv2.putText(img, line, (10, 100 + i * 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 160, 240), 1, cv2.LINE_AA)
	cv2.imwrite(screenshot_file, img)
	print(exc)

成功/失敗を判定し、いらすとやで拾った透過画像をマスク処理してスクリーンショットと合成します。
image.png
画像の合成は、こちらの記事を参考にさせていただきました。

失敗の通知

Incoming Webhook でWebフックを作成し、curlコマンドで通知しました。

Bashスクリプト
FLAG=$1
while read CLIENT; do
	if /usr/local/bin/foo.py $CLIENT $FLAG; then
		echo "$CLIENT($FLAG) Success."
	else
		if [ $FLAG -eq 0 ]; then
			TEXT="留守電の解除に失敗しました。クライアントは「$CLIENT」です。"
		else
			TEXT="留守電の登録に失敗しました。クライアントは「$CLIENT」です。"
		fi
		curl -X POST -d '{"text":"'$TEXT'"}' https://foo.webhook.office.com/webhookb2/XXXXXX
	fi
done <<EOF
foo
bar
baz
qux
quux
corge
grault
EOF

image.png

2
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?