There are various ways to go about this; but this one is clean and easy to understand, so would be my preferred route:
Function Move-FolderConditional { # todo: give this cmdlet a better name for your context
[CmdletBinding()]
Param (
[Parameter(Mandatory, ValueFromPipeline)]
[System.IO.DirectoryInfo[]]$Path
,
[Parameter(Mandatory)]
[System.IO.DirectoryInfo]$Destination
,
# files matching this pattern get moved to the target
[Parameter(Mandatory)]
[string]$ArchivableFolderPattern
,
# Files older than this date get moved to the target
[Parameter()]
[string]$MinKeepDateUtc = (Get-Date).AddDays(-3).ToUniversalTime()
)
Process {
foreach ($directory in $Path) {
if ($directory.BaseName -notmatch $ArchivableFolderPattern) {
Write-Warning "Could not move folder '$($directory.FullName)' as the name does not match the required pattern"
continue;
}
if ($directory.LastWriteTimeUtc -ge $MinKeepDateUtc) {
Write-Warning "Could not archive folder '$($directory.FullName)' as it was last updated at '$($directory.LastWriteTimeUtc.ToString('u'))'"
continue;
}
try {
#Move-Item -Path $directory -Destination $Destination -ErrorAction Stop # Uncommend this if you actually want to move your files
Write-Information "Successfully moved '$($directory.FullName)' to '$($Destination.FullName)'"
} catch [System.Management.Automation.ItemNotFoundException] { # For this exception we'd probably check in the Begin block instead - but this is just to give the idea that we could add a try/catch if required
Write-Warning "Could not archive folder '$($directory.FullName)' the target directory does not exist: '$($Destination.FullName)'"
}
}
}
}
# Example usage
Get-ChildItem $path -Directory -Force | Move-FolderConditional -ArchivableFolderPattern '^log' -InformationAction Continue -Destination 'z:\archive\'
But other options are available (I've just included snippets to give the gist of these):
Switch Statement
switch ( $directory )
{
{$_.BaseName -notmatch $ArchivableFolderPattern}
{
Write-Warning "Could not move folder '$($_.FullName)' as the name does not match the required pattern"
break
}
{$_.LastWriteTimeUtc -ge $MinKeepDateUtc}
{
Write-Warning "Could not archive folder '$($_.FullName)' as it was last updated at '$($_.LastWriteTimeUtc.ToString('u'))'"
break
}
default
{
Write-Information "Successfully moved '$($_.FullName)' to '$($Destination.FullName)'"
}
}
Flags
[bool]$archiveFolder = $true
if ($directory.BaseName -notmatch $ArchivableFolderPattern) {
Write-Warning "Could not move folder '$($directory.FullName)' as the name does not match the required pattern"
$archiveFolder = $false
}
if ($directory.LastWriteTimeUtc -ge $MinKeepDateUtc) {
# note: this will process even if archivefolder is already false... you can use `else` or amend the condition to include `$archiveFolder -or ($directory.LastWriteTimeUtc -ge $MinKeepDateUtc)`; though if going that route it's better to use the switch statement.
Write-Warning "Could not archive folder '$($directory.FullName)' as it was last updated at '$($_.LastWriteTimeUtc.ToString('u'))'"
$archiveFolder = $false
}
if ($archiveFolder) {
Write-Information "Successfully moved '$($directory.FullName)' to '$($Destination.FullName)'"
}
Other
Or you can do combinations of the above (e.g. use the switch statement to set your flags (in which case you can optionally remove the break so that all issues are displayed).
switchwith a script block); but the cleanest from a code perspective (IMO) is to create a custom function to replace your ForEach loop, have it accept pipeline input, then in theprocessblock include guard clauses (see foxdeploy.com/blog/… for some examples - only usereturninstead ofthrowgiven the context is a loop)