Private/Publish-FolderToSharePoint.ps1

<#
.SYNOPSIS
Recursively uploads a local folder and its contents to a SharePoint Online document library using optional secure authentication.
 
.DESCRIPTION
The Publish-FolderToSharePoint function uploads all files and subfolders from a specified local directory to a SharePoint Online document library. It supports secure authentication using encrypted passcodes or fallback to interactive login (UseWebLogin). Folder structure is preserved on SharePoint, and folders are created dynamically if missing.
 
.PARAMETER LocalFolderPath
Specifies the full path of the local folder whose contents are to be uploaded.
 
.PARAMETER SharePointSiteUrl
The URL of the SharePoint Online site to which files will be uploaded.
 
.PARAMETER SharePointFolderRelativeUrl
The server-relative URL of the SharePoint folder where content should be placed (e.g., "Shared Documents/Reports").
 
.PARAMETER Username
The SharePoint or Microsoft 365 account username used for secure authentication. If omitted, interactive login will be used.
 
.PARAMETER Passcode
Encrypted passcode string that is decrypted using the username to derive the password. Used only if Username is provided.
 
.EXAMPLE
Publish-FolderToSharePoint `
    -LocalFolderPath "C:\Reports\Citrix" `
    -SharePointSiteUrl "https://company.sharepoint.com/sites/ITCMR" `
    -SharePointFolderRelativeUrl "Shared Documents/Reports/Citrix"
 
.EXAMPLE
Publish-FolderToSharePoint `
    -LocalFolderPath "C:\Exports" `
    -SharePointSiteUrl "https://company.sharepoint.com/sites/Finance" `
    -SharePointFolderRelativeUrl "Documents/FY24" `
    -Username "service.sharepoint@company.com" `
    -Passcode "Base64EncryptedPass123..."
 
.NOTES
- Requires the PnP PowerShell module (Install-Module PnP.PowerShell).
- Uses Write-LogEntry for logging actions and status.
- Handles recursive file and folder upload with SharePoint folder checks.
#>



function Publish-FolderToSharePoint {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$LocalFolderPath,
        
        [Parameter(Mandatory = $true)]
        [string]$SharePointSiteUrl,
        
        [Parameter(Mandatory = $true)]
        [string]$SharePointFolderRelativeUrl,

        [Parameter(Mandatory = $false)]
        [string]$Username,

        [Parameter(Mandatory = $false)]
        [string]$Passcode
    )

    try {
        if ($PSBoundParameters.ContainsKey("Username") -and $PSBoundParameters.ContainsKey("Passcode")) {
            $passwordPlain = ConvertFrom-SecurePasscode -Passcode $Passcode -Username $Username
            $securePassword = ConvertTo-SecureString $passwordPlain -AsPlainText -Force
            $credential = New-Object System.Management.Automation.PSCredential ($Username, $securePassword)
            Connect-PnPOnline -Url $SharePointSiteUrl -Credentials $credential
        }
        else {
            Connect-PnPOnline -Url $SharePointSiteUrl -UseWebLogin
        }

        function Upload-Recursive {
            param (
                [string]$CurrentPath,
                [string]$CurrentSPPath
            )

            Get-ChildItem -Path $CurrentPath -File | ForEach-Object {
                $destination = "$CurrentSPPath/$($_.Name)"
                Write-LogEntry -Message "⬆ Uploading: $($_.FullName) → $destination"
                Add-PnPFile -Path $_.FullName -Folder $CurrentSPPath -ErrorAction SilentlyContinue
            }

            Get-ChildItem -Path $CurrentPath -Directory | ForEach-Object {
                $subSPPath = "$CurrentSPPath/$($_.Name)"

                if (-not (Get-PnPFolder -Url $subSPPath -ErrorAction SilentlyContinue)) {
                    Write-LogEntry -Message "📁 Creating SharePoint folder: $subSPPath"
                    Add-PnPFolder -Name $_.Name -Folder $CurrentSPPath
                }

                Upload-Recursive -CurrentPath $_.FullName -CurrentSPPath $subSPPath
            }
        }

        Upload-Recursive -CurrentPath $LocalFolderPath -CurrentSPPath $SharePointFolderRelativeUrl
    }
    catch {
        Write-LogEntry -Message "❌ Upload failed: $_"
    }
    finally {
        Disconnect-PnPOnline
    }
}