# Copy-SMB-Share-Permissions.ps1

# Set some SMB Share variables
$sourceSmbPath="\\FILESERVER002\Home"
$destinationSmbPath="\\FILESERVER002-n\Home"
$dateStamp = Get-Date -Format "yyyy-MM-dd-hhmmss"
$logFile="C:\copySmbPermissions-Log-$dateStamp.txt"

function copySmbPermissions{
    param(
        [string]$sourceSmbSharePath,
        [string]$destinationSmbSharePath
        )

    # Set some variables
    $sourceSmbServerName = $sourceSmbSharePath.split("\")[2];
    $sourceSmbShareName = $sourceSmbSharePath.split("\")[3];
    $destinationSmbServerName = $destinationSmbSharePath.split("\")[2];
    $destinationSmbShareName = $destinationSmbSharePath.split("\")[3];
    $GLOBAL:messages="";

    # Legacy method to obtain SMB share permissions that would work with PowerShell 2.0 (Windows 2008)
    function getSmbPermmissions{
        param(
            [string]$smbServerName,
            [string]$smbPath
            )
        $smbShareName = $smbPath.split("\")[3]
        $smbList = Get-WmiObject win32_LogicalShareSecuritySetting -ComputerName $smbServerName|?{$_.Name -notlike "*$"}
        if($smbList){
            $sample=$smbList.Name[0];
            if($sample -match "^\\\\(.*)"){
                # This accounts for Clustered File Server Role
                $smbObject=$smbList|?{$_.Name -eq $smbPath};
                }else{
                    # This accounts for Standalone File Server Role
                    $smbObject=$smbList|?{$_.Name -eq $smbShareName};
                    }
            }else{
                $message="Failed to retrieve SMB Permissions from $smbServerName";
                $GLOBAL:messages+=$message+"`r`n";
                write-host $message -ForegroundColor Yellow;
                $smbObject=$false;
                }

        if($smbObject){
            $message="Collecting share permissions for $smbPath...";
            $GLOBAL:messages+=$message+"`r`n";
            Write-Host $message;
            $smbPermissions = @()
            $acls = $smbObject.GetSecurityDescriptor().Descriptor.DACL
            foreach($acl in $acls){
                $user = $acl.Trustee.Name
                if(!($user)){$user = $acl.Trustee.SID}
                $domain = $acl.Trustee.Domain
                switch($acl.AccessMask){
                    2032127 {$accessRight = "Full"}
                    1245631 {$accessRight = "Change"}
                    1179817 {$accessRight = "Read"}
                    }          
                $smbPermissions+=[PSCustomObject]@{IdentityReference="$domain\$user";AccessRight=$accessRight};
                }
            return $smbPermissions;
            }else{
                return $false;
                }
    }

    # This function requires PowerShell 4.0 and higher
    function setSmbPermissions{
        param(
            $smbName=$destinationSmbShareName,
            $fileServerRole=$destinationSmbServerName,
            $smbPermissions=$sourceSmbPermissions
            )
        # Locate the host for the file server role
        $roleOwner=(Get-ClusterResource -Name $fileServerRole -ErrorAction SilentlyContinue).OwnerNode.Name
        
        if ($roleOwner){
            # Connect to host
            $message="Connecting to remote computer $roleOwner...";
            $GLOBAL:messages+=$message;
            write-host $message;
            $maxTime=10; $duration=0;
            do{
                $session = New-PSSession -ComputerName $roleOwner -ErrorAction SilentlyContinue;
                if (!($session)){
                    write-host "." -NoNewline;
                    $duration++;
                    sleep -seconds 1;
                    }
                if ($session){
                    $message=".. Connected in $duration seconds.";
                    $GLOBAL:messages+=$message+"`r`n";
                    write-host $message -NoNewline;
                    }
                } until ($session.state -match "Opened" -or $duration -eq $maxTime)

            if($session){
                $message="Setting share permissions for $smbName of $fileServerRole, currently owned by $roleOwner...";
                $GLOBAL:messages+=$message+"`r`n";
                Write-Host $message;
                $invokeCommandResult=Invoke-Command -Session $session -ScriptBlock{
                            param($smbName,$fileServerRole,$smbPermissions)

                            # Declare some variables;
                            [int]$successCount=0;
                            [int]$failuresCount=0;
                            [bool]$singleItem=$smbPermissions.Count -eq $null -or $smbPermissions.Count -eq 1;
                            [string]$sessionMessages="";

                            foreach ($permission in $smbPermissions){
                                $identityReference=$permission.IdentityReference;
                                # This accounts for non-domain accounts
                                if($identityReference -match "^\\[^\\]+$"){$identityReference=$identityReference.SubString(1,$identityReference.Length-1)}
                                $accessRight=$permission.AccessRight;
                                $expression="Grant-SmbShareAccess -Name $smbName -ScopeName $fileServerRole -AccountName '$identityReference' -AccessRight $accessRight -Force";

                                # Using self executing anonymous function to exit try-loop upon failures
                                .{
                                    try{
                                        $success=Invoke-Expression $expression;
                                        if(!($success)) {
                                            $failuresCount++;                                       
                                            $success=$false;
                                            return; # Exit try-loop
                                            }
                                        $successCount++;                                     
                                        $success=$true;                              
                                        }
                                    catch{
                                        write-host $Error;
                                        }                      
                                }
                            if($success){
                                $message="$expression => Success";
                                $sessionMessages+=$message+"`r`n";
                                write-host $message;
                                }else{
                                    $message="$expression => Failure"
                                    $sessionMessages+=$message+"`r`n";
                                    write-host $message -ForegroundColor Yellow;
                                    }
                            }

                            if ($singleItem){
                                $message="$successCount of 1 permission set is successful.";
                                $sessionMessages+=$message+"`r`n";
                                write-host $message;
                                }else{
                                    $message="$successCount of $($smbPermissions.Count) permission settings are successful.";
                                    $sessionMessages+=$message+"`r`n";
                                    write-host $message;                                    
                                    }
                            $overallResult=$failuresCount -eq 0;
                            $outputArray=@($overallResult,$sessionMessages)
                            return $outputArray;
                        } -Args $smbName,$fileServerRole,$smbPermissions
                Remove-PSSession $session;

                $GLOBAL:messages+=$invokeCommandResult[1]+"`r`n";                
                $result=$invokeCommandResult[0];                
                }else{
                    $message="Unable to connect to $roleOwner.";
                    $GLOBAL:messages+=$message+"`r`n";
                    write-host $message -ForegroundColor Red;
                    $result=$false;
                    }
            }else{
                    $message="Unable to get owner node for $fileServerRole.";
                    $GLOBAL:messages+=$message+"`r`n";
                    write-host $message -ForegroundColor Red;
                    $result=$false;
                    }
        return $result;
        }

    $sourceSmbPermissions=getSmbPermmissions -smbServerName $sourceSmbServerName -smbPath $sourceSmbSharePath
    if ($sourceSmbPermissions){
        $success=setSmbPermissions -smbName $destinationSmbShareName -fileServerRole $destinationSmbServerName -smbPermissions $sourceSmbPermissions
        if ($success){
            $message="Permissions from $sourceSmbSharePath have been successfully copied to $destinationSmbSharePath.";
            $GLOBAL:messages+=$message+"`r`n";
            write-host $message;
            return $true;
                }else{
                $message="Unable to *SET* SMB Permissions to destination $destinationSmbSharePath.";
                $GLOBAL:messages+=$message+"`r`n";
                write-host $message -ForegroundColor Red;
                return $false;
                }
        }else{
            $message="Unable to *GET* SMB Permissions from $sourceSmbSharePath.";
            $GLOBAL:messages+=$message+"`r`n";
            write-host $message -ForegroundColor Yellow;
            return $false;
            }
}

copySmbPermissions -sourceSmbSharePath $sourceSmbPath -destinationSmbSharePath $destinationSmbPath
#Add-Content $logFile $messages;