I want to extract all *.Z files in place in their current directories (7-Zip support LZW/UNIX compression).
I can't figure out why this is not working. I know how to use PowerShell to recursively get a full path of a filename and directory in which file resides. I also know how to use 7-zip to extract a file in place. But trying to put these two together is not working. Here's what I have:
Get-ChildItem -Recurse *.Z | foreach ($_) {7z.exe e $_.FullName -o$_.Directory}
I also tried:
Get-ChildItem -Recurse *.Z | foreach ($_) {7z.exe e $_.FullName -o$($_.Directory)}
and
Get-ChildItem -Recurse *.Z | foreach ($_) {7z.exe e $_.FullName -o${_.Directory}}
This is getting the files I want by FullName, and Directory is the correct path (no space between the o and directory is how 7-zip expects the output directory). However, it keeps trying to output the file to the .Z path rather than the directory. I know it is right if I do
Get-ChildItem -Recurse *.Z | Select Directory
that is where I want it to go.
I assume the issue was having no space but not sure why it would get same directory. I even manually defined a variable and passed that with no problems.
So the issue is 7-zip saying no files to process when I want to output to same directory but not sure why, and it seems Directory variable not being passed but file name again which makes no sense. Sample output per file:
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
Scanning the drive for archives:
1 file, 226 bytes (1 KiB)
Extracting archive: E:\Files\2014\more_cowbell\myfancyunixcompresseddocument.txt.Z
--
Path = E:\Files\2014\more_cowbell\myfancyunixcompresseddocument.txt.Z
Type = Z
No files to process
Everything is Ok
Files: 0
Size: 0
Compressed: 226
It works fine if I specify one specific output directory (no variable), but I want them extracted in place due to many subdirectories and conflicting file names between them.
I want to extract all *.Z files in place in their current directories (7-Zip support LZW/UNIX compression).
The -o parameter should be inside a doublequoted string with $($var) for variables:
Get-ChildItem -Recurse *.z | %{ 7z e $_.FullName "-o$($_.Directory)"}
Related
I have tried to do my research, but I can't fathom this one out.
I can combine multiple .txt files in a folder. no problem:
dir C:\Users\XXXX\AC1\22JUN *.txt | get-content | out-file C:\Users\XXXX\22JUN\AC1_22JUN.txt
however, I have 14 Directories each with subdirectories. (months of the year), and this will only ever grow. How can I write it so that it will go into each directory AC1 - AC14 and then look into each folder JAN-DEC and in each subdirectory create a combined file for AC1_22JUN, AC2_22JUN AC1_22JUL, AC2_22JUL and so on and so on?
is there also a way to rename the output file with data, such as the number of .txt files that have been combined. i.e. AC1_22JUN_314.txt
many thanks in advance
What you need to do is iterate over all your directories and their subdirectories and run a particular command in each of them. This is easy enough to achieve using the cmdlet Get-ChildItem and a pair of nested foreach loops.
In addition, you need to count the number of text files you've processed so that you can name your aggregate file appropriately. To do this you can break your pipeline using the temporary variable $files. You can later begin a new pipeline with this variable and use its count property to name the aggregate file.
The code for this is as follows:
$dirs = Get-ChildItem -Directory
foreach ($dir in $dirs)
{
$subdirs = Get-ChildItem $dir -Directory
foreach ($subdir in $subdirs)
{
$files = Get-ChildItem *.txt -Path $subdir.fullname
$name = "$($dir.name)_$($subdir.name)_$($files.count).txt"
$files | Get-Content | Out-File "$($subdir.fullname)/$name"
}
}
A few things to note:
The script needs to be run from the containing folder - in your case the parent folder for AC1-AC14. To run it from elsewhere you will have to change the first statement into something like $dirs = Get-ChildItem C:\path\to\container -Directory
Get-ChildItem is the same as the command dir. dir is an alias for Get-ChildItem. This is NOT the same as the variable $dir which I've used in the script.
Running the script multiple times will include any and all of your old aggregate files! This is because the output file is also a .txt file which is caught in your wildcard search. Consider refining the search criteria for Get-ChildItem, or save the output elsewhere.
I am trying to zip files that are in directories that have subdirectories and I can't figure out how to zip the files and not the subdirectories.
Here is the current setup:
C:\users\user\appdata\local\folder\
Inside of this folder, I need 3 out of the 20 or so folders that are in there so I used the Get-Childitem to accomplish this:
GCI C:\users\user\appdata\local\folder | ? {$_.name -like "*folder*}
Now that I have that, I don't want the subdirectories and just want the files that are sitting in the folder itself. I have not found a way to do this, but I have gotten close with using this:
& "C:\program files\7-zip\7z.exe" "a" "D:\TestBackup\Zipfile.7z" (GCI C:\users\user\appdata\local\folder | ? {$_.name -like "*folder*} | select -expandproperty FullName)
But this gives me the entire contents of the folder. I want to keep the structure so that it looks like this:
folder 1\files
folder 2\files
folder 3\files
I hope I am explaining myself well. The files are all different types of extensions so I was wanting a blanket way to do this or to exclude the subdirectories when zipping.
I had to consult the FAQ to get this right:
7-Zip stores only relative paths of files (without drive letter
prefix). You can change current folder to folder that is common for
all files that you want to compress and then you can use relative
paths:
cd /D C:\dir1\
7z.exe a c:\a.7z file1.txt dir2\file2.txt
Solution:
# Set base directory that is common for all files
Push-Location 'C:\users\user\appdata\local\folder'
# Get names of directories that match filter
$folderNames = (Get-ChildItem -Directory -Filter '*folder*').Name
# Call 7-zip, passing the list of directory names.
& 'C:\Program Files\7-Zip\7z.exe' a 'D:\TestBackup\Zipfile.7z' $folderNames
# Restore current directory
Pop-Location
Remarks:
Push-Location sets the current directory, while Pop-Location restores the previous current directory. Changing the current directory is crucial for this solution, as explained by the 7-zip FAQ. It is also the only way to set the base directory for Resolve-Path -Relative.
Pass -Directory or -File to Get-ChildItem if you are only interested in either directories or files.
Use -Filter instead of Where-Object (alias ?) if you only need simple wildcard filtering. -Filter is faster because it uses the FileSystem provider which filters at a lower API level, which avoids PowerShell overhead.
My folder structure looks like this:
SourceFolder
├─file1.txt
├─file1.doc
└─Subfolder1
├─file2.txt
├─file2.doc
└─SubSubFolder
├─file3.txt
└─doc3.txt
This script copies all *.txt files from folders, whose (folder) names contains the eng, to a destination folder. Only the files inside the folder.
$dest = "C:\Users\username\Desktop\Final"
$source = "C:\Users\username\Desktop\Test1"
Get-ChildItem $source -Filter "*.txt" -Recurse |
Where-Object { $_.DirectoryName -match "eng" } |
ForEach-Object { Copy-Item $_.fullname $dest }
In my situation the folders are in .rar format and I want the script to search .rar folders and copy the *.txt files from folder eng to destination. Is that possible with PowerShell?
Rar is a proprietary archive format. Your .rar items aren't folders but compressed archives of that format. PowerShell can't transparently handle such archives, and I'm not aware of a third-party provider that would add this functionality.
Basically, no, what you're asking isn't possible.
What you can do is extract files from the archive with tools like 7-zip, e.g.:
7z.exe e your.rar *.txt -r
For extracting only files from a nested subfolder inside the archive prepend the extract pattern with that path:
7z.exe e your.rar "nested\subfolder\*.txt" -r
I am a junior tech and have been tasked to write a short powershell script. The problem is that I have started to learn the PS 5 hours ago - once my boss told that I'm assigned to this task. I'm a bit worried it won't be completed for tomorrow so hope you guys can help me a bit. The task is:
I need to move the files to different folders depending on certain conditions, let me start from the he folder structure:
c:\LostFiles: This folder includes a long list of .mov, .jpg and .png files
c:\Media: This folder includes many subfolders withe media files and projects.
The job is to move files from c:\LostFiles to appropiate folders in c:\Media folder tree if
The name of the file from c:\LostFiles corresponds to a file name in one of the subfolders of the C:\media We must ignore the extension, for example:
C:\LostFiles has these files which we need to move (if possible) : imageFlower.png, videoMarch.mov, danceRock.bmp
C:\Media\Flowers\ has already this files: imageFlower.bmp, imageFlower.mov
imageFlower.png should be moved to this folder (C:\media\Flowers) because there is or there are files with exactly the same base name (extension must be ignored)
Only the files that have corresponding files (the same name) should be moved.
So far I have written this piece of code (I know it is not much but will be updating this code as I am working on it now (2145 GMT time). I know I missing some loops, hey yeah, I am missing a lot!
#This gets all the files from the folder
$orphans = gci -path C:\lostfiles\ -File | Select Basename
#This gets the list of files from all the folders
$Files = gci C:\media\ -Recurse -File | select Fullname
#So we can all the files and we check them 1 by 1
$orphans | ForEach-Object {
#variable that stores the name of the current file
$file = ($_.BaseName)
#path to copy the file, and then search for files with the same name but only take into the accont the base name
$path = $Files | where-object{$_ -eq $file}
#move the current file to the destination
move-item -path $_.fullname -destination $path -whatif
}
You could build a hashtable from the media files, then iterate through the lost files, looking to see if the lost file's name was in the hash. Something like:
# Create a hashtable with key = file basename and value = containing directory
$mediaFiles = #{}
Get-ChildItem -Recurse .\Media | ?{!$_.PsIsContainer} | Select-Object BaseName, DirectoryName |
ForEach-Object { $mediaFiles[$_.BaseName] = $_.DirectoryName }
# Look through lost files and if the lost file exists in the hash, then move it
Get-ChildItem -Recurse .\LostFiles | ?{!$_.PsIsContainer} |
ForEach-Object { if ($mediaFiles.ContainsKey($_.BaseName)) { Move-Item -whatif $_.FullName $mediaFiles[$_.BaseName] } }
How can I use powershell and 7zip ( 7za.exe ) to ZIP a folder while excluding certain file types?
I tried this:
cd "C:\path\to\folder to zip"
7za.exe a "C:\path\to\newZip.zip" -mx3 -x!*.txt -x!*.pdf
But that returns:
.txt: WARNING: The system cannot find the file specified.
.pdf: WARNING: The system cannot find the file specified.
and doesn't ZIP anything- just creates an empty ZIP file.
I have also tried this:
cd "C:\path\to\folder to zip"
Get-ChildItem "C:\path\to\folder to zip" -Recurse -Exclude *.txt, *.pdf | 7za.exe a -mx3 "C:\path\to\newZip.zip" $_.FullName
But that ZIPs everything in the "C:\path\to\folder to zip" folder instead of excluding anything..
Thank you for any help you can provide.
-Jim
Your second attempt is almost correct.
Your command to call 7-zip need to be wrapped in a for-each block, otherwise the $_.FullName is resolved to an empty string and 7-zip (in the absence of the input parameters) automatically zips everything in the directory. So change it to this:
Get-ChildItem "C:\path\to\folder to zip" -Recurse -Exclude *.txt, *.pdf | %{7za.exe a -mx3 "C:\path\to\newZip.zip" $_.FullName}
Note that % is an alias to foreach-object.