Public/Invoke-FSMShareMigrationPrep.ps1

function Invoke-FSMShareMigrationPrep {
    <#
    .SYNOPSIS
        Runs the full export -> optional remap -> create -> grant -> compare workflow,
        with a clean summary at the end.

    .DESCRIPTION
        One-button orchestration of the whole share-prep process. It exports shares and
        permissions from the source, optionally remaps paths, creates the shares on the
        target, applies permissions, and verifies the result, then prints a tallied
        summary (Created / Skipped / Failed / etc.).

        SAFETY: preview by default; add -Execute to make changes. With -LogPath, all
        result objects are written to dated CSVs and a transcript is captured.

    .PARAMETER SourceServer
        The original file server.

    .PARAMETER TargetServer
        The new file server.

    .PARAMETER WorkingPath
        Folder for the generated CSVs (and logs, if -LogPath is not given separately).

    .PARAMETER OldRoot
        Optional. If both OldRoot and NewRoot are supplied, paths are remapped.

    .PARAMETER NewRoot
        Optional replacement root for OldRoot.

    .PARAMETER DefaultFullAccess
        Initial Full Access principal(s) at share creation. Default 'Everyone'.

    .PARAMETER Credential
        Optional credentials used for every remote connection.

    .PARAMETER LogPath
        Optional folder to write result CSVs and a transcript to.

    .PARAMETER RemoveEveryone
        Strip the default Everyone permission after applying real permissions.

    .PARAMETER Execute
        Actually create shares and apply permissions. Without it, everything is a preview.

    .EXAMPLE
        Invoke-FSMShareMigrationPrep -SourceServer oldfs01 -TargetServer newfs01 -WorkingPath C:\Temp\FSMig

    .EXAMPLE
        Invoke-FSMShareMigrationPrep -SourceServer oldfs01 -TargetServer newfs01 -WorkingPath C:\Temp\FSMig `
            -OldRoot 'D:\Shares' -NewRoot 'E:\Data' -RemoveEveryone -LogPath C:\Temp\FSMig\Logs -Execute
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$SourceServer,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$TargetServer,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$WorkingPath,

        [string]$OldRoot,

        [string]$NewRoot,

        [string[]]$DefaultFullAccess = @('Everyone'),

        [pscredential]$Credential,

        [string]$LogPath,

        [switch]$RemoveEveryone,

        [switch]$Execute
    )

    if (($OldRoot -and -not $NewRoot) -or ($NewRoot -and -not $OldRoot)) {
        throw "OldRoot and NewRoot must be supplied together (or neither)."
    }

    if (-not (Test-Path -Path $WorkingPath)) {
        New-Item -Path $WorkingPath -ItemType Directory -Force | Out-Null
    }

    $transcriptStarted = $false
    if ($LogPath) {
        if (-not (Test-Path -Path $LogPath)) { New-Item -Path $LogPath -ItemType Directory -Force | Out-Null }
        $stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
        try {
            Start-Transcript -Path (Join-Path $LogPath "FSMigration-$stamp.log") -ErrorAction Stop | Out-Null
            $transcriptStarted = $true
        }
        catch {
            Write-FSMStatus -Message "Could not start transcript: $($_.Exception.Message)" -Level Warning
        }
    }

    try {
        $mode = if ($Execute) { 'EXECUTE (changes will be made)' } else { 'PREVIEW (no changes)' }
        Write-FSMStatus -Message "File share migration prep | $SourceServer -> $TargetServer | Mode: $mode" -Level Information

        $shareCsv      = Join-Path $WorkingPath "$SourceServer-shares.csv"
        $permissionCsv = Join-Path $WorkingPath "$SourceServer-share-permissions.csv"
        $targetShareCsv = $shareCsv

        Export-FSMShareInventory  -SourceServer $SourceServer -OutputPath $shareCsv      -Credential $Credential | Out-Null
        Export-FSMSharePermissions -SourceServer $SourceServer -OutputPath $permissionCsv -Credential $Credential | Out-Null

        if ($OldRoot -and $NewRoot) {
            $targetShareCsv = Join-Path $WorkingPath "$SourceServer-shares-remapped-for-$TargetServer.csv"
            Convert-FSMSharePath -InputPath $shareCsv -OutputPath $targetShareCsv -OldRoot $OldRoot -NewRoot $NewRoot | Out-Null
        }

        Write-FSMStatus -Message 'Creating target shares...' -Level Information
        $createResults = @(New-FSMTargetShares -TargetServer $TargetServer -ShareCsvPath $targetShareCsv `
            -DefaultFullAccess $DefaultFullAccess -Credential $Credential -Execute:$Execute)

        Write-FSMStatus -Message 'Applying share permissions...' -Level Information
        $grantResults = @(Grant-FSMTargetSharePermissions -TargetServer $TargetServer -PermissionCsvPath $permissionCsv `
            -RemoveEveryone:$RemoveEveryone -Credential $Credential -Execute:$Execute)

        Write-FSMStatus -Message 'Comparing source and target shares...' -Level Information
        $compareResults = @(Compare-FSMShareInventory -SourceServer $SourceServer -TargetServer $TargetServer -Credential $Credential)

        if ($LogPath) {
            $stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
            $createResults  | Export-Csv (Join-Path $LogPath "create-results-$stamp.csv")  -NoTypeInformation -Encoding UTF8
            $grantResults   | Export-Csv (Join-Path $LogPath "grant-results-$stamp.csv")   -NoTypeInformation -Encoding UTF8
            $compareResults | Export-Csv (Join-Path $LogPath "compare-results-$stamp.csv") -NoTypeInformation -Encoding UTF8
        }

        $createSummary = Show-FSMResultSummary -Result $createResults -Title 'Share creation'
        $grantSummary  = Show-FSMResultSummary -Result $grantResults  -Title 'Permission application'
        $missing = @($compareResults | Where-Object Status -eq 'MissingOnTarget')
        if ($missing.Count) {
            Write-FSMStatus -Message "$($missing.Count) share(s) still MISSING on target: $($missing.ShareName -join ', ')" -Level Warning
        } else {
            Write-FSMStatus -Message 'All source shares present on target.' -Level Success
        }

        # Return everything as one structured object for capture/automation.
        [pscustomobject]@{
            Mode            = if ($Execute) { 'Execute' } else { 'Preview' }
            CreateResults   = $createResults
            GrantResults    = $grantResults
            CompareResults  = $compareResults
            CreateSummary   = $createSummary
            GrantSummary    = $grantSummary
            MissingOnTarget = $missing.ShareName
        }
    }
    finally {
        if ($transcriptStarted) { Stop-Transcript | Out-Null }
    }
}