MyPSFunctions.SPO.ps1

<#
    ===========================================================================
     Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.196
     Created on: 10/26/2023 7:18 PM
     Created by: John@MyPSFunctions.com
     Organization: MyPSFunctions
     Filename: MyPSFunctions.SPO.psm1
    -------------------------------------------------------------------------
     Module Name: MyPSFunctions.SPO
    ===========================================================================
#>


Function Generate-OnedriveUsageReport
{
    [CmdletBinding()]
    param ()
    
    # Get a list of OneDrive for Business sites in the tenant sorted by the biggest consumer of quota
    Write-Log -Level Warning -Message "Finding OneDrive sites..."
    [array]$ODFBSites = Get-SPOSite -IncludePersonalSite $True -Limit All -Filter "Url -like '-my.sharepoint.com/personal/'" | Select Owner, Title, URL, StorageQuota, StorageUsageCurrent | Sort StorageUsageCurrent -Descending
    If (!($ODFBSites)) { Write-Log -Level Error -Message "No OneDrive sites found (surprisingly...)"; break }
    # Calculate total used
    $TotalODFBGBUsed = [Math]::Round(($ODFBSites.StorageUsageCurrent | Measure-Object -Sum).Sum /1024, 2)
    # Create list to store report data
    $Report = [System.Collections.Generic.List[Object]]::new()
    # Store information for each OneDrive site
    ForEach ($Site in $ODFBSites)
    {
        $ReportLine = [PSCustomObject]@{
            Owner = $Site.Title
            Email = $Site.Owner
            URL   = $Site.URL
            QuotaGB = [Math]::Round($Site.StorageQuota/1024, 2)
            UsedGB = [Math]::Round($Site.StorageUsageCurrent/1024, 4)
            PercentUsed = [Math]::Round(($Site.StorageUsageCurrent/$Site.StorageQuota * 100), 4)
        }
        $Report.Add($ReportLine)
    }
    Write-Log -Level Warning -Message "Current OneDrive for Business storage consumption is $TotalODFBGBUsed GB"
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_CurrentUser_Onedrive_Usage_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "OnedriveUsage" -Title "OnedriveUsage" -TitleBold -WorksheetName "OnedriveUsage" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

Function Add-SharepointCollaborationSiteAdminPermission
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SiteURL,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$AdminUPN
    )
    
    Set-SPOUser -site $SiteURL -LoginName $AdminUPN -IsSiteCollectionAdmin $True
    Write-Log -Level Error -message "Updated permission"
}

Function Add-SharepointCollaborationSiteAdminPermissionToGroup
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SiteURL,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$GroupEmailAddress
    )
    $AADGroup = Get-AzureADGroup -SearchString $GroupEmailAddress
    $AADGroupID = $AADGroup.Objectid
    $LoginName = "C:0t.c|tenant|" + $AADGroupID
    Set-SPOUser -site $SiteURL -LoginName $LoginName -IsSiteCollectionAdmin $True
    Write-Log -Level Error -message "Updated permission"
}

