{"id":434,"date":"2020-06-07T07:00:02","date_gmt":"2020-06-07T07:00:02","guid":{"rendered":"http:\/\/jeedom.sigalou-domotique.fr\/generer-une-liste-des-equipes-teams-leurs-canaux-les-proprietaires-membres"},"modified":"2024-04-21T13:14:56","modified_gmt":"2024-04-21T11:14:56","slug":"generer-une-liste-des-equipes-teams-leurs-canaux-les-proprietaires-membres","status":"publish","type":"post","link":"https:\/\/www.sigalou-domotique.fr\/en\/generer-une-liste-des-equipes-teams-leurs-canaux-les-proprietaires-membres","title":{"rendered":"Generate a list of Teams, their channels, owners, \u2026 members with Power Automate or PowerShell"},"content":{"rendered":"<h1>Objective:<\/h1>\n<p>I wanted to generate this type of list:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-431\" src=\"http:\/\/jeedom.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams.png\" alt=\"excelteams\" width=\"1396\" height=\"411\" srcset=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams.png 1396w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams-600x177.png 600w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams-300x88.png 300w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams-1024x301.png 1024w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams-768x226.png 768w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/excelteams-1200x353.png 1200w\" sizes=\"auto, (max-width: 1396px) 100vw, 1396px\" \/><\/p>\n<p><!--more--><\/p>\n<h1>&nbsp;First try, with Power Automate<\/h1>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-432\" src=\"http:\/\/jeedom.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/pa.png\" alt=\"pa\" width=\"295\" height=\"157\"><\/p>\n<p>I embarked on the implementation of the generation of an excel with Power Automate, it looked like this:<\/p>\n<table border=\"2\">\n<tbody>\n<tr>\n<td>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-433\" src=\"http:\/\/jeedom.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/pa2.png\" alt=\"pa2\" width=\"668\" height=\"632\" srcset=\"https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/pa2.png 668w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/pa2-600x568.png 600w, https:\/\/www.sigalou-domotique.fr\/wp-content\/uploads\/2020\/06\/pa2-300x284.png 300w\" sizes=\"auto, (max-width: 668px) 100vw, 668px\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To draw up the list, this may be enough, but at the time of writing this tutorial, <strong>Power Automate doesn't know yet<\/strong> extract members, owners or whether the channel or team is private. So it does not suit me, I looked for another solution.<\/p>\n<h1>Second try, use PowerShell<\/h1>\n<p>Returning to powerful command-line tools is often the reflex of IT professionals, and I was not disappointed with <strong>the MicrosoftTeams Module for PowerShell<\/strong>.<\/p>\n<p>Using <a href=\"http:\/\/jeedom.sigalou-domotique.fr\/jeedom\">Jeedom<\/a>, I tried to test PowerShell adapted to Raspbian. This is to install it on a Raspi3B+ that already hosts Jeedom.<\/p>\n<p>I have two Jeedoms, one in prod and one in dev, one in sous <strong>Stretch<\/strong> and a sub <strong>Buster<\/strong>. In the<a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/scripting\/install\/installing-powershell-core-on-linux?view=powershell-7#raspbian\" target=\"_blank\" rel=\"noopener noreferrer\"> Microsoft Docs<\/a>, it is specified to use Stretch, at home it works on both (for what I tested).<\/p>\n<h2>Installing PowerShell Core<\/h2>\n<p>Asking whether you install a 32bits or 64bits version is the first step, for this, type:<\/p>\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">uname -m<\/pre>\n\n\n\n<p>Any value below ARMv<strong>7<\/strong> are in 32 bit.<br>64-bit version starts at AMRv<strong>8.<\/strong><\/p>\n<p>The latest version of powershell can be found on&nbsp;<a href=\"https:\/\/github.com\/PowerShell\/PowerShell\">https:\/\/github.com\/PowerShell\/PowerShell<\/a> for Raspbian.Version 7.1.0 on the day of writing this tutorial.<\/p>\n<p>If an old or worrying version is already installed, it must be deleted by:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">rm -rf ~\/powershell<\/pre>\n\n\n\n<p>Launch installation (update version number)<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"typescript\" data-enlighter-theme=\"classic\">sudo su - apt-get install '^libssl1.0.[0-9]$' libunwind8 -y wget https:\/\/github.com\/PowerShell\/PowerShell\/releases\/download\/v7.1.0\/powershell-7.1.0-linux-arm32.tar.gz mkdir ~\/powershell tar -xvf .\/powershell-7.1.0-linux-arm32.tar.gz -C ~\/powershell sudo ~\/powershell\/pwsh -c New-Item -ItemType SymbolicLink -Path \"\/usr\/bin\/pwsh\" -Target \"$PSHOME\/pwsh\" -Force<code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\"><\/code><\/pre>\n\n\n\n<div>To launch PowerShell<\/div>\n<div>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"classic\" data-enlighter-linenumbers=\"false\">~\/powershell\/pwsh<\/pre>\n<\/div>\n\n\n\n<div>\n<div>\n<div>To check the version<\/div>\n<div>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\">$psversiontable<\/pre>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<h2>In PowerShell, install MicrosoftTeams Module<\/h2>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\">Uninstall-Module -Name MicrosoftTeams Install-Module -Name MicrosoftTeams -AllowPrerelease Import-Module MicrosoftTeams<\/pre>\n<h2>Do the first tests on the command line<\/h2>\n<p>To check the version and correct installation of MicrosoftTeams:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">get-module | ft name, version<\/pre>\n<p>Try it out by retrieving the Teams list<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">Connect-MicrosoftTeams<\/pre>\n<p><em><span style=\"text-decoration: underline;\">Note:<\/span> : Recently, an xdg-open error blocks the identification, I had to identify myself by a script using Credential<\/em><\/p>\n<p>View the list of MiscrosoftTeams Module commands<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">get-command -MicrosoftTeams module<\/pre>\n<p>Follow the instructions in yellow to identify yourself<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">$AllTeams = Get-Team Write-Output $AllTeams<\/pre>\n<p class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">The list of teams must be displayed<\/p>\n<h2>Install PSFTP<\/h2>\n<p>To send a Powershell-generated file to an FTP server, the easiest way is to install PSFTP (In PowerShell)<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">apt-get install PSFPT<\/pre>\n\n\n\n<h2>Run a command line script<\/h2>\n<p>To launch the script <a href=\"http:\/\/jeedom.sigalou-domotique.fr\/wp-content\/uploads\/2020\/12\/teams_sigalou.zip\">_sigalou Teams<\/a>.ps1, use this command:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">~\/powershell\/pwsh -File \"teams_sigalou.ps1\"<\/pre>\n\n\n\n<p><strong>Generate a CSV with the Teams list<\/strong><\/p>\n<p>After multiple tests, here is the last script, do not hesitate to adapt it.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\"># Script to generate the Teams list and export to a CSV file and then send this file by FTP to be exploited by an Excel file # Directed by Sigalou 06\/12\/2020 sigalou@@@sigalou-domotique.fr # Use GitHub or email for any questions, requests for improvement and do not hesitate to propose improvements # Please leave these lines # Source: http:\/\/jeedom.sigalou-domotique.fr\/generate-a-list-teams-teams-their-channels-owners-members # or https:\/\/github.com\/sigalou\/MicrosoftTeamstoCSV # FPT identification param([string]$UserName, [string]$Password, [switch]$MFA,[int]$Action) $passwordFTP = ConvertTo-SecureString -AsPlainText \"xxxxx\" -Force $credentialsFTP = New-Object System.Management.Automation.PSCredential \"xxxxx _ftp\", $passwordFTP Import-Module PSFTP # Identification M365 $UserName = \"xxxxx@xxxxx.com\" $Password = \"xxxx\" #Connect to Microsoft Teams $Module=Get-Module -Name MicrosoftTeams -ListAvailable if($Module.count -eq 0) { Write-Host MicrosoftTeams module is not available -ForegroundColor yellow $Confirm= Read-Host Are you sure you want to install module? [Y] Yes [N] No if($Confirm -match \"[yY]\") { Install-Module MicrosoftTeams } else { Write-Host MicrosoftTeams module is required.Please install module using Install-Module MicrosoftTeams cmdlet. Exit } } Write-Host \u2019n\u2019n\u2019n\u2019n\u2019n\u2019nLaunch ... -ForegroundColor Yellow #Authentication using MFA if($mfa.IsPresent) { $Team=Connect-MicrosoftTeams } #Authentication using non-MFA else { #Storing credential in script for scheduling purpose\/ Passing credential as parameter if(($UserName -ne \"\") -and ($Password -ne \"\")) { $SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force $Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword $Team=Connect-MicrosoftTeams -Credential $Credential } else { $Team=Connect-MicrosoftTeams } } #Check for Teams connectivity If($Team -ne $null) { Write-host \u201enConnected successfully to Microsoft Teams -ForegroundColor Green } elsewhere { Write-Host Error occurred while creating Teams session. Please try again -ForegroundColor Red exit } # Putting $True to have a debug on the screen to follow the generation $modeDEBUG=$False $Result=\"\" $Results=@() $Path=\".\/TeamsData.csv\" If (Test-Path $Path){ Remove-Item $Path } Write-Host Data Recovery... $Count=0 $Teams=Get-Team -Visibility Private $nbTeamsPrivate=$Teams.Count #$Teams=Get-Team -Visibility Public -User xxxxx@xxxxxxxxxxxxxxxx.fr $Teams=Get-Team -Visibility Public $nbTeams=$Teams.Count $ColA=$nbTeams.ToString()+\"-\"+$nbTeamsPrivate.ToString() $Result=@{'ColA'=$ColA;'ColB'=\"Updating of the $((Get-Date -format 'dd-MM-yyyy` HH:mm').ToString())\";} $Results= New-Object psobject -Property $Result $Results | select 'ColA', 'ColB' | Export-Csv $Path -NoTypeInformation -Append Write-Host `nData processing... $Teams | Sort-Object DisplayName | foreach { $counterLines=0 $TeamName=$_.Display $Description=$_.Description $GroupId=$_.GroupId $TeamUser=Get-TeamUser -GroupId $GroupId $TeamMemberCount=$TeamUser.Count $TeamPrefix=\"\"\" $putVirgule=0 $NameProprio=\"\" $AllProprios=$TeamUser | Where-Object { $_.Role -eq 'Owner' } $TouslesProprios | foreach { if ($putVirgule -eq 1) { $putVirgule=0 $NameProprio=$NameProprio+\", \" } $NameProprio=$NameProprio+$_.Name $putVirgule=1 } $NameProprio=$NameProprio+\" and \"+$TeamMemberCount+\" members\" if ($TeamMemberCount -gt 80) { $NameProprio=\"\" $TeamPrefix=\"\ud83c\udf10 \" } if ($_.Archived -eq \"True\") { $TeamPrefix=\"\ud83d\uddc4\" $NameProprio=\"[ Archived ]\" } If($Description -eq $TeamName) {$Description=\"\"} Write-Progress -Activity \" $Count\/$nbTeams $TeamName \" if$modeDEBUG) { Write-Host `n \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550[$TeamName] $Description -ForegroundColor green} $Count++ Get-TeamChannel -MembershipType Standard -GroupId $GroupId | foreach { $ChannelName=$_.DisplayName If($ChannelName -ne \"general\") { Write-Progress -Activity \" $Count\/$nbTeams $TeamName \/\/ $ChannelName\" #$Description=$_.Description if ($modeDEBUG) { Write-Host \u2560\u2550\u2550\u2550&gt; [$ChannelName] $ChannelMemberCount $Description} $Result=@{'ColA'=\"\";'ColB'=$ChannelName;} } else { $Result=@{'ColA'=$TeamPrefix+$TeamName;'ColB'=$NameProprio;} } $Results= New-Object psobject -Property $Result $Results | select 'ColA', 'ColB' | Export-Csv $Path -NoTypeInformation -Append $MeterLines++ } $channelsprives=Get-TeamChannel -MembershipType Private -GroupId $GroupId $channelsprivescount=$canalprives.Count If($channelsprivescount -eq \"1\") { if ($modeDEBUG) { Write-Host \u2560\u2550\u2550\u2550&gt; +$canalprivescount private channel } $Result=@{'ColA'=\"\";'ColB'=\"+1 private channel\";'ColC'=\"\";'ColD'=\"\";} $Results= New-Object psobject -Property $Result $Results | select 'ColA', 'ColB' | Export-Csv $Path -NoTypeInformation -Append $counterLines++ } elseIf($channelsprivescount -gt 1) { if ($modeDEBUG) { Write-Host \u2560\u2550\u2550\u2550&gt; +$Private canalsprivescount Private canals } $Result=@{'ColA'=\"\";'ColB'=\"+$private channelsprivescount channels\";} $Results= New-Object psobject -Property $Result $Results | select 'ColA', 'ColB' | Export-Csv $Path -NoTypeInformation -Append $MeterLines++ } if ($counterLines -eq '1') { if ($modeDEBUG) { Write-Host \u2560\u2550\u2550\u2550&gt; Add an empty } line $Result=@{'ColA'=\"\";'ColB'=\" \";} $Results= New-Object psobject -Property $Result $Results | select 'ColA', 'ColB' | Export-Csv $Path -NoTypeInformation -Append } if ($modeDEBUG) { Write-Host \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -ForegroundColor green } } Write-Progress -Activity \"\u201cn Processed Teams count: $Count \u201c\u201cn\u201d Currently Processing: $TeamName `n Currently Processing Channel: $ChannelName\" -Completed if((Test-Path -Path $Path) -eq \"True\") { Write-Host \u201cnReport available in $Path -ForegroundColor Green } Disconnect-MicrosoftTeams # Send the TeamsData.csv file in ftp Set-FTPConnection -Credentials $credentialsFTP -Server ftp.xxxx.org -Session FloFTP -ignoreCert -UseBinary -KeepAlive $Session = Get-FTPConnection -Session FloFTP Get-ChildItem \".\\TeamsData.csv\" | Add-FTPItem -Session $Session -Path \/Teams\/ -Overwrite      <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>","protected":false},"excerpt":{"rendered":"<p>Objectif : Je souhaitais g\u00e9n\u00e9rer ce type de liste :<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[14,24],"tags":[51],"class_list":["post-434","post","type-post","status-publish","format-standard","hentry","category-domotique","category-microsoft-365","tag-teams"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/posts\/434","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/comments?post=434"}],"version-history":[{"count":0,"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/posts\/434\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/media?parent=434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/categories?post=434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sigalou-domotique.fr\/en\/wp-json\/wp\/v2\/tags?post=434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}