はじめに
こんにちは。
リブセンスでコーポレートテクノロジーソリューション室(以下CTS)という部署に所属しております、黒木と申します。
今夏、従業員の予定管理の利便性向上を目的とし、今まで使用しておりましたGaroon(サイボウズ社提供のグループウェア)からGoogleカレンダーへ移行しました。
結果的には予定管理の完全移行を実現し、更にはWEB会議システムとの連携もできましたが、
いくつかトラブルも発生しましたので、事例を交えながらご紹介します。
CTSの業務内容
まずは私達CTSメンバーが「何をやっているか」というところから説明させて頂きます。
CTSの業務は非定型業務と定型業務2つに分かれます。 非定型業務は以下のような業務です。
各種PJの推進
システムリプレースや導入等の各種PJに関わる、製品選定・導入設計・構築など障害対応
社内インフラ、ネットワークの障害対応
かなりざっくりとした書き方ですが、社内の業務改善に対して、 前提条件や制約に一旦発想をとらわれず、ゼロベースでの検討を心がけています。
定型業務は今外部へのアウトソーシングを進めておりますが、以下のような業務になります。
アカウント管理
入社時のアカウント発行、異動等による権限変更、退職時のアカウント削除などPCセットアップ
入社時、PC入替時のPCセットアップヘルプデスク
PCやシステム関連の問い合わせ対応社内インフラ運用
サーバー、ネットワーク機器等の監視
私達がやっているいわゆる「情シス」「社内SE」と呼ばれる業務は、定型業務がかなりボリューミーで、どうしてもその安定稼働や現状維持に力をいれがちになると思います。
しかし、リブセンスのCTSは非定型業務に力を入れています。
保守運用やカスタマーサポートに甘んじることなく、自主的に社内の課題を定義し、より快適な環境を構築していくチームです。
定型業務のほとんどをアウトソーシング化できているので、非定型業務にかける時間を確保し、
今後さらなるリブセンスメンバーの生産性向上や業務効率化、モチベーション向上まで図りたいと考えています。
今回のブログのテーマである「Googleカレンダーへの移行」は非定型業務に入ります。
移行の目的は?
なぜGaroonを使用していたのに、Googleカレンダーへの移行を選んだのかご説明します。
- ユーザーエクスペリエンスの向上(モバイル、カスタマイズ)
- 既に数名Googleカレンダーを使用しているユーザーがおり、ツールを統一させる事での管理工数削減
- 各既存ツールとのAPI連携により生産性の向上(SlackやZoomとの連携が可能になるなど)
→会議室へのZoomRooms導入が決定しており、Googleカレンダーと連携させる事でより利便性が向上できる - コスト削減(GoogleカレンダーはGsuiteの現契約で使用できます)
のような理由から移行を決定しました。
どのような計画を立てたか?
- 調査・計画
- GoogleカレンダーとGaroonの機能比較
- Garoonでユーザーが使用している機能をGoogleカレンダーでどう補完するか
- 移行方法調査・検証
- 懸念点精査
- 掲示板やファイル管理を使用している総務/労務への共有及び懸念点洗い出し(4月~5月頭)
- 移行作業の懸念点(5月中)
- 事前準備
- 全社への共有(6月)
- 移行作業のスケジュールリスト化
- 運用開始(7月1日)
移行方法の検討
限られた工数で対応を進めるために、なるべく簡単で前例のある方式を取り入れ実施できる方法を調査しました。
掲示板
→Googleカレンダーでは機能を満たせないので、既に社内で利用しているConfluenceに移動従業員番号・内線・雇用形態・フリガナ
→Google Apps Managerにて流し込みバッチを作成し、Googleディレクトリへ反映。- 既に登録されている予定などのカレンダーデータ
→「Garoon SOAP APIでデータ抽出→データ成型→Google Calendar API」を検討するも少々手間を感じたので、もっと簡単な方法を探しました。
→Garoon Developper networkにてGGsyncなるツールを発見
→CTS内で検証したところ、何の問題もなく移行出来ることが判明!
(しかし後に理解(検証)不足を後悔することに...)
移行手順
カレンダーデータ以外はすぐに実施可能だったため、 事前に準備し移行日後の運用変更のみで完了。
カレンダーデータについても、GGsyncで簡単にデータ移行が出来た事で、当初のスケジュールを前倒しする事が出来るようになりました。
Garoonユーザーエクスポートインポートにより各ユーザーのパスワードを変更
各会議室、備品リソースをGGsncにて移行実施
退職者はCTSが登録者として登録するようAccessにて加工
3.GGsync「GGsync.properties」の値を各ユーザーに変更後バッチにて順次実施
ユーザーリスト一覧を読み込み「GGsync.properties」値を変更後、
実行するスクリプトをPowerShellで作成
cd C:\GGsync1 # .\GGsync.db が存在するかを確認 $result = (Test-Path ".\GGsync.db") if($result){ #ファイルが存在する場合はこちらが実行されます。 #Remove-Item .\GGsync.db }else{ #ファイルが存在しない場合はこちらが実行されます。 } #Remove-Item .\GGsync.d #Garoonエクスポートデータの取り込み $csv = Import-Csv .\Torikomi.csv -Encoding Default $CLASSPATH = "-jar C:/GGsync1/GGsync.jar C:/GGsync1" $ArryNo = 0 while ( $csv[$ArryNo]."E-mail" -ne $null ) { $strMailaddr = $csv[$ArryNo]."E-mail" $strLogin = $csv[$ArryNo].新ログイン名 $strPW = $csv[$ArryNo].PW $data=Get-Content .\Master_GGsync.properties $data[6]="google.calendar.id=" + $strMailaddr $data[31]="garoon.account=" + $strLogin $data[34]="garoon.password=" + $strPW $data | Out-File .\GGsync.properties -Encoding UTF8 #Read-Host "続けるには Enter キーを押してください..." java -jar C:/GGsync1/GGsync.jar C:/GGsync1 #Read-Host "続けるには Enter キーを押してください..." # DB・logファイルをリネームする Move-Item .\GGsync.db .\DB\GGsync.db_$strMailaddr -force #Move-Item .\GGsync.log .\Log\GGsync.log_$strMailaddr -force $ArryNo = $ArryNo +1 } Read-Host "処理完了-ログを確認してください"
処理実施後、Groonの変更したPWを各ユーザにメール送信も組み込む。
cd C:\GGsync1 $csv = Import-Csv .\Torikomi.csv -Encoding Default $ArryNo = 0 while ( $csv[$ArryNo]."E-mail" -ne $null ) { ### 新しいパスワードをユーザーに送付 #変数初期化 $MessageBody = "Garoonパスワード:" + $csv[$ArryNo].PW #ヘッダー文章追記 $Header = "Googleカレンダーデータ移行に伴い、`r`nGaroonパスワードの初期化を行いましたのでお知らせいたします" #メール送信用パラメータ設定 $SMTPUserName = "SMTP名" $SMTPPassword = "パスワード" $myhost = "smtp.gmail.com" $port = 587 $from = "送信アドレス" $to = $csv[$ArryNo]."E-mail" $bcc = "必要に応じて" $subject = "【重要】GaroonPW変更のお知らせ [" + $csv[$ArryNo]."E-mail" + "]" $msg = New-Object Net.Mail.MailMessage $msg.From = $from $msg.To.Add($to) if($cc) {$msg.CC.Add($cc)} if($bcc) {$msg.Bcc.Add($bcc)} #SubjectとBodyのエンコード $enc = [Text.Encoding]::GetEncoding("csISO2022JP"); $subject64 = [Convert]::ToBase64String($enc.GetBytes($subject), [Base64FormattingOptions]::None) $msg.Subject =[String]::Format("=?{0}?B?{1}?=", $enc.HeaderName, $subject64) $view = [Net.Mail.AlternateView]::CreateAlternateViewFromString($MessageBody, $enc, [Net.Mime.MediaTypeNames]::Text.Plain) $view.TransferEncoding = [Net.Mime.TransferEncoding]::SevenBit $msg.AlternateViews.Add($view) #SMTPメール送信 $sc = New-Object Net.Mail.SmtpClient($myhost,$port) $sc.EnableSsl = $true $sc.Credentials = New-Object Net.NetworkCredential($SMTPUserName,$SMTPPassword) $sc.send($msg) $sc.Dispose() $msg.Dispose() $ArryNo = $ArryNo +1 }
4.各ログを確認しエラー個所を手動にて修正
当日発覚したトラブル
1.Google Admin APIの制限
ユーザーデータの移行に直列処理だと12時間程かかる見込みがあった為、時間を短縮する為に5系統に分割し実施。
5系統に分割し実施したところ、何故かエラーが多発...
調べたところGoogle Admin APIの制限に引っかかっているようなので、GoogleProjectより制限項目の引き上げを設定。
2.予定の登録者をバッチ実行者にしてしまった各ユーザーがスケジュールの取消等ができない事が判明。
(検証時のCTSメンバー全員がGoogleAdmin権限を持っていたため、ここまで気付けず...)
Google Apps Scriptで各ユーザーを登録者としてリソースの登録が出来そうだったので検証したところ、無事登録ができた。
従来の予定一覧CSVをスプレッドシートで加工して、Google Apps Scriptで実行。
// 設定 function getConfig() { return { spreadSheetId: 'sheetID', spreadSheetTabName: 'sheetname' } } // カレンダーにイベントを登録 function registerAll() { var config = getConfig(); var spreadSheet = SpreadsheetApp.openById(config.spreadSheetId); var sheet = spreadSheet.getSheetByName(config.spreadSheetTabName); var eventIds = sheet .getDataRange() .getValues() .filter(function (e, i) { return i !== 0 && e[6] === ''; }).map(function (e) { var id = e[7]; var calendarEvent = CalendarApp.getCalendarById(id).createEvent( e[0], e[1], e[2], { description: e[3], location: e[4], guests: e[5] }); return [calendarEvent.getId()]; }); if (eventIds.length === 0) return; sheet.getRange('G2:G' + (eventIds.length+1) ).setValues(eventIds); } // 登録されたイベントをキャンセルして、シートから削除 function cancelAll() { var range = 'G2:G1000'; var config = getConfig(); var spreadSheet = SpreadsheetApp.openById(config.spreadSheetId); var sheet = spreadSheet.getSheetByName(config.spreadSheetTabName); sheet .getRange(range) .getValues() .filter(function (eventId) { return eventId[0] !== ''; }).forEach(function (id) { CalendarApp.getDefaultCalendar().getEventById(id).deleteEvent(); }); sheet.getRange(range).clear(); } //セルの結合解除 function myFunction() { var range = 'F2:G8181'; var config = getConfig(); var spreadSheet = SpreadsheetApp.openById(config.spreadSheetId); var sheet = spreadSheet.getSheetByName(config.spreadSheetTabName); var rng = sheet.getRange(range); rng.breakApart(); }
APIの制限に悩まされつつも何とか当日までに処理を完了しました....
結果
検証不足および担当の割振りや実施する内容の共有が出来ていなかったため、想定外の落とし穴や手戻りの多発により、工数のみならず精度もだいぶ落ちてしまった。
精度が落ちることによる会議室の登録漏れや重複によるキャンセルされた残骸が散らばってしまい、ユーザーへ迷惑をかけてしまった。
(反省点は多々ありますが)運用開始までの限られた時間の中で、起きたトラブルに対しての改善策をすぐに導き出すことが出来た。
目的に記載したように、既に利用していたSlackや、移行後導入したZoomなど、API連携の幅が広がり利便性が向上した。
(例えば、ZoomはGoogleカレンダーからワンタッチでMTGが開始できます)
感想
想定外だったが、何とかしなくちゃならないと思い避けていたGoogle Apps Scriptを少しだが利用することが出来るようになった。
→今後業務改善に活かせそうなソリューションの幅が広がりました。合わせてGCPでの制限事項や設定方法も学べた。
- 検証時はユーザと同じ環境を作り上げてあらゆる事態を想定する事を学びました。
※GoogleAdminコンソール時に特権ID利用の確認を聞かれるため、自身にAdmin権限が付いていることをつい忘れてしまいますね....
終わりに
全社員が使っているサービスを切り替えるってなかなか思い切りがいる事だったと思います。
また、計画を振り返ってみると良かった点より、苦労した点/反省点の方が良いようにも感じます。
力技でなんとかしたものもありました。
(リブセンスメンバーのITリテラシーの高さに本当に助けられました....)
ただ、この移行により利便性が向上した事は確かであると自信を持って言えます。
これからもCTSとして、現状に捉われず、リブセンスメンバーがより効率的に働けるような環境や仕組みづくりに積極的に取り組んでいきたいと思います。