I wish to search for files or folders provided to $itemsToInclude
under directory C:\bea
Once found it should add the found item [file or folder] to $zipFileName while persisting the folder structure.
Thus, if rt.jar is found in C:\bea\dev\log\rt.jar
as well as C:\bea\QA\log\rt.jar
my C:\bea\package-dev.zip
should contain both like below:
- `C:\bea\dev\log\rt.jar`
- `C:\bea\QA\log\rt.jar`
Below is my attempt which fails with error Access to the path 'C:\bea\package-dev.zip' is denied."
but my powershell can very well write to the C:\bea\
folder. I dont expect to see any ACCESS DENIED error.
$zipFileName = "C:\bea\package-dev.zip"
cd "C:\bea"
$itemsToInclude = "font.properties,rt.jar"
Write-Host "itemsToInclude is- $itemsToInclude"
$workspace = "C:\bea"
if ($itemsToInclude -eq '*') {
# Include all files, including files from subdirectories
Write-Host "Include all files, including files from subdirectories"
Get-ChildItem -Path $workspace -Recurse -File |
Compress-Archive -DestinationPath $zipFileName -Update -Force
} else {
# Include specific files as per the comma-separated list
Write-Host "Include specific files as per the comma-separated list"
$pattern = $itemsToInclude.Split(',').ForEach({ [regex]::Escape($_) }) -join '|'
$filesToInclude = Get-ChildItem $workspace -Recurse -File |
Where-Object FullName -Match $pattern
$filesToInclude | ForEach-Object {
$relativePath = $_.FullName.Substring($workspace.Length)
$destinationPath = Join-Path $zipFileName $relativePath
$destinationFolder = Split-Path $destinationPath -Parent
if (-not (Test-Path $destinationFolder)) {
New-Item -ItemType Directory -Path $destinationFolder | Out-Null
}
Copy-Item $_.FullName -Destination $destinationPath -Force
}
Compress-Archive -Path $zipFileName -DestinationPath $zipFileName -Update
}
Output:
itemsToInclude is- font.properties,rt.jar
Include specific files as per the comma-separated list
New-Object : Exception calling ".ctor" with "2" argument(s): "Access to the path 'C:\bea\package-dev.zip' is denied."
At C:\windows\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:729
char:30
+ ... ileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
Note: I m able to successfully create ZIP without the absolute path for files in the same directory using the below code:
$zipFileName = "C:\bea\package-dev.zip"
cd "C:\bea"
$itemsToInclude = "font.properties,rt.jar"
Write-Host "itemsToInclude is- $itemsToInclude"
$workspace = "C:\bea"
if ($itemsToInclude -eq '*') {
# Include all files, including files from subdirectories
Write-Host "Include all files, including files from subdirectories"
Get-ChildItem -Path $workspace -Recurse -File |
Compress-Archive -DestinationPath $zipFileName -Update -Force
} else {
# Include specific files as per the comma-separated list
Write-Host "Include specific files as per the comma-separated list"
$pattern = $itemsToInclude.Split(',').ForEach({ [regex]::Escape($_) }) -join '|'
Get-ChildItem $workspace -Recurse -File |
Where-Object FullName -Match $pattern |
Compress-Archive -DestinationPath $zipFileName -Update
}
Can you please suggest?
Hard to determine why your code is failing, it might possible that the Compress-Archive
is not correctly closing the zip stream or you have the zip opened while trying to run your code.
If you're able to install modules then using PSCompression
can simplify the task of adding zip entries to an existing zip archive for you. The module can be installed through the PowerShell Gallery using:
Install-Module PSCompression -Scope CurrentUser
Then the else
peace of your code can be replaced using a similar logic as in the example 4 of the docs:
if (-not (Test-Path $zipFileName)) {
$null = New-Item $zipFileName -ItemType File
}
Write-Host 'Include specific files as per the comma-separated list'
$pattern = $itemsToInclude.Split(',').ForEach({ [regex]::Escape($_) }) -join '|'
$filesToInclude = Get-ChildItem $workspace -Recurse -File |
Where-Object FullName -Match $pattern
$filesToInclude | ForEach-Object {
$newZipEntrySplat = @{
EntryPath = $_.FullName.Substring($workspace.Length)
SourcePath = $_.FullName
Destination = $zipFileName
}
New-ZipEntry @newZipEntrySplat
}