Below is my workflow on PowerShell that searches for files and folders provided as a comma-separated list to itemsToInclude:
$zipFileName = "${{ github.workspace }}\package-$env:GITHUB_RUN_NUMBER.zip"
cd "${{ github.workspace }}"
$itemsToInclude = $env:INPUTS_FILESINZIP
Write-Host "itemsToInclude is- $itemsToInclude"
if (-not (Test-Path $zipFileName)) {
$null = New-Item $zipFileName -ItemType File
}
$workspace = "${{ github.workspace }}"
# Define the directories to exclude
$excludeDirectories = @('DevOps')
$excludeExtensions = @('.java', '.class')
# Include specific files and folders as per the comma-separated list
Write-Host 'Include specific files and folders as per the comma-separated list'
$itemsToIncludeList = $itemsToInclude -split ','
$filesToInclude = Get-ChildItem $workspace -Recurse -File -Exclude $excludeDirectories | Where-Object {
$itemName = $_.Name
Write-Host "Checking file: $itemName"
$itemsToIncludeList -contains $itemName
}
$filesToInclude | ForEach-Object {
$newZipEntrySplat = @{
EntryPath = $_.FullName.Substring($workspace.Length)
SourcePath = $_.FullName
Destination = $zipFileName
}
Write-Host "Adding file: $($_.FullName)"
New-ZipEntry @newZipEntrySplat
}
Write-Host "Zip file created: $zipFileName"
env:
INPUTS_FILESINZIP: ${{ inputs.filesinzip }}
The time it takes to search for desired files and include them in ZIP is more than acceptable.
Thus, I wish to exclude the folder DevOps and all files having extensions .java and .class so the time taken for this step is reduced.
Unfortunately, the -Exclude option does not work and I can see all files inside the AreDevOps folder listed in the output for Checking file:
Can you please suggest?
What you're looking for is to exclude an entire directory subtree from enumeration from a recursive
Get-ChildItemcall with-Exclude.Unfortunately, this is not directly supported in Windows PowerShell and still not as of PowerShell (Core) 7.4:
The
-Includeand-Excludeparameters operate on item (file or directory) names only (not on paths).They only operate on the matching items themselves. That is, if a directory's name matches, its subtree is still recursed into.
GitHub issue #15159 is a feature request to also support excluding the entire subtrees of matching subdirectories.
Workarounds:
If the subdirectories whose subtrees you want to exclude are all top-level, i.e. immediate child items of the target directory, you can use a two-step approach:
The first
Get-ChildItemcall returns only top-level items that do not match the name, thereby excluding the directories of interest.The second call then only recurses on the non-excluded items, using filename-extension exclusions.
If you need to exclude the subtrees of directories matching given names on any level of the input subtree, you will need post-filtering, which results in much slower execution:
The approach is a two-step one again:
First, enumerate subdirectories only, and exclude the unwanted subtrees, resulting in a list of directories of interest only.
Then, in each directory of interest, recursively look for files of interest.
Note: The assumption is that there are (far) fewer directories than files, so that first eliminating entire subdirectory trees is more efficient than walking the entire tree and having to examine each file's path.
The use of a regex is needed to rule out false positives, and also enables more efficient matching with multiple exclusions, due to using only a single
-notmatchoperation.$excludeDirectories = 'DevOps', 'obj', 'bin'-notmatchoperation would eliminate.