Export-ArchiveFile.ps1

<#
.SYNOPSIS
Export and Archive files.
 
.DESCRIPTION
The Export-Archive command can be used to archive files. If required zipped and packaged into a single file.
 
.PARAMETER SourcePath
The Source file path that file/s need to be Exported. This path needs to be a folder
 
.PARAMETER DestinationPath
The Destination path the Exoported files need to be Copied/Moved
 
.PARAMETER FileType
File Type to archive. Multiple file types are supported with comma separation
Example “*.csv,*ps1,*.log”
 
.PARAMETER ArchiveFilesOlderthan
Export files older than the specified number of days. Example if all files older than 10 days needs to be exported.
use value of 10
 
.PARAMETER ArchiveToZip
This optional parameter is used to specify if the destination exported file/s needs to be zipped.
If this parameter is specified the ArchiveFilename parameter is Visible.
 
.PARAMETER ArchiveFileName
If the ArchiveToZip parameter is specified. This parameter is enabled.
Use this optional parameter to specify the Zip file name
 
.PARAMETER DeleteFilesFromSource
If this optional parameter is specified files from the source directory is deleted(removed) after file has been exported
 
.PARAMETER Verify
This parameter is used to verify that the source and destination files match on completion of the export process.
The output of this will only be displayed if the -verbose switch is used
 
.PARAMETER Recurse
Indicates that this gets the items in the specified locations and in all child items of the locations.
 
.PARAMETER Force
Indicates that this command will overwrite items that cannot otherwise be changed, such as copying over a read-only
file or alias.
 
.EXAMPLE
Export-ArchiveFile -SourcePath C:\scripts\ -DestinationPath C:\test\ -FileType "*.csv" -ArchiveFilesOlderthan 20 -ArchiveToZip - -Verify -Force -Recurse -Verbose
 
.EXAMPLE
 
Export-ArchiveFile -SourcePath C:\scripts\ -DestinationPath C:\test\ -FileType "*.csv" -ArchiveFilesOlderthan 20 -ArchiveToZip -ArchiveFileName Test.zip -Verify -Force -Recurse -Verbose
 
 
.NOTES
The Export-Archive can be used to archive all files and subfolders. If the -force switch is used all duplicate files will be overwritten in the destination
If the -force switch is used in conjunction with -ArchiveToZip the Zip file will be overwritten and updated
If the -force switch is used in conjunction with - DeleteFilesFromSource
the files will be deleted from the source even if file verification on both source and destination do not match
 
#>

