Public/Compare-FSMShareInventory.ps1

function Compare-FSMShareInventory {
    <#
    .SYNOPSIS
        Compares non-special shares between source and target file servers.

    .DESCRIPTION
        Lists shares on both servers and reports, per share name, whether it exists on
        both, only the source (still missing on target), or only the target. Use it as a
        post-migration verification pass.

    .PARAMETER SourceServer
        The original file server.

    .PARAMETER TargetServer
        The new file server.

    .PARAMETER ExcludeShareName
        Share names to skip. Defaults to the standard administrative/system shares.

    .PARAMETER Credential
        Optional credentials for the remote connections (used for both servers).

    .EXAMPLE
        Compare-FSMShareInventory -SourceServer oldfs01 -TargetServer newfs01
    #>

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

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

        [string[]]$ExcludeShareName = (Get-FSMDefaultExclusion),

        [pscredential]$Credential
    )

    $listScript = {
        param([string[]]$ExcludeShareName)
        Get-SmbShare |
            Where-Object { -not $_.Special -and $ExcludeShareName -notcontains $_.Name } |
            Select-Object Name, Path
    }

    $sourceShares = @(Invoke-FSMRemote -ComputerName $SourceServer -Credential $Credential -ArgumentList (,$ExcludeShareName) -ScriptBlock $listScript)
    $targetShares = @(Invoke-FSMRemote -ComputerName $TargetServer -Credential $Credential -ArgumentList (,$ExcludeShareName) -ScriptBlock $listScript)

    $sourceByName = @{}
    foreach ($share in $sourceShares) { $sourceByName[$share.Name] = $share }

    $targetByName = @{}
    foreach ($share in $targetShares) { $targetByName[$share.Name] = $share }

    $allNames = @($sourceByName.Keys) + @($targetByName.Keys) | Sort-Object -Unique

    foreach ($name in $allNames) {
        $inSource = $sourceByName.ContainsKey($name)
        $inTarget = $targetByName.ContainsKey($name)

        [pscustomobject]@{
            ShareName  = $name
            SourcePath = if ($inSource) { $sourceByName[$name].Path } else { $null }
            TargetPath = if ($inTarget) { $targetByName[$name].Path } else { $null }
            Status     = if ($inSource -and $inTarget) { 'ExistsOnBoth' }
                         elseif ($inSource)            { 'MissingOnTarget' }
                         else                          { 'OnlyOnTarget' }
        }
    }
}