PowerShell.PowerLibrary.RoboCopyExtension.psm1

<#
    Copy Files is based on ROBOCOPY :: Robust File Copy for Windows
#>

Function Copy-FilesByRoboCopy 
{
    <#
    .Synopsis
        Use this Function to utilize Robo Copy.
    .DESCRIPTION
        Wrapper on top of RoboCopy
    .PARAMETER Source
        Where to Read Files to be copied/moved.
    .PARAMETER Destination
        Where to copy/move files.
    .PARAMETER CopySubdirectories
        Enable Recursive Copy.
    .PARAMETER Mode
        Set the Read Mode.
        Z :: copy files in restartable mode. B :: copy files in Backup mode. ZB :: use restartable mode; if access denied use Backup mode.
    .PARAMETER CopyFlags
        What to COPY for files (default is /COPY:DAT). (copyflags : D=Data, A=Attributes, T=Timestamps). (S=Security=NTFS ACLs, O=Owner info, U=aUditing info)
    .PARAMETER DirectoryCopyFlags
        What to COPY for directories (default is /DCOPY:DA). (copyflags : D=Data, A=Attributes, T=Timestamps)
    .PARAMETER Purge
        Delete dest files/dirs that no longer exist in source.
    .PARAMETER LogToDestination
        Logs Job Output to log file in destination.
    .PARAMETER LogToDestinationDateFormat
        DateTime Format. Example: yyyy-MM-dd
    .PARAMETER ScriptingOptions
        Of Type [Microsoft.SqlServer.Management.Smo.ScriptingOptions]
    .PARAMETER ExcludedFiles
        Files to be excluded
    .PARAMETER ExcludedDirectories
        Directories to be excluded
    .PARAMETER Parameters
        Extra parameters to be sent to robocopy
    #>


    param
    (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
        [string]
        $Source,
        
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1)]
        [string]
        $Destination,

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'Copy Subdirectories, but not empty ones')]
        [Alias("S")]
        [switch]
        $CopySubdirectories,

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'Z :: copy files in restartable mode. B :: copy files in Backup mode. ZB :: use restartable mode; if access denied use Backup mode.')]
        [Alias("M")]
        [ValidatePattern("^[Z,z]?[B,b]?$")]
        [string]
        $Mode = "B",

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'What to COPY for files (default is /COPY:DAT). (copyflags : D=Data, A=Attributes, T=Timestamps). (S=Security=NTFS ACLs, O=Owner info, U=aUditing info)')]
        [Alias("C")]
        [ValidatePattern("^[D,d]?[A,a]?[T,t]?[S,s]?[O,o]?[U,u]?$")]
        [string]
        $CopyFlags = "DAT",

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'What to COPY for directories (default is /DCOPY:DA). (copyflags : D=Data, A=Attributes, T=Timestamps)')]
        [Alias("DC")]
        [ValidatePattern("^[D,d]?[A,a]?[T,t]?$")]
        [string]
        $DirectoryCopyFlags = "DAT",

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'Delete dest files/dirs that no longer exist in source.')]
        [Alias("P")]
        [switch]
        $Purge,

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'Logs Job Output to log file in destination.')]
        [Alias("Log")]
        [switch]
        $LogToDestination,

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'DateTime Format. Example: yyyy-MM-dd')]
        [Alias("LogF")]
        [string]
        $LogToDestinationDateFormat = 'yyyy-MM-dd',
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $true)]
        [string[]]
        $ExcludedFiles,
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $true)]
        [string[]]
        $ExcludedDirectories,
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $true)]
        [string[]]
        $Parameters
    );

    $TrackedParameters = [System.Collections.Generic.List[string]]::new();
    $Tracker = [System.Collections.Hashtable]::new();
    $LogToDestinationId = Get-UniqueId '$LogToDestination';
    $CopySubdirectoriesId = Get-UniqueId '$CopySubdirectories';
    $ModeId = Get-UniqueId '$Mode';
    $CopyFlagsId = Get-UniqueId '$CopyFlags';
    $DirectoryCopyFlagsId = Get-UniqueId '$DirectoryCopyFlags';
    $PurgeId = Get-UniqueId '$Purge';
    $ExcludedFilesId = Get-UniqueId '$ExcludedFiles';
    $ExcludedDirectoriesId = Get-UniqueId '$ExcludedDirectories';
    $VerboseId = Get-UniqueId 'Verbose';
    $__ = $Tracker.Add($CopySubdirectoriesId, $false);
    $__ = $Tracker.Add($ModeId, $false);
    $__ = $Tracker.Add($CopyFlagsId, $false);
    $__ = $Tracker.Add($DirectoryCopyFlagsId, $false);
    $__ = $Tracker.Add($PurgeId, $false);
    $__ = $Tracker.Add($ExcludedFilesId, $false);
    $__ = $Tracker.Add($ExcludedDirectoriesId, $false);
    IF($null -ne $Parameters -and $Parameters.Length -gt 0)
    {
        foreach($Parameter in $Parameters)
        {
            $Parameter = $Parameter.ToLowerInvariant();
            IF($Parameter -ccontains '/log:' -or $Parameter -ccontains '/log+:')
            {
                $Tracker[$LogToDestinationId] = $true; 
            }
            IF($Parameter -ceq "/s")
            { 
                $Tracker[$CopySubdirectoriesId] = $true; 
            }
            IF($Parameter -ceq "/v")
            { 
                $Tracker[$VerboseId] = $true; 
            }
            IF($Parameter -ceq "/purge")
            { 
                $Tracker[$PurgeId] = $true; 
            }
            IF(@("/b", "/z", "/zb") -ccontains $Parameter)
            {
                $Tracker[$ModeId] = $true; 
            }
            IF($Parameter -ccontains "/copy:")
            {
                $Tracker[$CopyFlagsId] = $true; 
            }
            IF($Parameter -ccontains "/dcopy:")
            {
                $Tracker[$DirectoryCopyFlagsId] = $true; 
            }
            IF($Parameter -ccontains "/xf")
            {
                $Tracker[$ExcludedFilesId] = $true; 
            }
            IF($Parameter -ccontains "/xd")
            {
                $Tracker[$ExcludedDirectoriesId] = $true; 
            }
            $TrackedParameters.Add($Parameter);
        }
        $Parameters | ForEach-Object{ $TrackedParameters.Add($_.ToLowerInvariant()); }
    }

    IF($PSBoundParameters["Verbose"].IsPresent -and !$Tracker[$VerboseId])
    {
        $__ = $TrackedParameters.Add("/v");
    }

    IF($LogToDestination.IsPresent -and !$Tracker[$LogToDestinationId])
    {
        $__ = $TrackedParameters.Add("/log:$Destination-$([datetime]::Today.ToString($LogToDestinationDateFormat)).log");
        $__ = $TrackedParameters.Add("/tee");
    }

    IF($CopySubdirectories.IsPresent -and !$Tracker[$CopySubdirectoriesId])
    {
        $__ = $TrackedParameters.Add("/s");
    }

    IF(![string]::IsNullOrWhiteSpace($Mode) -and !$Tracker[$ModeId])
    {
        $__ = $TrackedParameters.Add("/$($Mode.ToLowerInvariant())");
    }

    IF(![string]::IsNullOrWhiteSpace($CopyFlags) -and !$Tracker[$CopyFlagsId])
    {
        $__ = $TrackedParameters.Add("/copy:$($CopyFlags.ToLowerInvariant())");
    }

    IF(![string]::IsNullOrWhiteSpace($DirectoryCopyFlags) -and !$Tracker[$DirectoryCopyFlagsId])
    {
        $__ = $TrackedParameters.Add("/dcopy:$($DirectoryCopyFlags.ToLowerInvariant())");
    }

    IF($CopySubdirectories.IsPresent -and !$Tracker[$PurgeId])
    {
        $__ = $TrackedParameters.Add("/purge");
    }

    IF($null -ne $ExcludedFiles -and $ExcludedFiles.Length -gt 0 -and !$Tracker[$ExcludedFilesId])
    {
        $__ = $TrackedParameters.Add("/xf");
        $TrackedParameters.AddRange($ExcludedFiles);
    }

    IF($null -ne $ExcludedDirectories -and $ExcludedDirectories.Length -gt 0 -and !$Tracker[$ExcludedDirectoriesId])
    {
        $__ = $TrackedParameters.Add("/xd");
        $TrackedParameters.AddRange($ExcludedDirectories);
    }
    
    $Arguments = [System.Collections.ArrayList]::new();
    $__ = $Arguments.Add($Source);
    $__ = $Arguments.Add($Destination);
    $__ = $Arguments.AddRange($TrackedParameters);
    RETURN & ROBOCOPY $Arguments;
}
Set-Alias -Name RoboCopy-Files -Value Copy-FilesByRoboCopy;