How to fix issue with leftover SharePoint folder after a CM operation

This page describes a temporary solution to a known problem that exists within Channel Management.

Problem description

Each Teams channel has a corresponding SharePoint site that contains all of the files for that team:

Each folder corresponds to a Teams channel, where files for that channel are stored. When you’re performing a CM operation that is expected to remove the original channel (Such as Merge or Move), the channel does indeed get removed, however its SharePoint folder is not. Moreover, the original files are kept too.

It is still possible to modify or remove these files, however the folder itself cannot be modified or removed:

Here’s the SharePoint side of things:

Notice that there exists the “Removed channel” folder and that there is no “delete” or “rename” options.

 

The “Removed channel” should be removed with the CM operation. It is a known issue and the CM shouldn’t leave a copy.

Workaround

The solution described below can lead to data loss, so please read carefully.

It is possible to remove these folders with PowerShell, with the Microsoft.Online.SharePoint.Powershell module, using the code below.

This code is tested to work with PowerShell v5.1, might not work in newer versions. To check currently running version type.

$PSversionTable

 

This has to be run from an elevated PowerShell console:

function Remove-SPFolder { param( $user, $password, $siteUrl, $folderURL ) #modules try { Import-Module Microsoft.Online.SharePoint.Powershell -DisableNameChecking } catch { Install-Module Microsoft.Online.SharePoint.Powershell Write-Output "Error installing module" $_.Exception.Message } # GUI function Create-Inputbox { param( [string]$formTitle = 'Data Entry Form', [string]$position = 'CenterScreen', [string]$prompt ) function Create-Button { param( $parentForm, [ValidateCount(2, 2)][int[]]$location, [ValidateCount(2, 2)][int[]]$size, [string]$text, [ValidateSet("None", "OK", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "TryAgain", "Continue")]$dialogResult ) $button = New-Object System.Windows.Forms.Button $button.Location = New-Object System.Drawing.Point($location[0], $location[1]) $button.Size = New-Object System.Drawing.Size($size[0], $size[1]) $button.Text = $text $button.DialogResult = [System.Windows.Forms.DialogResult]::$dialogResult $parentForm.AcceptButton = $button $parentForm.Controls.Add($button) } Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object System.Windows.Forms.Form $form.Text = $formTitle $form.Size = New-Object System.Drawing.Size(300, 200) $form.StartPosition = $position Create-Button -parentForm $form -location 75, 120 -size 75, 23 -text "OK" -dialogResult "OK" Create-Button -parentForm $form -location 150, 120 -size 75, 23 -text "Cancel" -dialogResult "Cancel" $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(10, 20) $label.Size = New-Object System.Drawing.Size(280, 20) $label.Text = $prompt $form.Controls.Add($label) $textBox = New-Object System.Windows.Forms.TextBox $textBox.Location = New-Object System.Drawing.Point(10, 40) $textBox.Size = New-Object System.Drawing.Size(260, 20) $form.Controls.Add($textBox) $form.Topmost = $true $form.Add_Shown({ $textBox.Select() }) $result = $form.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { $content = $textBox.Text return $content } else { return } } if (!$siteURL) { $SiteUrl = (Create-Inputbox -formTitle "Site URL" -prompt "Please provide SharePoint site URL").trim() } $SiteUrl #URL Variables if (!$folderURL) { $FolderURL = "Shared Documents/$((Create-Inputbox -formTitle "Channel / Team name" -prompt "Please provide Sharepoint Folder name").trim() <# -replace " ", "%20" #>)" } $FolderURL if ($SiteUrl -and $FolderURL) { Try { if ($user -and $password) { # $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $password $pw = $password | ConvertTo-SecureString -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $pw } $Cred = if ($cred) { $cred } else { Get-Credential } $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password) #Setup the context $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl) $ctx.Credentials = $credentials $web = $ctx.web #Get the folder object from given URL $Folder = $web.GetFolderByServerRelativeUrl($FolderURL) #sharepoint online powershell delete folder in document library $Folder.DeleteObject() $ctx.Load($ctx.Site) $ctx.ExecuteQuery() # $ctx.ExecuteQueryAsync() Write-host "Folder deleted Successfully!" -ForegroundColor Green } Catch { Write-host "Breakpoint!" write-host -f Red "Error deleting Folder!" $_.Exception.Message } } } Remove-SPFolder

The script will create several dialog boxes for one expecting the SharePoint site url of the folder you’re looking to remove:

 

 

It is important that the correct URL is used and also to click on “OK” not “enter”.

Then the script will prompt for the folder(channel) name to remove:

 

The script will prompt you to provide a tenant user:

Provide a user that has tenant Admin privileges. Upon success you should see the following message.

Note: MFA for the user and Security defaults must be turned off.

SharePoint folder would then be deleted along with its contents.