Public/Grant-FSMTargetSharePermissions.ps1

function Grant-FSMTargetSharePermissions {
    <#
    .SYNOPSIS
        Applies exported share-level permissions to shares on a target file server.

    .DESCRIPTION
        Reads a permission CSV and applies each allow/deny entry to the matching share
        on the target. SMB deny entries are full denies by design, so the right is not
        needed for them.

        SAFETY: preview mode by default; add -Execute to apply. Each entry is handled in
        its own try/catch, so an unresolvable account (common when migrating between
        domains) becomes a 'Failed' row instead of stopping the run. Use -RemoveEveryone
        to strip the default Everyone permission after the real ones are applied.

    .PARAMETER TargetServer
        The file server to apply permissions on.

    .PARAMETER PermissionCsvPath
        Path to the permission CSV (from Export-FSMSharePermissions).

    .PARAMETER RemoveEveryone
        After applying permissions, remove the default Everyone entry from each share.

    .PARAMETER Credential
        Optional credentials for the remote connection.

    .PARAMETER Execute
        Actually apply changes. Without it, you get a preview only.

    .EXAMPLE
        Grant-FSMTargetSharePermissions -TargetServer newfs01 -PermissionCsvPath C:\Temp\perms.csv

    .EXAMPLE
        Grant-FSMTargetSharePermissions -TargetServer newfs01 -PermissionCsvPath C:\Temp\perms.csv -RemoveEveryone -Execute
    #>

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

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

        [switch]$RemoveEveryone,

        [pscredential]$Credential,

        [switch]$Execute
    )

    if (-not (Test-Path -Path $PermissionCsvPath)) {
        throw "Permission CSV not found: '$PermissionCsvPath'."
    }

    $permissions = @(Import-Csv -Path $PermissionCsvPath)
    Assert-FSMCsvColumn -InputObject $permissions `
        -RequiredColumn 'ShareName', 'AccountName', 'AccessControlType', 'AccessRight' `
        -Path $PermissionCsvPath

    # Each cast is parenthesised: in argument-parsing mode an unparenthesised
    # [bool]$Execute is read as the literal string '[bool]False', not a cast,
    # which then fails to bind to the remote [bool] parameters.
    Invoke-FSMRemote -ComputerName $TargetServer -Credential $Credential `
        -ArgumentList $permissions, ([bool]$RemoveEveryone), ([bool]$Execute) -ScriptBlock {
        param($Permissions, [bool]$RemoveEveryone, [bool]$Execute)

        foreach ($perm in $Permissions) {
            try {
                $shareExists = Get-SmbShare -Name $perm.ShareName -ErrorAction SilentlyContinue
                if (-not $shareExists) {
                    [pscustomobject]@{
                        ShareName = $perm.ShareName; Account = $perm.AccountName
                        Right = $perm.AccessRight; Type = $perm.AccessControlType
                        Action = 'Skipped'; Reason = 'Share does not exist on target'
                    }
                    continue
                }

                if (-not $Execute) {
                    [pscustomobject]@{
                        ShareName = $perm.ShareName; Account = $perm.AccountName
                        Right = $perm.AccessRight; Type = $perm.AccessControlType
                        Action = 'WhatIf'; Reason = 'Would apply permission. Re-run with -Execute to apply.'
                    }
                    continue
                }

                if ($perm.AccessControlType -eq 'Allow') {
                    Grant-SmbShareAccess -Name $perm.ShareName -AccountName $perm.AccountName `
                        -AccessRight $perm.AccessRight -Force -ErrorAction Stop | Out-Null
                }
                elseif ($perm.AccessControlType -eq 'Deny') {
                    Block-SmbShareAccess -Name $perm.ShareName -AccountName $perm.AccountName `
                        -Force -ErrorAction Stop | Out-Null
                }
                else {
                    throw "Unknown AccessControlType '$($perm.AccessControlType)'"
                }

                [pscustomobject]@{
                    ShareName = $perm.ShareName; Account = $perm.AccountName
                    Right = $perm.AccessRight; Type = $perm.AccessControlType
                    Action = 'Applied'; Reason = 'Permission applied'
                }
            }
            catch {
                [pscustomobject]@{
                    ShareName = $perm.ShareName; Account = $perm.AccountName
                    Right = $perm.AccessRight; Type = $perm.AccessControlType
                    Action = 'Failed'; Reason = $_.Exception.Message
                }
            }
        }

        if ($RemoveEveryone -and $Execute) {
            $Permissions.ShareName | Sort-Object -Unique | ForEach-Object {
                $shareName = $_
                try {
                    $everyonePerm = Get-SmbShareAccess -Name $shareName -ErrorAction SilentlyContinue |
                        Where-Object { $_.AccountName -in @('Everyone', 'BUILTIN\Everyone') }

                    foreach ($entry in $everyonePerm) {
                        Revoke-SmbShareAccess -Name $shareName -AccountName $entry.AccountName -Force -ErrorAction Stop | Out-Null
                        [pscustomobject]@{
                            ShareName = $shareName; Account = $entry.AccountName
                            Right = $entry.AccessRight; Type = $entry.AccessControlType
                            Action = 'Removed'; Reason = 'Default Everyone permission removed'
                        }
                    }
                }
                catch {
                    [pscustomobject]@{
                        ShareName = $shareName; Account = 'Everyone'
                        Right = $null; Type = $null
                        Action = 'Failed'; Reason = "Could not remove Everyone: $($_.Exception.Message)"
                    }
                }
            }
        }
    }
}