Function Add-SharepointCollectionSiteURLAdminusingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    
    $CollabSites = Import-Csv $CSVFile
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($CollabSites | Measure).count
    #Loop through each Site Collection
    ForEach ($Site in $CollabSites)
    {
        $SiteURL = $Null
        $SiteURL = $Site.SiteUrl
        $Title = $Null
        $Title = $Site.Title
        Write-Log -Level Warning -message "The script is analyzing $Title - $SiteURL….. --- $i/$Count"
        #Get the Site colection
        $SiteCollectionData = Get-SPOSite $SiteURL
        
        #sharepoint online powershell get all site collection admins
        $SiteAdmins = Get-SPOUser -Site $SiteCollectionData -Limit ALL | Where { $_.IsSiteAdmin -eq $True }
        $FoundSiteAdmins = $Null
        $FoundSiteAdmins = @()
        foreach ($Admin in $SiteAdmins)
        {
            
            $FoundSiteAdmins += $Admin.DisplayName + "-:-" + $Admin.LoginName
        }
        $FoundAdmins = $FoundSiteAdmins -join "_"
        Write-Log -Level Warning -message "Found admin $FoundAdmins"
        $FoundKMSAdmins = $FoundSiteAdmins | where { $_ -like "*KMS-Admin*" }
        $FoundKMSSiteAdmins = $FoundKMSAdmins -join "-"
        $FoundKMSAdminCount = ($FoundKMSAdmins | Measure).count
        If ($FoundKMSAdminCount -ge 1)
        {
            Write-Log -Level INFO -message "Found admins are/is : $FoundKMSSiteAdmins for $Title"
            $KMSAdmins = "Yes"
            
            # Add KMS Group as Admin
            Try
            {
                Set-SPOUser -site $SiteURL -LoginName "C:0t.c|tenant|9804662d-449e-4215-8725-1537c236d680" -IsSiteCollectionAdmin $True
                $Added = "Yes"
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $Added = "No, Failed with Error: $ErrorMessage"
            }
        }
        Else
        {
            Write-Log -Level Error -message "Did NOT Found admins for $Title"
            $Added = "No"
            $KMSAdmins = "No"
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                Title            = $Title;
                SiteURL            = $SiteURL;
                FoundAdmins        = $FoundAdmins;
                Found_KMSAdmins = $KMSAdmins;
                Added            = $Added;
            })
        
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_SharepointCollectionAdmins_Sites_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "SharepointCollection" -Title "SharepointCollection" -TitleBold -WorksheetName "SharepointCollection" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Add-SharepointCollectionSiteAdminusingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    
    $CollabSites = Import-Csv $CSVFile
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($CollabSites | Measure).count
    #Loop through each Site Collection
    ForEach ($Site in $CollabSites)
    {
        $SiteURL = $Null
        $SiteURL = $Site.SiteUrl
        $Title = $Null
        $Title = $Site.Title
        $FoundAdmins = $Null
        $FoundAdmins = $Site.FoundAdmins
        Write-Log -Level Warning -message "The script is analyzing $Title - $SiteURL….. --- $i/$Count"
        Write-Log -Level Warning -message "Found admins: $FoundAdmins"
        $FoundKMSAdmins = $FoundAdmins | where { $_ -like "*KMS-Admin*" }
        $FoundKMSAdminCount = ($FoundKMSAdmins | Measure).count
        If ($FoundKMSAdminCount -ge 1)
        {
            Write-Log -Level warning -message "Found admins are/is : $FoundAdmins for $Title"
            $KMSAdmins = "Yes"
            
            # Add KMS Group as Admin
            Try
            {
                Set-SPOUser -site $SiteURL -LoginName "C:0t.c|tenant|9804662d-449e-4215-8725-1537c236d680" -IsSiteCollectionAdmin $True
                Write-Log -Level Error -message "Update permission"
                $Added = "Yes"
                sleep 10
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $Added = "No, Failed with Error: $ErrorMessage"
            }
        }
        Else
        {
            Write-Log -Level Error -message "Did NOT Found admins for $Title"
            $Added = "No"
            $KMSAdmins = "No"
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                Title            = $Title;
                SiteURL            = $SiteURL;
                FoundAdmins        = $FoundAdmins;
                Found_KMSAdmins = $KMSAdmins;
                Added            = $Added;
            })
        
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_SharepointCollectionAdmins_Sites_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "SharepointCollectionAdminSites" -Title "SharepointCollectionAdminSites" -TitleBold -WorksheetName "SharepointCollectionAdminSites" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Get-PnPOffice365GroupOwners
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity
    )
    
    $Microsoft365GroupID = (Get-PnPMicrosoft365Group -Identity $Identity).id.GUID
    Get-PnPMicrosoft365GroupOwner -Identity $Microsoft365GroupID
    
}

Function Get-UnifiedLogs_SharepointSite_30Days
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharepointSiteURL
    )
    
    $StartDate = (Get-Date).AddDays(-90)
    $EndDate = Get-Date
    
    $Logs = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -ObjectIDs $SharepointSiteURL
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $SharepointSiteURLName = $SharepointSiteURL.Substring(30)
    $SharepointSiteURLName = $SharepointSiteURLName -replace '/', "_"
    $SPO_UnifiedLogs_CSVFile = ".\SharepointSite_90Days_UnifiedLogs_" + $SharepointSiteURLName + "_" + $DateFull + ".xlsx"
    $Logs | Export-Excel $SPO_UnifiedLogs_CSVFile -TableName "SharepointSite90DaysLogs" -Title "SharepointSite90DaysLogs" -TitleBold -WorksheetName "SharepointSite90DaysLogs" -TableStyle Medium9 -AutoSize -AutoFilter
    $Logs | ft UserIds, Operations, RecordType, CreationDate
    Write-Host "The Sharepoint Site unified logs for last 30 days was exported to:" -NoNewline; Write-Host "$SPO_UnifiedLogs_CSVFile" -ForegroundColor Green
}

