1

I am trying to develop a powershell script that will allow me to archive all files that are older than 2 years and copy over their parent directories to a new root folder. I would also like to delete the original file and any empty directories after the archiving has been completed.

I have the below function which should allow me to do the first part (moving the files and parent directories) being called from a test script at the moment and it is failing with the error:

Copy-Item : Cannot evaluate parameter 'Destination' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input. At C:\Users\cfisher\Documents\WindowsPowerShell\Modules\ShareMigration\ShareMigration.psm1:99 char:43 + Copy-Item -Force -Destination { + ~ + CategoryInfo : MetadataError: (:) [Copy-Item], ParameterBindingException + FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.CopyItemCommand

Here is the function:

Function ArchiveFiles { [CmdletBinding()]

Param (
    [Parameter(Mandatory=$True)][string]$SourceDirectory,
    [Parameter(Mandatory=$True)][string]$DestinationDirectory,
    [Parameter(Mandatory=$True)][ValidateSet('AddMinutes','AddHours','AddDays','AddMonths','AddYears')][string]$TimeUnit,
    [Parameter(Mandatory=$True)][int]$TimeLength
)
Begin {
    Write-Host "Archiving files..." -ForegroundColor Yellow -BackgroundColor DarkGreen
}
Process {
    $Now = Get-Date
    $LastWrite = $Now.$TimeUnit(-$TimeLength)

    $Items = Get-ChildItem -Path $SourceDirectory -Recurse | where { $_.LastWriteTime -lt "$LastWrite" }

    ForEach($Item in $Items) {
        Copy-Item -Force -Destination {
            If ($_.PSIsContainer) {
                If (!(Test-Path -Path $_.Parent.FullName)) {
                    New-Item -Force -ItemType Directory -Path
                    (
                        Join-Path $DestinationDirectory $_.Parent.FullName.Substring($SourceDirectory.length)
                    )
                }
                Else {
                    Join-Path $DestinationDirectory $_.Parent.FullName.Substring($SourceDirectory.length)
                }
            }
            Else {
              Join-Path $DestinationDirectory $_.FullName.Substring($SourceDirectory.length)
            }
        }
    }
}
End {
    Write-Host "Archiving has finished." -ForegroundColor Yellow -BackgroundColor DarkGreen
}

}

I thought that passing the results of Join-Path as input to the -Destination parameter would do the trick, but it does not seem to be playing along. Do I need to create new items for each path or something? Kind of new to powershell so sorry if this looks sloppy. I appreciate any constructive criticism and solutions.

Thanks!

4
  • I never did copy item with a scriptblock. Why you don't use copy item infront of the join-path command? Commented Oct 3, 2017 at 17:22
  • That is a good idea. Let me give it a try. Commented Oct 3, 2017 at 17:36
  • why not just use Robocopy? Commented Oct 3, 2017 at 18:39
  • … -Destination $(. { scrip_block_body_here }) should work (note () . { } Dot sourcing operator and $( ) Subexpression operator. See Get-Help 'about_Operators'. However, a dot sourced scriptblock must be a valid code snippet (and Iˇm not sure about yours one). Commented Oct 3, 2017 at 19:12

1 Answer 1

2

You could use Robocopy to achive what you are looking for.

Source : What to copy

Destination : Where to put copy

Days : How old should the last access time for file be before copy

RemoveOldFiles : Delete Files and folders from source that were copied over.

Robocopy has alot of different options that could help you make this take much easier

In this case we are using

/MINLAD : Get files older then Last Access Date

/e : Copy sub directories even empty ones

/mov : Move files instead of copying them

Function ArchiveFileSystem([string]$Source, [string]$Destination, [int]$Days, [switch]$RemoveOldFiles){
    $LastWrite = Get-date (Get-Date).AddDays(-$Days) -Format yyyyMMdd
    robocopy $Source $Destination /MINLAD:$LastWrite /e (&{if($RemoveOldFiles -eq $true){'/mov'}})
}
ArchiveFileSystem -Source C:\TestSource -Destination C:\TestDestination -Days 1 -RemoveOldFiles
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much. This is a much easier approach than what I was attempting to do. This solution seems to work great for my purposes. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.