PowerShell 7Zip4Powershell zipping .zip error - powershell

Currently have a PSscript that does 1.65tb of .bmp files sorted into folders by yyyy/MM/dd/HH, replaces the # in the file name then converted to .jpg.
What I can't get past is the next step which gives me an error because it tries to zip the zip file that was created.
How to I prevent that? I tried the -Exclude but I think it has to be done just before the actual compression happens.
tried -Append and it fails for file not found.
(last step is delete the files that were zipped but I believe that can be done with a Remove-Item)
Directory structure looks like this with files in youngest child directory:
D:\Test\Processed\2020\01\13\13
D:\Test\Processed\2020\01\13\14
D:\Test\Processed\2020\01\13\15
D:\Test\Processed\2020\01\13\16
D:\Test\Processed\2020\01\13\17
D:\Test\Processed\2020\01\13\18
D:\Test\Processed\2020\01\13\19
D:\Test\Processed\2020\01\13\20
D:\Test\Processed\2020\01\13\21
D:\Test\Processed\2020\01\13\22
D:\Test\Processed\2020\01\13\23
PowerShell script
$sourceRootPath = "D:\Test\Processed\2020\01\13"
$targetRootPath = "D:\Test\Processed\2020\Archived"
Get-ChildItem -Path $sourceRootPath -Recurse -Exclude *.zip | Where-Object {$_.PSIsContainer} | ForEach-Object {
$directoryFullName = $_.FullName
$directoryName = $_.Name
#$folderPathToCompress - redundant but keeps my thinking straight for now
$folderPathToCompress = $directoryFullName
# This creates an error that the .zip file does not exist and exits
#Compress-7Zip -Path $folderPathToCompress -ArchiveFileName $directoryFullName\$directoryName.zip -Format Zip -CompressionLevel Ultra -Append
# This creates the .zip file BUT creates an error when it tries to zip the .zip file it is creating
#Compress-7Zip -Path $folderPathToCompress -ArchiveFileName $directoryFullName\$directoryName.zip -Format Zip -CompressionLevel Ultra
}
I will get this posting stuff figure out, sorry for the errors, I am open to learning two things at once but it takes 4x longer... so back at it.
1.) I am using the 7Zip4Powershell Module - it looked like a good idea, but maybe I should stick with passing everything to a variable and then Invoke-Expression thus not use the module but the 7zip command directly(?)
2.) Made a few attempts with same results but issue not resolved ... yet
This is what the error looks like and the different attempts below.
Compress-7Zip : The process cannot access the file 'D:\Test\Processed\2020\01\13\13\13.zip' because it is being used by another process.
At C:\Users\moe3srv\Desktop\test2.ps1:19 char:6
+ (Compress-7Zip -Path $folderPathToCompress -ArchiveFileName $dire ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (SevenZip4PowerS...+CompressWorker:CompressWorker) [Compress-7Zip], IOException
+ FullyQualifiedErrorId : err01,SevenZip4PowerShell.Compress7Zip
(Get-ChildItem -Path $sourceRootPath -Recurse)
(Get-ChildItem -Path $sourceRootPath -Recurse -Exclude .zip )
(Get-ChildItem -Path $sourceRootPath -Recurse -Exclude *.zip )

Alternatively in PowerShell we can user Compress-Archive
eg,
Compress-Archive -Path C:\Reference\* -DestinationPath C:\Archives\Draft.zip

Related

Powershell - removing subfolder recursively in a mapped drive getting error Illegal characters in path

I use a mapped drive to copy folder and files into a Sharpoint directory.
Here is my code
net use Q: "\\Sharepoint\Dir" /user:domain\user Password
copy-item "C:\Dir" -Destination Q:\
net use Q: /delete
Now before copying new files everyday I need to remove 1 subfolder and all his files (data of the day before). Then I try
remove-item "Q:\Subfolder" -Recurse -Force
but i'm getting this error
Illegal characters in path '{0}'. (Parameter 'Q:\Subfolder\.')
It's working if i write the whole file path like so
remove-item "Q:\Subfolder\file.ext" -Recurse -Force
But I need to remove all of the subfolder...
Some of my other unsuccessful tries
- remove-item "Q:\Subfolder\*" -Recurse -Force
- remove-item "Q:\\Subfolder" -Recurse -Force
- Get-ChildItem Q: -Directory -Force | ForEach-Object {
$regex = "^te"
if ($_.BaseName -match $regex) {
remove-item $_.BaseName
}
Hope someone can help, thanks !

Rename file before copy to certain folder

I´m a newbie still and learning to create PowerShell scripts to make Life in IT easier.
At present I´m trying to build a script, which runs a certain Microsoft tool, scanning defined network shares in a csv file and creating an JSON output file.
Now as the pattern of this file is always the same like "Report_Username_Hostname.vba.JSON", I would like to append either the scanned directory name or even a range of numbers, fe. "Report_Username_Hostname(100).vba.JSON" or "Report_Username_Hostname(sharename).vba.JSON"
This is neccessaray as after this renaming step, I upload this and other files within this folder to another folder on different server to upload them into a Database.
I planned to run this script in in many different locations on most automatic level and they all copy the their collected files to just one upload folder.
I already tried several options I found somewhere in the deep of the Internet, but I only came to the point where the file was renamed to 0 or similar, but not to expected result.
The Powershell script doing the work is this:
$PSpath = 'C:\temp\FileRemediation\Scripts\'
$Rpath = $PSpath +'..\Reports\1st'
$localshare = $PSpath +'..\temp\1st'
$csvinputs = Import-Csv $PSpath\fileremediation_1st.csv
$uploadshare = '\\PGC2EU-WFSFR01.eu1.1corp.org\upload\'
# This section checks if the folder for scan reports is availabe and if not will create necessary folder.
If(!(test-path $Rpath))
{
New-Item -ItemType Directory -Force -Path $Rpath
}
If(!(test-path $localshare))
{
New-Item -ItemType Directory -Force -Path $localshare
}
Set-Location $Rpath
# This section reads input from configuration file and starts Ms ReadinessReportCreator to scan shares in configuration file.
ForEach($csvinput in $csvinputs)
{
$uncshare = $csvinput.sharefolder
$Executeable = Start-Process "C:\Program Files (x86)\Microsoft xxx\xxx.exe" `
-Argumentlist "-p ""$uncshare""", "-r", "-t 10000", "-output ""$localshare"""`
-Wait
Get-ChildItem -Path $localshare -Filter '*.JSON' | Rename-Item -NewName {$_.FullName+$uncshare}
}
# This section copies the output *.JSON file of the xxx to the share, where I they will be uploaded to DB.
Get-ChildItem -Path $localshare -Filter '*.JSON' | Where {$_.Length -ge 3} | move-item -Destination '$uploadshare'
the fileremediation_1st.csv looks like
sharefolder
\\server\sharename
Can someone please help me on this, I don´t have a clue what I´m doing wrong.
Thank you!
Current error I get is
Rename-Item : Cannot rename the specified target, because it
represents a path or device name. At
C:\temp\FileRemediation\scripts\fileremediation_V2_1st.ps1:28 char:55
+ ... share -Filter '*.JSON' | Rename-Item -NewName {$_.FullName+$uncshare}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.RenameItemCommand
As said before, I would also be fine with a dedicated range of numbers, which is append to the file name "Report_Username_Hostname(100).vba.JSON"
The perfect world would be if I could split the \server\sharename from csv file and append the sharename to my filename.
I think the issue is with:
Rename-Item -NewName {$_.FullName+$uncshare}
Your input file (Get-ChildItem) path is:
$PSpath = 'C:\temp\FileRemediation\Scripts\'
$localshare = $PSpath +'..\temp\1st'
The Rename-Item uses $_.FullName which resolves to something like this:
C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON
The variables then contain:
$_.FullName = C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON
$uncshare = "\\server\sharename"
So Your Rename-Item ... $_.FullName+$uncshare will try to rename it to:
C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON\\server\sharename
Which is not a valid path.

Powershell script to copy files based on filename

I have a folder that contains several thousand files. I would like to write a Powershell script that loops through the files and copies each file whose filename contains a specific keyword. In pseudocode:
For each file in C:\[Directory]
If filename contains "Presentation" Then
copy file in C:\[Directory 2]
Simply like this ?
copy-item "C:\SourceDir\*Presentation*" "C:\DestinationDir"
or like this :
copy-item "C:\SourceDir\*" "C:\DestinationDir" -Filter "*rrrr*"
But a risk exist if you have a directory with "presentation" in his name into the source directory. Then take all method proposed here and add -file in get-childitem command.
Like in this short version of Robdy code :
gci "C:\SourceDir" -file | ? Name -like "*Presentation*" | cpi -d "C:\DestinationDir"
That code should do the trick:
$files = Get-ChildItem -Path "C:\path\to\source\folder"
$files | Where-Object Name -Like "*Presentation*" | Copy-Item -Destination "C:\path\to\destination\folder"
Of course can be written in one line but I put in two for visibility.
Edit: as Esperento57 pointed out, you might want to add -ItemType File to Get-ChildItem cmdlet to not include folders with 'Presentation' in their name. Also, depending on your needs you might also want to use -Recurse param to include files in subfolders.
If you have files in subfolders and you want to keep the path in destination folder you'll have to change the script a bit to something like:
Copy-Item -Destination $_.FullName.Replace('C:\path\to\source\folder','C:\path\to\destination\folder')
And for the above you'll have to make sure that folders are actually created (e.g. by using -Force for Copy-Item.
This seems to work:
$src = "Dir1"
$dst = "Dir2"
Get-ChildItem $src -Filter "*Presentation*" -Recurse | % {
New-Item -Path $_.FullName.Replace($src,$dst) -ItemType File -Force
Copy-Item -Path $_.FullName -Destination $_.FullName.Replace($src,$dst) -Force
}
Try something like this:
Get-ChildItem "C:\Your\Directory" -File -Filter *YourKeyWordToIsolate* |
Foreach-Object { Copy-Item $_.FullName -Destination "C:\Your\New\Directory" }
... but, of course, you'll need to fill in some of the blanks left open by your pseudocode example.
Also, that's a one-liner, but I inserted a return carriage for easier readability.

zip files using powershell

This is what I am trying to do with powershell for zipping files.
Sort out files older than xxx days
Add those files in a zip file.
Delete the source files.
I have Powershell_Community_Extensions installed so I use Write-zip to do the job.
$Source = "\\network\share"
$files = Get-ChildItem -Path $Source | Where-Object {$_.LastWriteTime -lt (get-date).AddDays(-62)}
$files | Write-Zip -OutputPath $Source\Archive.zip -EntryPathRoot $Source -Append -Quiet
Remove-Item $files -Force
Issues:
I have to use -EntryPathRoot with Write-zip, otherwise it wont pick up network share
Remove-item also wont pickup files from network share, it says "Remove-Item : Cannot find path 'C:\Windows\system32\feb03.txt' because it does not exist.", why it deleting file from C:\Windows\system32\ instead of \\network\share
Write-zip -append did add files into the zip file, but it did not just add files in the root of that zip file, it actually created entire folder structure in the root of the zip and added newer filtered files in the end of that folder structure. I just want to add the newer filtered files into root of that zip file.
Any idea please?
Utilizing the v5 *Archive cmdlets:
$Source = '\\network\share'
$Files = Get-ChildItem -Path $Source |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-62) }
Compress-Archive -Path $Files.FullName -DestinationPath $Source\Archive.zip -CompressionLevel Optimal -Update
$Files | Remove-Item -Force