Function Reset-OnedriveQuotaToDefault
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN
    )
    Try
    {
        $SPOSite = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Owner -eq $UPN" | where { $_.Url -like "*-my.sharepoint.com/personal/*" } | select -First 1
        Write-Log -Level warning -Message "The Onedrive current configuration:"
        $SPOSite | fl Owner, StorageUsageCurrent, StorageQuota, StorageQuotaType
        $OneDriveURL = $SPOSite.Url
        Set-SPOSite -Identity $OneDriveURL -StorageQuotaReset
        Sleep 5
        $SPOSite2 = Get-SPOSite -Identity $OneDriveURL -Detailed
        Write-Log -Level warning -Message "The Onedrive quota as been resetted"
        $SPOSite2 | fl Owner, StorageUsageCurrent, StorageQuota, StorageQuotaType
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Reset the Onedrive quota"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
    }
}

Function Generate-OneDriveStorageUsageReport
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $False,
                   Position = 1)]
        [string]$CSVName
    )
    
    $ODFBSites = Get-SPOSite -IncludePersonalSite $True -Limit All -Filter "Url -like '-my.sharepoint.com/personal/'" | Select Owner, Title, URL, StorageQuota, StorageUsageCurrent | Sort StorageUsageCurrent -Desc
    $TotalODFBGBUsed = [Math]::Round(($ODFBSites.StorageUsageCurrent | Measure-Object -Sum).Sum /1024, 2)
    $Report = @()
    ForEach ($Site in $ODFBSites)
    {
        $Owner = $Null
        $Owner = $Site.Title
        $URL = $Null
        $URL = $Site.URL
        Write-Host "Generating Data for Site : Owner:" -NoNewline; Write-Host "$Owner" -ForegroundColor Yellow -NoNewline; Write-Host " - URL:" -NoNewline; Write-Host "$URL" -ForegroundColor Green
        $ReportLine = [PSCustomObject][Ordered]@{
            Owner = $Site.Title
            Email = $Site.Owner
            URL = $Site.URL
            QuotaGB = [Math]::Round($Site.StorageQuota/1024, 2)
            UsedGB = [Math]::Round($Site.StorageUsageCurrent/1024, 4)
        }
        $Report += $ReportLine
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($CSVName) { $CSVOuputFile = $CSVName }
    Else { $CSVOuputFile = "OneDriveStorageUsageReport_" + $DateFull + ".csv" }
    $Report | Export-CSV $CSVOuputFile -NoTypeInformation -Encoding UTF8
    $File = Get-Item $CSVOuputFile
    $FileLocation = $File.VersionInfo.FileName
    Write-Host "Current OneDrive for Business storage consumption:" -NoNewline; Write-Host "$TotalODFBGBUsed GB" -ForegroundColor red -NoNewline; Write-Host " - Report location is: " -NoNewline; Write-Host "$FileLocation" -ForegroundColor Yellow
}

Function Update-OnedriveQuota
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [int]$QuotaGB
    )
    
    # Source https://docs.microsoft.com/en-us/onedrive/change-user-storage
    # Check Sharepoint Online Connection
    Read-Host 'Are you Connected to Sharepoint Online (Powershell Module)? - <CTRL+C> to Cancel or <Enter> to continue'
    #Find Onedrive URL
    #$SPOSite = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter { "Url -like '-my.sharepoint.com/personal/'" -and "Owner -eq $UPN" } | select -First 1
    $SPOSites = $Null
    $SPOSites = @()
    $SPOSites = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Owner -eq $UPN" | where { $_.Url -like "*-my.sharepoint.com/personal/*" }
    foreach ($SPOSite in $SPOSites)
    {
        $OneDriveURL = $SPOSite.Url
        $OneDriveCurrentQuotaMB = $SPOSite.StorageQuota
        $OneDriveCurrentQuotaGB = $OneDriveCurrentQuotaMB / 1024
        Write-Host "$UPN Onedrive Url is : $OneDriveURL - The current Quota is $OneDriveCurrentQuotaGB GB" -ForegroundColor Yellow
        # Convert Quota in MB
        [Int]$QuotaMB = 1024 * $QuotaGB
        Set-SPOSite -Identity $OneDriveURL -StorageQuota $QuotaMB
        #Set-PnPTenantSite -Url $OneDriveURL -StorageMaximumLevel $QuotaMB
        Write-Host "$UPN new Quota is $QuotaGB" -ForegroundColor Green
    }
}

Function Update-OnedriveAnonymousLinkExpiration
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [int32]$ExpirationInDays
    )
    
    #Find User Onedrive link
    $SPOSite = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Owner -eq $UPN" | where { $_.Url -like "*-my.sharepoint.com/personal/*" } | select -First 1
    $OneDriveURL = $SPOSite.Url
    $SPOSiteCurrent = Get-SPOSite -Identity $OneDriveURL
    $CurrentAnonymousLinkExpirationInDays = $Null
    $CurrentAnonymousLinkExpirationInDays = $SPOSiteCurrent.AnonymousLinkExpirationInDays
    $CurrentOverrideTenantAnonymousLinkExpirationPolicy = $Null
    $CurrentOverrideTenantAnonymousLinkExpirationPolicy = $SPOSiteCurrent.OverrideTenantAnonymousLinkExpirationPolicy
    
    Write-Host "The script find for $UPN the following Onedrive URL:" -NoNewline; Write-Host  $OneDriveURL -ForegroundColor Yellow
    Write-Host " -- Current OverrideTenantAnonymousLinkExpirationPolicy =" -NoNewline; Write-Host  $CurrentOverrideTenantAnonymousLinkExpirationPolicy -ForegroundColor Red
    Write-Host " -- Current AnonymousLinkExpirationInDays = " -NoNewline; Write-Host $CurrentAnonymousLinkExpirationInDays -ForegroundColor Red
    #Update OneDrive AnymousLinkExpiration
    Set-SPOSite -Identity $OneDriveURL -AnonymousLinkExpirationInDays $ExpirationInDays -OverrideTenantAnonymousLinkExpirationPolicy $True
    $SPOSiteNew = Get-SPOSite -Identity $OneDriveURL
    $NewAnonymousLinkExpirationInDays = $Null
    $NewAnonymousLinkExpirationInDays = $SPOSiteNew.AnonymousLinkExpirationInDays
    $NewOverrideTenantAnonymousLinkExpirationPolicy = $Null
    $NewOverrideTenantAnonymousLinkExpirationPolicy = $SPOSiteNew.OverrideTenantAnonymousLinkExpirationPolicy
    
    Write-Host "The script update for user with $UPN and the following Onedrive URL:" -NoNewline; Write-Host  $OneDriveURL -ForegroundColor Yellow
    Write-Host " -- New OverrideTenantAnonymousLinkExpirationPolicy =" -NoNewline; Write-Host $NewOverrideTenantAnonymousLinkExpirationPolicy -ForegroundColor Green
    Write-Host " -- New AnonymousLinkExpirationInDays =" -NoNewline; Write-Host $NewAnonymousLinkExpirationInDays -ForegroundColor Green
}

Function Search-DeletedOnedriveInfo
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN
    )
    
    $LocalPart = $UPN.Substring(0, $UPN.LastIndexOf("@"))
    $Filter = '*' + $LocalPart + '*'
    $SPODeletedSites = $Null
    $SPODeletedSites = @()
    $Table = $Null
    $Table = @()
    $SPODeletedSites = Get-SPODeletedSite -IncludeOnlyPersonalSite -limit All | where { $_.Url -like $Filter }
    foreach ($SPODeletedSite in $SPODeletedSites)
    {
        $URL = $Null
        $URL = $SPODeletedSite.url
        $DeletedSite = $Null
        $StorageUsageCurrent = $Null
        $SPOSite = $Null
        $DeletedSite = Get-SPODeletedSite -Identity $URL
        Try
        {
            
            $SPOSite = Get-SPOSite $URL -Detailed
            $StorageUsageCurrent = $SPOSite.StorageUsageCurrent
        }
        Catch
        {
            $StorageUsageCurrent = "Not Found"
        }
        
        $Table += New-object PSobject -Property ([Ordered] @{
            Url = $DeletedSite.Url;
            StorageUsageCurrent = $StorageUsageCurrent;
            DeletionTime = $DeletedSite.DeletionTime;
            DaysRemaining = $DeletedSite.DaysRemaining;
        })
        
    }
    $Table | ft
}

Function Find-OneDriveUserURL
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN
    )
    
    $LocalPart = $UPN.Substring(0, $UPN.LastIndexOf("@"))
    $Filter = '*' + $LocalPart + '*'
    $SPOSites = Get-SPOSite -IncludePersonalSite:$true -limit All | where { $_.Url -like $Filter }
    $SPOSites | ft Owner, URL -AutoSize
}

Function Find-PnPOnedriveUserURL
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UPN
    )
    
    Get-PnPUserProfileProperty -Account $UPN | select personalUrl
    
}