Function Export-ArchiveFile {

    [cmdletbinding(DefaultParameterSetName='None')]
    param(
    [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,Mandatory=$True,HelpMessage="Log File Path",Position=0,ParameterSetName="Archive")]
    [ValidateScript({test-path -path $_ -type container})]
    [string]$SourcePath,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$True,HelpMessage="Destination file path",ParameterSetName="Archive")]
    [ValidateScript({test-path -path $_ -type container})]
    [string]$DestinationPath,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$True,HelpMessage="File Type to Archive, Example `"*.txt,*.csv`"",Position=1,ParameterSetName="Archive")]
    [string[]]$FileType,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$True,HelpMessage="Log files to archive in days",Position=2,ParameterSetName="Archive")]
    [int]$ArchiveFilesOlderthan,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$false,HelpMessage="zip Archive Folder",ParameterSetName='Archive',Position=3)]
    [switch]$ArchiveToZip,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$false,HelpMessage="Archive file name",ParameterSetName='Archive',Position=4)]
    [switch]$DeleteFilesFromSource,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$False,HelpMessage="verify that all files have been archived",ParameterSetName="Archive")]
    [switch]$Verify,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$False,HelpMessage="recurse through all subfolders",ParameterSetName="Archive")]
    [switch]$Recurse,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$False,HelpMessage="Force file overwrite",ParameterSetName="Archive")]
    [switch]$Force
    )

    DynamicParam{
        
        if($ArchiveToZip -eq $True){
            $ParameterName = 'ArchiveFileName'
            $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
            $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
            $ParameterAttribute.Mandatory = $False
            $ParameterAttribute.Position = 6
            $ParameterAttribute.ParameterSetName ="Archive"
            $AttributeCollection.Add($ParameterAttribute)
            $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
            $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
            return $RuntimeParameterDictionary
        }#IF
    }





    BEGIN{
        if($ArchiveToZip -eq $True){
            $ArchiveFileName = $PSBoundParameters[$ParameterName]
        }#IF
        Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] Starting: $($MyInvocation.MyCommand)"
        Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] PSVersion = $($PSVersionTable.PSVersion)"
        Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] OS = $((Get-CimInstance win32_OperatingSystem).Caption)"
        Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] User = $($env:userdomain)\$($env:USERNAME)"
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $IsAdmin = [System.Security.Principal.WindowsPrincipal]::new($id).IsInRole('administrators')
        Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] Is Admin = $IsAdmin"
    }#BEGIN


    PROCESS{
            #initialize variable
            $ExportZipFileName = $null
            #check and remove extra \ from source path if specified
            $SourcePath = $SourcePath -replace "\\$"
            #check and remove extra \ from Destination path if specified
            $DestinationPath = $DestinationPath -replace "\\$"
            #Split the file types so it can be passed into get-childitem
            $FileType = $FileType -split ","
            $ArchiveDateDate = (Get-Date).AddDays(-$ArchiveFilesOlderthan)
                if($Recurse.IsPresent)
                {
                    Write-Verbose "Recurse switch detected"
                    Get-ChildItem -Path $SourcePath\* -Include $FileType -Recurse | Where-Object {$_.LastWriteTime -le $ArchiveDateDate} -OutVariable FilesToArchive | Out-Null
                }#IF
                else
                {
                    Get-ChildItem -Path $SourcePath\* -Include $FileType | Where-Object {$_.LastWriteTime -le $ArchiveDateDate} -OutVariable FilesToArchive | Out-Null   
                }#Else

                if(!$FilesToArchive){                
                        Write-Verbose "No files to Archive"
                    }#IF
                else{
                        $Count = $FilesToArchive.count
                        
                        for($i=0 ;$i -lt $Count;$i++){
                            Write-Progress -Activity "File Archive Progress" -Status  "File: : $($FilesToArchive[$i].Name)" -PercentComplete ($i/$Count*100)
                            $DestinationFilePathToCopy = $DestinationPath + ($FilesToArchive[$i].FullName | Split-Path -NoQualifier) 
                            Write-Verbose "$($FilesToArchive[$i].Name) is older than $($ArchiveFilesOlderthan) days and will be Exported"
                                if((Test-Path $DestinationFilePathToCopy -PathType Leaf) -eq $False){
                                    Write-Verbose "$($FilesToArchive[$i].Name) does not exist and will be created"
                                    New-Item -Path $DestinationFilePathToCopy -ItemType File -Force | Out-Null
                                }#IF
                                elseif (!$Force.isPresent){
                                    Write-Verbose "$($FilesToArchive[$i].Name) already exists in destination and will not be overwritten"
                                    continue
                                }#Elseif

                            Write-Verbose "Moving $($FilesToArchive[$i].Name) to $($DestinationPath)"

                            switch($DeleteFilesFromSource)
                            {
                                true{
                                    Write-Verbose "DeleteFilesFromSource switch detected"
                                    Move-Item $($FilesToArchive[$i].FullName) -Destination $DestinationFilePathToCopy -Force | Out-Null -ErrorAction Stop
                                    
                                }#True

                                false{
                                    Copy-Item $($FilesToArchive[$i].FullName) -Destination $DestinationFilePathToCopy -Force | Out-Null -ErrorAction Stop
                                    
                                }#False

                            }#Switch
                           
                        }#for


                }#Else

       
        if($ArchiveToZip.IsPresent){
            Write-Verbose "Archive to zip switch detected"
            $CurrentPath = ($FilesToArchive[0].DirectoryName | Split-Path -NoQualifier)
            $TopLevelZipPath = $CurrentPath -split '\\'
            $ZipFilePath = $DestinationPath+"\"+$TopLevelZipPath[1]
            
            
            if($ArchiveFileName){ 
                $FileStatus = ((Test-Path -Path $DestinationPath\$ArchiveFileName".zip" -PathType Leaf))
                switch($FileStatus) {
                    True 
                    {
                        if($Force.IsPresent)
                        {
                            Write-Verbose "Creating zip $($DestinationPath)\$($ArchiveFileName).zip"    
                            Compress-Archive -Path $ZipFilePath -DestinationPath $DestinationPath\$ArchiveFileName -Update -CompressionLevel Optimal
                            $ExportZipFileName = "$($DestinationPath)\$($ArchiveFileName)"
                            
                        }#if
                        else{
                            Write-Verbose "cannot create zipfile $($DestinationPath)\$($ArchiveFileName).zip already exists"
                            continue
                        }#else
                    }#True
                    False 
                    {
                        Write-Verbose "Creating zip $($DestinationPath)\$($ArchiveFileName).zip"   
                        Compress-Archive -Path $ZipFilePath -DestinationPath $DestinationPath\$ArchiveFileName -force -CompressionLevel Optimal
                        $ExportZipFileName = "$($DestinationPath)\$($ArchiveFileName)"
                    }#False
                }#Switch
            }#IF
              
            else
            {
                #If an Archive file name is not spcified the Source folders top level folder will be used as the zip file name
                $NewArchiveFileName = $TopLevelZipPath[1]
                $FileStatus = ((Test-Path -Path $DestinationPath\$NewArchiveFileName".zip" -PathType Leaf))
                switch($FileStatus) 
                {
                    True
                    {
                        if($Force.IsPresent)
                        {
                        Write-Verbose "Creating zip $($DestinationPath)\$($NewArchiveFileName).zip"    
                        Compress-Archive -Path $ZipFilePath -DestinationPath $DestinationPath\$NewArchiveFileName -Update -CompressionLevel Optimal
                        $ExportZipFileName = "$($DestinationPath)\$($NewArchiveFileName)"              
                        }#if
                        else{
                        Write-Verbose "cannot create zipfile $($DestinationPath)\$($NewArchiveFileName).zip already exists"
                        continue
                        }#else
                    }#True

                    False
                    {
                        Write-Verbose "Creating zip $($DestinationPath)\$($NewArchiveFileName).zip"   
                        Compress-Archive -Path $ZipFilePath -DestinationPath $DestinationPath\$NewArchiveFileName -force -CompressionLevel Optimal
                        $ExportZipFileName = "$($DestinationPath)\$($NewArchiveFileName)"  
                    }#False
                   
                }#Switch
            }#else
        

        }#IF


    
        For($i=0;$i -lt $FilesToArchive.Count;$i++){

            $Properties = [ordered]@{
                "FileName" = $FilesToArchive[$i]
                "Location" = $DestinationPath
                "LastWriteTime" =$FilesToArchive[$i].LastWriteTime
            }#Properties
            $FilesProcessed = New-Object -TypeName psobject -Property $Properties
            $FilesProcessed
        }#For
        if($ArchiveToZip.isPresent){
            Write-Verbose "Total Files Exported $($FilesToArchive.Count)"
            Write-Verbose "$($ExportZipFileName).zip was created in $($DestinationPath)" 
        }#IF
        
    } #Process
    END {
        Switch($Verify.IsPresent){
            True{
                Write-Verbose "File Verification switch detected"
                $ArchiveVerifyPath = ($DestinationPath + ($SourcePath | Split-Path -NoQualifier))
                if($Recurse.IsPresent)
                    {
                    $FilesInArchive = Get-ChildItem $ArchiveVerifyPath\* -Include $FileType -Recurse
                    
                    }#IF
                    else 
                    {
                    $FilesInArchive = Get-ChildItem  $ArchiveVerifyPath\* -Include $FileType
                    
                    }#Else

                if($FilesToArchive.Count -eq $FilesInArchive.Count)
                    {
                        Write-Verbose    "FILE VERIFICATION PASSED"
                        Write-Verbose    "Files in Archive = $($FilesInArchive.Count)"
                        Write-Verbose    "Files From Source = $($FilesToArchive.Count)"
                    }
                Else
                    {
                        Write-Verbose    "FILE VERIFICATION FAILED"
                        Write-Verbose    "Files in Archive = $($FilesInArchive.Count)"
                        Write-Verbose    "Files From Source = $($FilesToArchive.Count)"
                    }#Else
            }#True

            False{


            }#False
        }
        if(($ArchiveToZip.IsPresent) -and ($FilesToArchive.count -eq $FilesInArchive.Count)){
            Write-Verbose "Removing folder $($ZipFilePath)"
            Remove-Item $ZipFilePath -Confirm:$False -Recurse -Force -ErrorAction Stop
        }#IF
        elseif($Force.IsPresent){
            Write-Verbose "Removing folder $($ZipFilePath). -Force Switch detected"
            Remove-Item $ZipFilePath -Confirm:$False -Recurse -Force -ErrorAction Stop
        }
        else{
            Write-Verbose "$($ZipFilePath) Removal Failed."
        }
    }#END


    
}#Function

# SIG # Begin signature block
# MIIGzwYJKoZIhvcNAQcCoIIGwDCCBrwCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUpIuLOoDnM32Az1EqCxQzVq78
# cl2gggRHMIIEQzCCAiugAwIBAgIQIzTOQXJ+IapNzXoyKIWCRTANBgkqhkiG9w0B
# AQsFADA9MR8wHQYDVQQLDBZGb3IgVGVzdCBQdXJwb3NlcyBPbmx5MRowGAYDVQQD
# DBFDZXJ0UmVxIFRlc3QgUm9vdDAeFw0xNzEyMjgwMjE1MjFaFw0xODEyMjgwMjM1
# MjFaMBUxEzARBgNVBAMMClNlY3VyZUNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDA7XUJkhK7ZVD0RtIZfu7BVL26XVM1+O3VkSOxO7r1xbdnKUpq
# LdITVNRzNwF+4mXIMbUBRBtrPal+jUnoFA+3l4Rsd8j7y9of2ibXOxo0o5GEv5X3
# pkKaqHqbMP+D0Y0fnc8c0KWy9eirMg9wnK2Yw+7UDs2Rp1BK6ovUkaiuN0QUx/mM
# BYZUdpXyWSbWNFpXzm1IoU3aTgP/HWRcigsqoO3kMupNX1Q74ERlnEljhfIKH/hZ
# im6PlebuG4AHKRMGZJrfLU6izom3BYMNSVrmZsdbIPmFnMBB1J/0WyJfafph1SaZ
# gw8l9UoKAGG4qaXCCWx2Pr+8jrQkyQb5gOkRAgMBAAGjZzBlMA4GA1UdDwEB/wQE
# AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBRzd3Eotls4z8iG
# vhvpcx4xX60FojAdBgNVHQ4EFgQUO4nHKKKGpJm0aJLk7KZW63DS4uswDQYJKoZI
# hvcNAQELBQADggIBADmFZB2J9tiuwG3cpIdUDMr2gXIOCbfFAOBm5Si4VlVAM1JS
# 4U8j37f9oySpK2lB9Kc4fRAOjKpcUBJCQGGBFNeuuiYBzgMOiDBLftnb6stHgq8H
# F/9U3xdO62lEp3NHijUKkFgeO5WJA0kdP7sI7ZGErdisP18gz3+bb6TglQV2/PvY
# LXjCt98+l1uKpi4U/NQwez0wStQ0SXORSD7/l5ZCjXdPxP6CsAAsJBwq7GD9ZXeB
# vnLw9iBgBXVF1sgjiGar7Hx6ZCp4Lzdj7ydJaPSysBJC4MnM1yBv7MfFNUHKxxaD
# 7eSb7WMZfB1oonqETnoUWDnrbnzA9vngeUQZ0noymEFmkTvTl4dZBfJkEoGs4zkV
# 7pLFqS0gc4RIOz2OE5119wZAMz6nRr2r394tNpZ/6xhqCvTPsLep0eneejM2Fayk
# AAepuJbOoWXtkTiIiNiRDxaLhAa9tXshByRutDXRm5Y07m/Fao0BlC0T8O1BzW+F
# XAiqQRZgJNmwtz239ykfLBqZuvnJ7vJG5xVFs29RiYJ5B/4VfSzkf8Y+8cdSNV53
# QH0IorEgelRFHXxxH8TnW4PKEO5iFz2Kq+qZYaChc1k5F3FRJNl3n8T/uZV34DR5
# ybxER738cVOHzAI9cJinFGIfYTvDKABoVjlGKavgkhoaSFZGj6vplSMz+yE2MYIB
# 8jCCAe4CAQEwUTA9MR8wHQYDVQQLDBZGb3IgVGVzdCBQdXJwb3NlcyBPbmx5MRow
# GAYDVQQDDBFDZXJ0UmVxIFRlc3QgUm9vdAIQIzTOQXJ+IapNzXoyKIWCRTAJBgUr
# DgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMx
# DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkq
# hkiG9w0BCQQxFgQUUl3Kxpp0PpXKxID7xpdGNqDVUc4wDQYJKoZIhvcNAQEBBQAE
# ggEAGvPMze6YxYvs9bC+QurwOZw/K/SxMJNwLrbjBsv3ZVFJdjGiXFP6yKCTebs7
# xlNEWfWIAyCnpxiKGeZZs7FM5UvaJRLifMHwQ4LY+tivsgJMtnY5EwUv7f5dRaRC
# lnXFUzPPSkbzPMg2AxFBcF2KbGrMTDyPDgnXq8HImobbXWEgCMAbyhT2aBdSA5Km
# 2fy9xjqfbdmn+zc/6KjHRfwyFpMZC+ecdVCIDl93neE9rjouWUcGA3OD91xGYM8Y
# YOj1e0buNKJTXDtyWVNoeUlRNzbB24RsxXXr5/G940XTqBgiWxYHYjKEXOQdPWk1
# E4QAjlT9wLujqlm6iOYnPPGFDw==
# SIG # End signature block