Remediation/Teams/TMS-CHANNELS.ps1
|
# UNTESTED: this script has never been run on a real tenant. Read it, try it on a test tenant first, and use it at your own risk. <# .SYNOPSIS Prepares how private and shared channels are handled and B2B direct connect (procedure TMS-CHANNELS). .DESCRIPTION Reads channels and teamMembership, and gives the list of private and shared channels of the source. decisions\TMS-CHANNELS.csv has one row per shared channel: Internal, or External organization with its tenant identifier in Note. For an external organization, the script allows B2B direct connect in the target, inbound and outbound, for all users. In an -Apply run, the script reads the teams that share each channel and the channel policy of the target. Limits: the copy of a channel is validated at the POC with the chosen tool. The same configuration must be done at the other organization. The channel policy is not changed: the script only says if it blocks sharing. #> $c = Open-TcRemediation $PartnerUri = 'v1.0/policies/crossTenantAccessPolicy/partners' function Get-DirectAccessBody { return @{ usersAndGroups = @{ accessType = 'allowed'; targets = @(@{ target = 'AllUsers'; targetType = 'user' }) } applications = @{ accessType = 'allowed'; targets = @(@{ target = 'AllApplications'; targetType = 'application' }) } } } function Get-Partner { param([string]$Target, [string]$Id) return (@(Invoke-TcGraph -Tenant $Target -Uri $PartnerUri -All) | Where-Object { (Get-TcMember $_ 'tenantId') -eq $Id } | Select-Object -First 1) } $proposals = foreach ($t in $c.Tenants) { Write-TcRemediationTenant $t $list = @(Get-TcRemediationTable $t 'channels' | Where-Object { $_['Type'] -in 'Private', 'Shared' }) Write-TcRemediationNote ("{0} private channel(s), {1} shared" -f @($list | Where-Object { $_['Type'] -eq 'Private' }).Count, @($list | Where-Object { $_['Type'] -eq 'Shared' }).Count) Export-TcRemediationReport -Name "channels-$t" -Rows @($list | ForEach-Object { [pscustomobject]@{ 'Team' = $_['Team']; Channel = $_['Channel']; Type = $_['Type'] } }) | Out-Null Add-TcManualAction -Tenant $t -Object 'Channel POC' -Description "Try the copy of a shared channel and a private channel during the POC" ` -Instruction @('Structure, members, files and messages. Record what the tool does not carry over and plan to recreate it by hand.', 'Microsoft Entra guests cannot be added to a shared channel.') foreach ($l in $list | Where-Object { $_['Type'] -eq 'Shared' }) { [ordered]@{ Tenant = $t; 'Team' = $l['Team']; Channel = $l['Channel']; Proposal = '' } } } $decisions = @(Get-TcDecision -Name 'TMS-CHANNELS' -Proposal @($proposals) -Key 'Tenant', 'Team', 'Channel' -Choice 'Internal', 'External organization') foreach ($d in $decisions | Where-Object { (Get-TcMember $_ 'Decision') -eq 'External organization' }) { $id = ((Get-TcText $d 'Note')).Trim() if ($id -notmatch '^[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$') { Write-TcRemediationAlert ("{0}: the Note column must give the tenant identifier of the external organization" -f (Get-TcMember $d 'Channel')); continue } Add-TcBlockAction -Tenant 'Target' -Service Graph -Object $id -Description ("Allow B2B direct connect with the tenant {0} (channel {1})" -f $id, (Get-TcMember $d 'Channel')) -Data @{ Partner = $id } ` -Test { param($a) $p = Get-Partner $a.tenant $a.data.Partner return $p -and (Get-TcMember (Get-TcMember (Get-TcMember $p 'b2bDirectConnectInbound') 'usersAndGroups') 'accessType') -eq 'allowed' -and (Get-TcMember (Get-TcMember (Get-TcMember $p 'b2bDirectConnectOutbound') 'usersAndGroups') 'accessType') -eq 'allowed' } ` -Block { param($a) $id = $a.data.Partner $p = Get-Partner $a.tenant $id $access = @{ b2bDirectConnectInbound = (Get-DirectAccessBody); b2bDirectConnectOutbound = (Get-DirectAccessBody) } if ($p) { $a.undo = @{ type = 'Graph'; tenant = $a.tenant; method = 'PATCH'; uri = "$PartnerUri/$id"; body = @{ b2bDirectConnectInbound = (Get-TcMember $p 'b2bDirectConnectInbound'); b2bDirectConnectOutbound = (Get-TcMember $p 'b2bDirectConnectOutbound') } } Invoke-TcGraph -Tenant $a.tenant -Method PATCH -Uri "$PartnerUri/$id" -Body $access | Out-Null } else { $access.tenantId = $id $a.undo = @{ type = 'Graph'; tenant = $a.tenant; method = 'DELETE'; uri = "$PartnerUri/$id" } Invoke-TcGraph -Tenant $a.tenant -Method POST -Uri $PartnerUri -Body $access | Out-Null } } Add-TcManualAction -Tenant 'Target' -Object $id -Description ("Do the same configuration at the organization {0}" -f $id) -Instruction @('Both sides are required: the administrator of the external organization must allow B2B direct connect, inbound and outbound.') -Who 'External administrator' } Invoke-TcRemediationPlan -Verify { param($t) $teams = @(Get-TcRemediationTable $t 'teams') foreach ($name in @(Get-TcRemediationTable $t 'channels' | Where-Object { $_['Type'] -eq 'Shared' } | ForEach-Object { $_['Team'] } | Select-Object -Unique)) { $e = $teams | Where-Object { $_['Name'] -ceq $name } | Select-Object -First 1 if (-not $e) { continue } foreach ($channel in @(Invoke-TcGraph -Tenant $t -Uri ("v1.0/teams/{0}/allChannels?`$filter=membershipType eq 'shared'&`$select=id,displayName" -f $e['Id']) -All)) { $others = @(Invoke-TcGraph -Tenant $t -Uri ("v1.0/teams/{0}/channels/{1}/sharedWithTeams" -f $e['Id'], (Get-TcMember $channel 'id')) -All | Where-Object { (Get-TcMember $_ 'tenantId') -and (Get-TcMember $_ 'tenantId') -ne (Get-TcMember (Get-TcRemediationTenant $t) 'TenantId') }) New-TcRemediationResult Info ("{0} / {1}: {2} team(s) of another organization {3}" -f $name, (Get-TcMember $channel 'displayName'), $others.Count, (($others | ForEach-Object { (Get-TcMember $_ 'tenantId') } | Select-Object -Unique) -join ', ')) } } $p = Invoke-TcServiceCommand -Tenant 'Target' -Service Teams -Command 'Get-CsTeamsChannelsPolicy' -Parameters @{ Identity = 'Global' } if ((Get-TcMember $p 'AllowChannelSharingToExternalUser') -and (Get-TcMember $p 'AllowUserToParticipateInExternalSharedChannel')) { New-TcRemediationResult OK 'the channel policy of the target allows external sharing' } else { New-TcRemediationResult Warning 'the channel policy of the target blocks external sharing' } } Close-TcRemediation |