Compress-Archive Error: Cannot access the file because it is being used by another process

I would like to zip a path (with a service windows running inside).
When the service is stopped, it works perfectly, when the service is running, I have the exception:
The process cannot access the file because it is being used by another
process.
However, when I zip with 7-zip, I don't have any exception.
My command:
Compress-Archive [PATH] -CompressionLevel Optimal -DestinationPath("[DEST_PATH]") -Force
Do you have any idea to perform the task without this exception?
Copy-Item allows you to access files that are being used in another process.
This is the solution I ended up using in my code:
Copy-Item -Path "C:\Temp\somefolder" -Force -PassThru |
Get-ChildItem |
Compress-Archive -DestinationPath "C:\Temp\somefolder.zip"
The idea is that you pass through all the copied items through the pipeline instead of having to copy them to a specific destination first before compressing.
I like to zip up a folder's content rather than the folder itself, therefore I'm using Get-ChildItem before compressing in the last line.
Sub-folders are already included. No need to use -recurse in the first line to do this
A good method to access files being used by another process is by creating snapshots using Volume Shadow Copy Service.
To do so, one can simply use PowerShells WMI Cmdlets:
$Path = "C:/my/used/folder"
$directoryRoot = [System.IO.Directory]::GetDirectoryRoot($Path).ToString()
$shadow = (Get-WmiObject -List Win32_ShadowCopy).Create($directoryRoot, "ClientAccessible")
$shadowCopy = Get-WmiObject Win32_ShadowCopy | ? { $_.ID -eq $shadow.ShadowID }
$snapshotPath = $shadowCopy.DeviceObject + "\" + $Path.Replace($directoryRoot, "")
Now you can use the $snapshotPath as -Path for your Compress-Archive call.
This method can also be used to create backups with symlinks.
From there on you can use the linked folders to copy backed up files, or to compress them without those Access exceptions.
I created a similiar function and a small Cmdlet in this Gist: Backup.ps1
There was a similar requirement where only few extensions needs to be added to zip.
With this approach, we can copy the all files including locked ones to a temp location > Zip the files and then delete the logs
This is bit lengthy process but made my day!
$filedate = Get-Date -Format yyyyMddhhmmss
$zipfile = 'C:\Logs\logfiles'+ $filedate +'.zip'
New-Item -Path "c:\" -Name "Logs" -ItemType "directory" -ErrorAction SilentlyContinue
Robocopy "<Log Location>" "C:\CRLogs\" *.txt *.csv *.log /s
Get-ChildItem -Path "C:\Logs\" -Recurse | Compress-Archive -DestinationPath $zipfile -Force -ErrorAction Continue
Remove-Item -Path "C:\Logs\" -Exclude *.zip -Recurse -Force