I have a lots of folders with contents that I want to move to another folder Below I want to move the 3 folders to the ARKIV folder - it works but the script crasches at the end. Am I using the Exclude flag the wrong way? If I use -Whatif it seems to want to move that folder as well - see picture 2
My code is as follows:
$current_logfiles = "H:\FAKTURA\"
$destination = "H:\FAKTURA\ARKIV\"
$excludes = "H:\FAKTURA\ARKIV\"
if ((Test-Path -Path $destination))
{
Get-ChildItem -Exclude $excludes -Path H:\FAKTURA | Move-Item -Destination
H:\FAKTURA\ARKIV -Whatif
}
Am I using the Exclude flag the wrong way?
Yes:
-Exclude
(like -Include
) only operates on item (file or directory) names, not entire paths.
-Excludes
only excludes the matching item itself. This means that when -Recurse
is used and a directory is excluded, its contents (subtree) are not.
In your case, since you're not using -Recurse
and are therefore only targeting the immediate child items of your input directory, the solution is to use the name only, i.e. $excludes = 'ARKIV'
:
$excludes = 'ARKIV'
Get-ChildItem -Exclude $excludes -Path H:\FAKTURA |
Move-Item -Destination H:\FAKTURA\ARKIV -Whatif
Note: Due to a bug in Windows PowerShell, you must use -Path
in the command above, even though -LiteralPath
is conceptually appropriate and in general more robust.
(The code could be simplified: you could use $destination
with -Destination
and (Split-Path -Leaf $destination)
as the $excludes
value.
To skip items that are already present in $destination
, insert the following pipeline segment before Move-Item
:
Where-Object { -not (Test-Path -LiteralPath (Join-Path $destination $_.Name)) }
)
-Exclude
:It follows from the above that, when -Recurse
is used:
You cannot exclude items by subtree path.
You cannot exclude items along with their subtrees
These limitations apply to Windows PowerShell and to PowerShell (Core) up to at least the version current as of this writing, v7.3.x.
The next section links to feature requests that may provide this functionality in the future.
Workarounds, based on post-filtering via Where-Object
:
In the simplest case, if the paths to exclude can be matched via wildcard expressions, use -notlike
; e.g.:
Get-ChildItem -Recurse -File -Filter *.txt |
Where-Object FullPath -notlike Arkiv/* |
Where-Object FullPath -notlike */sub/dir/* |
This works for excluding the content of the directories of interest, but not these directories themselves (which isn't a problem in this example, given that -File
is used to enumerate only files).
While you could add another -notlike
operation that omits the /*
in order to also match the directories themselves (e.g., -notlike */sub/dir
), such duplication is obviously cumbersome.
An alternative is to use regexes with -notmatch
instead:
Get-ChildItem -Recurse -Directory |
Where-Object FullPath -notmatch '(^|\\)node_modules(\\|$)'
This excludes directories named node_modules
and their subtrees wherever they may be located in the input directory subtree.
Note that \\
matches a verbatim \
, i.e. a Windows path separator; use /
on Unix-like platforms or [\\/]
for cross-platform compatibility.
This answer shows a programmatic way to construct these regexes, based on an array of verbatim exclusion paths.
There are two relevant feature requests to potentially overcome the limitations of -Exclude
in the future:
GitHub issue #4126 asks for -Exclude
to also support path patterns.
GitHub issue #15159 proposes a new subtree-exclusion parameter, such as
-ExcludeRecursive
.