Bulk Remove Owners

Use PnP PowerShell to Remove owners in bulk using a CSV file.

# Connect PnP with the same email as $SiteCollAdmin

# Define the log file path
$logFilePath = "Remove-logfile.log"

# Function to log messages
function Log-Message {
    param (
        [string]$Message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm"
    $logMessage = "$timestamp - $Message"
    $logMessage | Add-Content -Path $logFilePath
}

# Define the function to process and remove owners from the site
function Remove-SiteOwners {
    param (
        [string]$SiteUrl,
        [string]$Owners
    )

    try {
        # Connect to the SharePoint Online site
        Connect-PnPOnline -Url $SiteUrl -Interactive -ClientId xxxxxxx-xxxxxxxx....
        Log-Message "Connected to site: $SiteUrl"

        # Get site details and check if it's a Teams site (Microsoft 365 Group)
        $site = Get-PnPSite -Includes GroupId

        if ($site.GroupId -ne [Guid]::Empty) {
            # If GroupId is not empty, it's a Teams site
            Log-Message "Site $SiteUrl is a Teams site (Microsoft 365 Group)"

            # Split the owners by semicolon
            $ownerList = $Owners -split ";"

            # Loop through each owner and remove them from the Microsoft 365 Group
            foreach ($userEmail in $ownerList) {
                $userEmail = $userEmail.Trim() # Ensure no extra spaces around the emails
                    try {
                        Remove-PnPMicrosoft365GroupOwner -Identity $site.GroupId -User $userEmail -ErrorAction Stop
                        Log-Message "Removed $userEmail from Microsoft 365 Group owners for site $SiteUrl"
                    }
                    catch {
                        Log-Message "Failed to remove $userEmail from Microsoft 365 Group owners for site $SiteUrl. Error: $_"
                        Write-Warning "Failed to remove $userEmail from Microsoft 365 Group owners for site $SiteUrl"
                    }
            }
        } else {
            # If it's a regular SharePoint site
            Log-Message "Site $SiteUrl is a regular SharePoint site"

            # Get the associated owner group
            $ownersGroup = Get-PnPGroup -AssociatedOwnerGroup

            # Split the owners by semicolon
            $ownerList = $Owners -split ";"

            # Loop through each owner and remove them from the SharePoint owner group
            foreach ($userEmail in $ownerList) {
                $userEmail = $userEmail.Trim() # Ensure no extra spaces around the emails
                try {
                    Remove-PnPGroupMember -LoginName $userEmail -Group $ownersGroup.Id -ErrorAction Stop
                    Log-Message "Removed $userEmail from SharePoint group $($ownersGroup.Title) on site $SiteUrl"
                }
                catch {
                    Log-Message "Failed to remove $userEmail from SharePoint group $($ownersGroup.Title) on site $SiteUrl. Error: $_"
                    Write-Warning "Failed to remove $userEmail from SharePoint group $($ownersGroup.Title) on site $SiteUrl"
                }
            }
        }
    }
    catch {
        Log-Message "Failed to remove owners from site: $SiteUrl. Error: $_"
        Write-Warning "Failed to remove owners from site: $SiteUrl"
    }
}

# Path to your CSV file
$csvPath = "Sites.csv"

# Import the CSV file and store it as an array of sites
$sites = Import-Csv -Path $csvPath

# Total number of sites
$totalSites = $sites.Count

# Initialize a counter for processed sites
$processedCount = 0

# Loop through each site URL in the CSV file and process the owners
for ($i = 0; $i -lt $totalSites; $i++) {
    $site = $sites[$i]
    $SiteUrl = $site.URL
    $Owners = $site.Owners

    # Print progress update
    $processedCount = $i + 1
    $percentComplete = [math]::Round(($processedCount / $totalSites) * 100, 2)
    Write-Host "Processing site $processedCount of $totalSites ($percentComplete% complete): $SiteUrl"
    Log-Message "Processing site $processedCount of $totalSites ($percentComplete% complete): $SiteUrl"

    # Define the site collection admin (for example purposes, replace as needed)
    $SiteCollAdmin = "owner email"

    try {
        # Set the site collection admin
        Set-PnPTenantSite -Url $SiteUrl -Owners $SiteCollAdmin -ErrorAction Stop
        Log-Message "Set site collection admin for site: $SiteUrl"

        # Call the Remove-SiteOwners function to remove owners
        Remove-SiteOwners -SiteUrl $SiteUrl -Owners $Owners

        # Remove the site collection admin
        Remove-PnPSiteCollectionAdmin -Owners $SiteCollAdmin
        Log-Message "Removed site collection admin for site: $SiteUrl"
    }
    catch {
        Log-Message "Failed to set or remove admin for site: $SiteUrl. Error: $_"
        Write-Warning "Failed to set or remove admin for site: $SiteUrl"
    }

    # Optionally add a short delay between iterations (to avoid throttling)
    Start-Sleep -Seconds 1
}

# Final message after all sites are processed
Write-Host "Completed processing $processedCount out of $totalSites sites."
Log-Message "Completed processing $processedCount out of $totalSites sites."