Functions/Public/New-CT365Group.ps1

<#
.SYNOPSIS
This function creates Office 365 Groups, Distribution Groups, Mail-Enabled Security Groups, and Security Groups based on the data provided in an Excel file.
.DESCRIPTION
The function New-CT365Group takes the path of an Excel file, User Principal Name and a Domain as input. It creates Office 365 Groups, Distribution Groups, Mail-Enabled Security Groups, and Security Groups based on the data found in the Excel file. If a group already exists, the function will output a message and skip the creation of that group.
.PARAMETER FilePath
The full path to the Excel file(.xlsx) containing the data for the groups to be created. The Excel file should have a worksheet named "Groups". Each row in this worksheet should represent a group to be created. The columns in the worksheet should include the DisplayName, Type (365Group, 365Distribution, 365MailEnabledSecurity, 365Security), PrimarySMTP (without domain), and Description of the group.
.PARAMETER UserPrincipalName
The User Principal Name (UPN) used to connect to Exchange Online.
.PARAMETER Domain
The domain to be appended to the PrimarySMTP of each group to form the email address of the group.
.EXAMPLE
New-CT365Group -FilePath "C:\Path\to\file.xlsx" -UserPrincialName "admin@domain.com" -Domain "domain.com"
This will read the Excel file "file.xlsx" located at "C:\Path\to\", use "admin@domain.com" to connect to Exchange Online, and append "@domain.com" to the PrimarySMTP of each group to form the email address of the group.
.INPUTS
System.String
.OUTPUTS
System.String
The function outputs strings informing about the creation of the groups or if the groups already exist.
.NOTES
The function uses the ExchangeOnlineManagement and Microsoft.Graph.Groups modules to interact with Office 365. Make sure these modules are installed before running the function.
.LINK
Get-UnifiedGroup
.LINK
New-UnifiedGroup
.LINK
Get-DistributionGroup
.LINK
New-DistributionGroup
.LINK
Get-MgGroup
.LINK
New-MgGroup
#>

function New-CT365Group {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateScript({
            #making sure the Filepath leads to a file and not a folder and has a proper extension
            switch ($psitem){
                {-not([System.IO.File]::Exists($psitem))}{
                    throw "The file path '$PSitem' does not lead to an existing file. Please verify the 'FilePath' parameter and ensure that it points to a valid file (folders are not allowed)."
                }
                {-not(([System.IO.Path]::GetExtension($psitem)) -match "(.xlsx)")}{
                    "The file path '$PSitem' does not have a valid Excel format. Please make sure to specify a valid file with a .xlsx extension and try again."
                }
                Default{
                    $true
                }
            }
        })]
        [string]$FilePath,
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [string]$UserPrincipalName,
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateScript({
            # Check if the domain fits the pattern
            switch ($psitem) {
                {$psitem -notmatch '^(((?!-))(xn--|_)?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?[a-z]{2,}(?:\.[a-z]{2,})+$'}{
                    throw "The provided domain is not in the correct format."
                }
                Default {
                    $true
                }
            }
        })]
        [string]$Domain
    )
    

    # Import the required modules
    $ModulesToImport = "ImportExcel","Microsoft.Graph.Groups","PSFramework","ExchangeOnlineManagement"
    Import-Module $ModulesToImport
    
    # Connect to Exchange Online
    Connect-ExchangeOnline -UserPrincipalName $UserPrincipalName -ShowProgress $true
    
    # Connect to Microsoft Graph
    Connect-MgGraph -Scopes "Group.ReadWrite.All"
    
    # Import data from Excel
    $groups = Import-Excel -Path $FilePath -WorksheetName Groups
    
    foreach ($group in $groups) {
        # Append the domain to the PrimarySMTP
        $group.PrimarySMTP += "@$Domain"
        switch -Regex ($group.Type) {
            "^365Group$" {
                try {
                    Write-PSFMessage -Level Output -Message "Creating 365 Group: $($group.DisplayName)" -Target $Group.DisplayName
                    Get-UnifiedGroup -Identity $group.DisplayName -ErrorAction Stop
                    Write-PSFMessage -Level Warning -Message "365 Group: $($group.DisplayName) already exists" -Target $Group.DisplayName
                } catch {
                    New-UnifiedGroup -DisplayName $group.DisplayName -PrimarySMTPAddress $group.PrimarySMTP -AccessType Private -Notes $group.Description -RequireSenderAuthenticationEnabled $False
                    Write-PSFMessage -Level Output -Message "Created 365 Group: $($Group.DisplayName) successfully" -Target $Group.DisplayName
                }
            }
            "^365Distribution$" {
                try {
                    Write-PSFMessage -Level Output -Message "Creating 365 Distribution Group: $($group.DisplayName)" -Target $Group.DisplayName
                    Get-DistributionGroup -Identity $group.DisplayName -ErrorAction Stop
                    Write-PSFMessage -Level Warning -Message "365 Distribution Group $($group.DisplayName) already exists" -Target $Group.DisplayName
                } catch {
                    New-DistributionGroup -Name $group.DisplayName -DisplayName $($group.DisplayName) -PrimarySMTPAddress $group.PrimarySMTP -Description $group.Description -RequireSenderAuthenticationEnabled $False
                    Write-PSFMessage -Level Output -Message "Created 365 Distribution Group: $($group.DisplayName)"  -Target $Group.DisplayName
                }
            }
            "^365MailEnabledSecurity$" {
                try {
                    Write-PSFMessage -Level Output -Message "Creating 365 Mail-Enabled Security Group: $($group.DisplayName)" -Target $Group.DisplayName
                    Get-DistributionGroup -Identity $group.DisplayName -ErrorAction Stop
                    Write-PSFMessage -Level Warning -Message "365 Mail-Enabled Security Group: $($group.DisplayName) already exists" -Target $Group.DisplayName
                } catch {
                    New-DistributionGroup -Name $group.DisplayName -PrimarySMTPAddress $group.PrimarySMTP -Type "Security" -Description $group.Description -RequireSenderAuthenticationEnabled $False
                    Write-PSFMessage -Level Output -Message "Created 365 Mail-Enabled Security Group: $($group.DisplayName)" -Target $Group.DisplayName
                }
            }
            "^365Security$" {
                Write-PSFMessage -Level Output -Message "Creating 365 Security Group: $($group.DisplayName)" -Target $Group.DisplayName
                $ExistingGroup = Get-MgGroup -Filter "DisplayName eq '$($group.DisplayName)'"
                if ($ExistingGroup) {
                    Write-PSFMessage -Level Warning -Message "365 Security Group: $($group.DisplayName) already exists" -Target $Group.DisplayName
                    continue
                }
                $mailNickname = $group.PrimarySMTP.Split('@')[0]
                New-MgGroup -DisplayName $group.DisplayName -Description $group.Description -MailNickName $mailNickname -SecurityEnabled:$true -MailEnabled:$false
                Write-PSFMessage -Level Output -Message "Created 365 Security Group: $($group.DisplayName)" -Target $Group.DisplayName
            }
            default {
                Write-PSFMessage -Level Error -Message "Invalid group type for $($group.DisplayName)" -Target $Group.DisplayName
            }
        }
    }
    # Disconnect Exchange Online and Microsoft Graph sessions
    Disconnect-ExchangeOnline -Confirm:$false
    Disconnect-MgGraph
}