Functions/Public/New-CT365Teams.ps1

<#
.SYNOPSIS
Creates new Microsoft 365 Teams and channels based on data from an Excel file.
 
.DESCRIPTION
The New-CT365Teams function connects to SharePoint Online and creates new Microsoft 365 Teams and channels using the PnP PowerShell Module.
The teams and channels are defined in an Excel file provided by the user.
 
.PARAMETER FilePath
Specifies the path to the Excel file that contains the teams and channels information.
The Excel file should contain a worksheet named "Teams".
This parameter is mandatory and can be passed through the pipeline.
 
.PARAMETER AdminUrl
Specifies the SharePoint Online admin URL.
If not provided, the function will attempt to connect to SharePoint Online interactively.
 
.PARAMETER ChannelColumns
Specifies the columns in the Excel file that contain the channel names.
By default, it looks for columns named "Channel1Name" and "Channel2Name".
You can specify other column names if your Excel file is structured differently.
 
.EXAMPLE
New-CT365Teams -FilePath "C:\path\to\teams.xlsx" -AdminUrl "https://contoso-admin.sharepoint.com"
 
This example connects to the specified SharePoint Online admin URL, reads the teams and channels from the provided Excel file, and then creates the teams and channels in Microsoft 365.
 
.EXAMPLE
$filePath = "C:\path\to\teams.xlsx"
$filePath | New-CT365Teams
 
This example uses pipeline input to provide the file path to the New-365Teams function.
 
.NOTES
Please submit any feedback and/or recommendations
Prerequisite : PnP.PowerShell, ImportExcel, PSFramework, Microsoft.Identity.Client modules should be installed.
 
#>

function New-CT365Teams {
    [CmdletBinding()]
    param (
        # Validate the Excel file path.
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateScript({
            switch ($psitem){
                {-not([System.IO.File]::Exists($psitem))}{
                    throw "Invalid file path: '$PSitem'."
                }
                {-not(([System.IO.Path]::GetExtension($psitem)) -match "(.xlsx)")}{
                    "Invalid file format: '$PSitem'. Use .xlsx"
                }
                Default{
                    $true
                }
            }
        })]
        [string]$FilePath,

        [Parameter(Mandatory=$false)]
        [ValidateScript({
            if ($_ -match '^[a-zA-Z0-9]+\.sharepoint\.[a-zA-Z0-9]+$') {
                $true
            } else {
                throw "The URL $_ does not match the required format."
            }
        })]
        [string]$AdminUrl,
        
        [Parameter(Mandatory=$false)]
        [string[]]$ChannelColumns = @("Channel1Name", "Channel2Name")
    )

    begin {
        # Import required modules.
        $ModulesToImport = "ImportExcel","PnP.PowerShell","PSFramework","Microsoft.Identity.Client"
        Import-Module $ModulesToImport
        
        try {
            # Connect to SharePoint Online.
            $connectPnPOnlineSplat = @{
                Url = $AdminUrl
                Interactive = $true
                ErrorAction = 'Stop'
            }
            Connect-PnPOnline @connectPnPOnlineSplat
        }
        catch {
            # Log an error and exit if the connection fails.
            Write-PSFMessage -Message "Failed to connect to SharePoint Online" -Level Error 
            return 
        }
        
        try {
            # Import site data from Excel.
            $SiteData = Import-Excel -Path $FilePath -WorksheetName "Teams"
        }
        catch {
            # Log an error and exit if importing site data fails.
            Write-PSFMessage -Message "Failed to import SharePoint Site data from Excel file." -Level Error 
            return
        }
    }

    process {
        foreach ($team in $SiteData) {
            Write-PSFMessage -Message "Processing team: $($team.TeamName)" -Level Host
        
            $existingTeam = Get-PnPTeamsTeam | Where-Object { $_.DisplayName -eq $team.TeamName }
    
            # If the team does not exist, create it.
            if (-not $existingTeam) {
                try {
                    $newPnPTeamsTeamSplat = @{
                        DisplayName = $team.TeamName
                        Description = $team.TeamDescription
                        Visibility = 'Private'
                        ErrorAction = 'Stop'
                    }
    
                    New-PnPTeamsTeam @newPnPTeamsTeamSplat
                    Write-PSFMessage -Message "Successfully created Team: $($team.TeamName)" -Level Host
                }
                catch {
                    Write-PSFMessage -Message "Failed to create team $($team.TeamName): $_" -Level Error
                    continue  # Skip to the next team in case of error.
                }
            } 
    
            # If the team already exists or was just created, log a message.
            Write-PSFMessage -Message "Team $($team.TeamName) exists or was just created. Proceeding to create channels..." -Level Host
    
            # Retry mechanism to fetch team details up to 3 times.
            $retryCount = 0
            $maxRetries = 3
            $teamResult = $existingTeam ?? $null
    
            while ($retryCount -lt $maxRetries -and (-not $teamResult)) {
                Start-Sleep -Seconds 15  # Wait before fetching the team details.
                $teamResult = Get-PnPTeamsTeam | Where-Object { $_.DisplayName -eq $team.TeamName }
                $retryCount++
            }
    
            # If the team wasn't found after all retry attempts, log a warning and skip to the next team.
            if (-not $teamResult) {
                Write-PSFMessage -Message "Team $($team.TeamName) was not found after $maxRetries attempts." -Level Warning
                continue
            }
    
            # Create channels based on the provided column names.
            foreach ($column in $ChannelColumns) {
                $channelName = $team.$column
                if (-not $channelName) { continue }  # Skip to the next channel if the name is not found.
    
                Write-PSFMessage -Message "Creating channel: $channelName for team: $($team.TeamName)" -Level Host
                try {
                    Add-PnPTeamsChannel -Team $teamresult.GroupId -DisplayName $channelName -Description "Channel named $channelName for $($team.TeamName)"
                    Write-PSFMessage -Message "Successfully created channel: $channelName for team: $($team.TeamName)" -Level Host
                }
                catch {
                    Write-PSFMessage -Message "Failed to create channel $channelName for team $($team.TeamName): $_" -Level Error
                }
            }
        }
    }

    end {
        # Disconnect from PnP
        Disconnect-PnPOnline
        Write-PSFMessage "Teams and Channels creation completed."
    }
}