Microsoft Teams を利用していると、テナント内にチームが数多く作成されることは避けられないことであり、それだけ Microsoft Teams が利用されていることでもあります。

ただ、管理者としては、不適切な運用がされているチームなどを管理したいとも思うでしょうし、そのために棚卸のような作業を行われている管理者も多いかと思います。

Microsoft Teams の PowerShell を利用すると棚卸も効率化できるのではないかと思いましたので、その一例を書いておきます。

ちなみに、Microsoft Teams の PowerShell は、今日現在バージョンは 1.0.3 ですね。

PowerShell Gallery | MicrosoftTeams
https://www.powershellgallery.com/packages/MicrosoftTeams/

事前にインストールしておきましょう。

チームの情報を収集する

まずは、PowerShell を利用してチームの情報を収集します。

#Microsoft Teams に接続
Connect-MicrosoftTeams

#チームの情報を収集
$teams = @()
Get-Team | ForEach-Object {
    $obj = New-Object object
    $channels = Get-TeamChannel -GroupId $_.GroupId
    $users = Get-TeamUser -GroupId $_.GroupId
    $owners = $users | Where-Object { $_.Role -like "owner" }
    $members = $users | Where-Object { $_.Role -like "member" }
    $guests = $users | Where-Object { $_.Role -like "guest" }

    $obj | Add-Member -NotePropertyMembers @{
        "GroupId"       = $_.GroupId;
        "DisplayName"   = $_.DisplayName;
        "Visibility"    = $_.Visibility;
        "Archived"      = $_.Archived;
        "MailNickName"  = $_.MailNickName;
        "Description"   = $_.Description;
        "Channels"      = $channels.count;
        "Owners"        = $owners.count;
        "OwnerIds"      = $owners.User -join "`r`n"
        "Members"       = $members.count;
        "MemberIds"     = $members.User -join "`r`n"
        "Guests"        = $guests.count;
        "GuestIds"      = $guests.User -join "`r`n";
    }
    $teams += ($obj | Select-Object GroupId, DisplayName, Visibility, Archived, MailNickName, Description, Channels, Owners, OwnerIds, Members, MemberIds, Guests, GuestIds)
}

まずは管理者アカウントで Connect-MicrosoftTeams を実行することで、PowerShell から Microsoft Teams に接続します。

その後、Get-Team でテナント内のチームの一覧を取得するのですが、ここで得られる情報にはチャネル数や所有者やメンバー、ゲストの情報が含まれていないため、Get-TeamChannelGet-TeamUser を利用してそれらの情報も収集しておきます。

上記のスクリプトを実行することで、必要なチームの情報が $teams にセットされます。

すべてのチームを出力する

全てのチームの情報を出力します。

$teams

これで全チームの情報が出力されます。CSV として出力したい場合には次のようなコマンドです。

$teams | Export-Csv "C:\export\teams.csv" -Encoding UTF8 -NoTypeInformation

これで全チームの情報が「C:\export」フォルダーに「teams.csv」のファイル名で出力されます。

所有者が不在のチームを出力する

チームの運用で一番の問題となる所有者が不在のチームを出力してみます。チームを作成したユーザーが退職したなどの理由で所有者が不在となることがあります。この状態になってしまうと、メンバーの管理などが行えない状態となるため対応が必要です。

#所有者が不在のチーム
$teams | Where-Object { $_.Owners -eq 0 } | ft

上記のコマンドで $teams の中から所有者が不在のチームのみを取り出します。

所有者が不在のチームに一括で管理者アカウントを所有者として追加する

所有者が不在のチームが洗い出せたら、Office 365 の管理者アカウントなどを一時的にチームの管理者に追加するなどの運用も考えられます。

#hirofumi@contoso.com を所有者不在チームの所有者として一括追加する
$teams | Where-Object { $_.Owners -eq 0 } | ForEach-Object {
    Add-TeamUser $_.GroupId -User "hirofumi@contoso.com" -Role "owner"
}

上記のコマンドで所有者不在チームに指定したアカウントを Add-TeamUser を利用し一括追加できます。

ゲストが存在するチームを出力する

次にゲストが存在するチームを出力してみましょう。

#ゲストが登録されているチーム
$teams | Where-Object { $_.Guests -ne 0 } | ft

上記のコマンドでゲストが存在するチームのみを取り出します。

一般チャネルのみのチームを出力する

最後に、チャネルが「一般」しか存在しないチームを出力します。Microsoft Teams では活用が進むとチャネルも増えてくることになると思いますが、逆に一般チャネルしか存在しないチームは上手く活用されていないのではないかとも考えられます。

#一般チャネルのみのチーム
$teams | Where-Object { $_.Channels -eq 1 } | ft

一般チャネルのみのチームはすなわち、チャネル数が 1 つのチームですね。

チームに紐づく SharePoint サイトの情報も合わせて収集する

(2020/03/03 追記)チームに紐づく SharePoint サイトの情報も合わせて収集するサンプルを作成しました。

SharePoint Online Management Shell を組合わせて利用することで、チームに紐づく SharePoint サイトの情報も合わせて収集することができます。

#Microsoft Teams に接続
Connect-MicrosoftTeams

#SharePoint Online に接続
$tenant = "<your tenant>"
$adminUrl = "https://" + $tenant + "-admin.sharepoint.com"
Connect-SPOService $adminUrl

