Bulk Remove Members

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

#Connect PnP with 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 add members to the site
function Remove-SiteMembers {
    param (
        [string]$SiteUrl,
        [string]$Members
    )

    try {
        # Connect to the SharePoint Online site
        Connect-PnPOnline -Url $SiteUrl -Interactive -ClientId xxxxx-xxxxxx......
        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 members by semicolon
            $memberList = $Members -split ";"

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

            # Get the associated member group
            $membersGroup = Get-PnPGroup -AssociatedMemberGroup

            # Split the members by semicolon
            $memberList = $Members -split ";"

            # Loop through each member and add them to the SharePoint group
            foreach ($userEmail in $memberList) {
                $userEmail = $userEmail.Trim() # Ensure no extra spaces around the emails
                try {
                    Remove-PnPGroupMember -LoginName $userEmail -Group $membersGroup.Id -ErrorAction Stop
                    Log-Message "Removed $userEmail to SharePoint group $($membersGroup.Title) on site $SiteUrl"
                }
                catch {
                    Log-Message "Failed to remove $userEmail to SharePoint group $($membersGroup.Title) on site $SiteUrl. Error: $_"
                    Write-Warning "Failed to remove $userEmail to SharePoint group $($membersGroup.Title) on site $SiteUrl"
                }
            }
        }
    }
    catch {
        Log-Message "Failed to remove members to site: $SiteUrl. Error: $_"
        Write-Warning "Failed to remove members to 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 members
for ($i = 0; $i -lt $totalSites; $i++) {
    $site = $sites[$i]
    $SiteUrl = $site.URL
    $Members = $site.Members

    # 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 = "admin 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-SiteMembers function to add members
        Remove-SiteMembers -SiteUrl $SiteUrl -Members $Members

        # 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."