#全チームに紐づくサイト情報を収集
$teamSites = @()
Get-SPOSite -Template "GROUP#0" -Limit All | ForEach-Object {
    $obj = New-Object object
    #GroupId などが -Identity を指定したときにのみ取得可のため
    $site = Get-SPOSite -Identity $_.Url -Detailed
    $obj | Add-Member -NotePropertyMembers @{
        "Url"                   = $site.Url;
        "Title"                 = $site.Title;
        "RelatedGroupId"        = $site.RelatedGroupId;
        "GroupId"               = $site.GroupId;
        "StorageQuota"          = $site.StorageQuota;
        "StorageUsageCurrent"   = $site.StorageUsageCurrent;
    }
    $teamSites += ($obj | Select-Object Url, Title, RelatedGroupId, GroupId, StorageQuota, StorageUsageCurrent)
}

#全チームのプライベートチャネルに紐づくサイト情報を収集
$privateChannelSites = @()
Get-SPOSite -Template "TEAMCHANNEL#0" -Limit All | ForEach-Object {
    $obj = New-Object object
    #GroupId などが -Identity を指定したときにのみ取得可のため
    $site = Get-SPOSite -Identity $_.Url -Detailed
    $obj | Add-Member -NotePropertyMembers @{
        "Url"                 = $site.Url;
        "Title"               = $site.Title;
        "RelatedGroupId"      = $site.RelatedGroupId;
        "GroupId"             = $site.GroupId;
        "StorageQuota"        = $site.StorageQuota;
        "StorageUsageCurrent" = $site.StorageUsageCurrent;
    }
    $privateChannelSites += ($obj | Select-Object Url, Title, RelatedGroupId, GroupId, StorageQuota, StorageUsageCurrent)
}

#チームの情報を収集
$teams = @()
Get-Team | ForEach-Object {
    $obj = New-Object object
    $groupId = $_.GroupId
    $channels = Get-TeamChannel -GroupId $_.GroupId
    $users = Get-TeamUser -GroupId $_.GroupId
    $owners = $users | Where-Object { $_.Role -like "owner" }
    $members = $users | Where-Object { $_.Role -like "member" }
    $guests = $users | Where-Object { $_.Role -like "guest" }

    $site = $teamSites | Where-Object { $_.GroupId -eq $groupId}
    $privateChannels = $privateChannelsSites | Where-Object { $_.RelatedGroupId -eq $groupId }
 
    $obj | Add-Member -NotePropertyMembers @{
        "GroupId"       = $_.GroupId;
        "DisplayName"   = $_.DisplayName;
        "Visibility"    = $_.Visibility;
        "Archived"      = $_.Archived;
        "MailNickName"  = $_.MailNickName;
        "Description"   = $_.Description;
        "Channels"      = $channels.count;
        "Owners"        = $owners.count;
        "OwnerIds"      = $owners.User -join "`r`n";
        "Members"       = $members.count;
        "MemberIds"     = $members.User -join "`r`n";
        "Guests"        = $guests.count;
        "GuestIds"      = $guests.User -join "`r`n";
        "TeamSiteUrl"   = $site.Url;
        "StorageQuota"  = $site.StorageQuota;
        "StorageUsageCurrent" = $site.StorageUsageCurrent;
        "PrivateChannels"     = $privateChannels.count;
        "PrivateChannelSiteUrls" = $privateChannels.Url -join "`r`n";
    }
    $teams += ($obj | Select-Object GroupId, DisplayName, Visibility, Archived, MailNickName, Description, Channels, Owners, OwnerIds, Members, MemberIds, Guests, GuestIds, TeamSiteUrl, StorageQuota, StorageUsageCurrent, PrivateChannels, PrivateChannelSiteUrls)
}

実行時には $tenant にそれぞれのテナント名を指定してください。また、Microsoft Teams への接続と SharePoint Online への接続をそれぞれ行うため、認証画面が 2 回表示されます。

SharePoint Online のチームサイトは、チームのサイトテンプレートである「GROUP#0」と、プライベートチャネルの専用サイトテンプレートである「TEAMCHANNEL#0」が利用されているため、その情報でフィルターして取得できます。

また、チームとの紐づけに利用されている「GroupId」や「RelatedGroupId」は、Get-SPOSite に -Identity プロパティを利用した時にのみ取得可能となっているため、処理が少しややこしくなっています。

プライベートチャネルを持つチームを出力する

SharePoint Online のチームサイトの情報を組合わせることで、プライベートチャネルを持つチームのみを出力することができます。

#プライベートチャネルを持つチーム
$teams | Where-Object { $_.PrivateChannels -ne 0 } | ft

プライベートチャネルは新しい機能ですので、どのくらい利用されているか気になりますね。

一定以上のファイル容量を使用しているチームを出力する

そのほか気になるのが、ファイル容量をどのくらい消費しているかもあると思います。一定以上のファイル容量を使用しているチームも出力できます。

#100GB 以上のファイル容量を使用しているチーム
$teams | Where-Object { $_.StorageUsageCurrent -ge 100GB/1MB } | ft

ただし、この条件だとプライベートチャネルにファイルが大量に入っているチームの場合は出力できません。その場合は、スクリプトをもう少し書き直す必要がありますね。

さいごに

Microsoft Teams のチームの棚卸についての観点は、その企業ごとに様々な観点があるかと思いますが、PowerShell を利用することでその作業を効率化できることもあります。

今回のスクリプトを例に、いろいろと試していただけたらと思います。