Create 7-Zip Archive with Files from Textfile - Powershell - powershell

I'm coding a small Powershell application at work for our supporters to Archive Files. But now im stuck because of the 7zip Option.
The Users can select a Day and Directory and the Code selects all Files which were modified before that Day.
Now i want to store all these Files in a Zip Archive but i don't get it :(
$path = Read-Host "please select path : "
Set-Alias sz "C:\Program Files\7-Zip\7zG.exe"
$bis = Read-Host "please select date (dd.mm.yyyy): "
$bisdate = [datetime]::ParseExact($bis,'dd.MM.yyyy',$null)
$files = Get-ChildItem $path | Where {$_.LastWriteTime -lt $bisdate} | ForEach-Object { $_.FullName} > C:\Test\list.txt
I found several samples for 7zip operations but can't find a solution for this Situation. Is there any option like in Bash? Something like that?
zip archive -# < out.txt

You can create archive with this code ifyou has 7z.exe and 7z.dll in specified directory:
foreach ($filePath in [System.IO.File]::ReadAllLines("c:\Test\list.txt"))
{
$archParams += "`"" + $filePath + "`" "
}
$archParams = "a `"C:\Test\list.zip`" " + $archParams
Start-Process -FilePath "C:\Program Files\7-Zip\7z.exe" -Wait -ArgumentList $archParams
The escaping of qoutes are necessary because of space-symbol in paths to files

You can use "7za". It is a 7zip-console-application. You find it using google.
Place it in a common path, which is in you path-variables.
Here is an example:
7za a -tzip "C:temp\myzip.zip" "C:\temp\Client\*.*"

Related

Copy and paste files through clipboard in Powershell

In the folder E:\Files there are 2 files, which I want to copy and paste into D:\Dest:
E:\Files\
File1.txt
File2.txt
Using the keyboard I would simply select the 2 files, push ctrl+c, and in the destination folder D:\Dest\ I then push ctrl+v.
Now I want to achieve this using Powershell. So I copy the files into the clipboard:
Set-Clipboard -Path E:\Files\*
But how to paste those files now into the destination folder? Obviously, I will need Get-Clipboard. But it's not quite clear to me, how to use it, in order to paste the files.
I know I could copy the contents of these 2 files and then by using Set-Content create those files in D:\Dest\ on my own and copy the content into them. But is there any direct way? Because with Set-Clipboard those files already are in the clipboard. They just need to be pasted. I can use ctrl+v and it works. But I want to paste them through Powershell. Any ideas?
Here's the script I use to paste files/directories:
$fileDrop = get-clipboard -Format FileDropList
if($fileDrop -eq $null)
{
write-host "No files on the clipboard"
return
}
foreach($file in $fileDrop)
{
if($file.Mode.StartsWith("d"))
{
$source = join-path $file.Directory $file.Name
$e = "copy-item -Recurse $source $($file.Name)"
$e
Invoke-Expression $e
}
else
{
$file.Name
$file | copy-item
}
}
You could use the .NET Clipboard class:
Add-Type -AssemblyName System.Windows.Forms
$files = [System.Collections.Specialized.StringCollection]::new()
$files.Add('YOUR_FILE_PATH_HERE')
[System.Windows.Forms.Clipboard]::SetFileDropList($files)
This copies YOUR_FILE_PATH_HERE to the local clipboard.
You could use this, for example, when you're in a local terminal and need to copy file(s) to a remote session without PowerShell remoting (e.g., RDP or Citrix) without opening the directory in Explorer.
It's a little unwieldy, so if I used it a lot, I'd probably put it in a function like Copy-FileToClipboard and add it to my PowerShell profile.
Inspired by the other comment in this thread, but refactored, and supporting both move and copy actions (moving is the default action, while copying is achieved with the -c parameter). The script pastes clipboard files and folders into the current directory (I have placed it in a PATH directory and use it as paste).
$data = Get-Clipboard -Format FileDropList
if ($data -ne $null)
{
foreach ($file in $data)
{
if ($args[0] -eq "-c")
{
$action = "Copied:"
Copy-Item -Recurse -LiteralPath $file
}
else
{
$action = "Moved:"
Move-Item -LiteralPath $file
}
$action
"- from: $(Join-Path $file.Directory $file.Name)"
"- into: $(Join-Path "$(Get-Location)" $file.Name)"
}
}
The -LiteralPath parameter was needed to handle filenames containing square brackets.

Powershell Save File In Original Folder When Recursing Through Folders

I am attempting to use a Powershell Script I found on here to convert PDF files into TIFF files. I have the majority of the script working but I can't seem to figure out how to have the TIFF files saved in the original folder that the PDF was in.
#Path to your Ghostscript EXE
$tool = 'C:\Program Files\gs\gs9.25\bin\gswin64c.exe'
#Directory containing the PDF files that will be converted
$inputDir = 'C:\Temp\Test_ED_Data\1\'
#Output path where converted PDF files will be stored
$outputDirPDF = 'C:\Temp\PDF_Out\'
#Output path where the TIFF files will be saved
$outputDir = $inputDir
$pdfs = get-childitem $inputDir -recurse | where {$_.Extension -match "pdf"}
foreach($pdf in $pdfs)
{
$tif = $outputDir + $pdf.BaseName + ".tiff"
if(test-path $tif)
{
"tif file already exists " + $tif
}
else
{
'Processing ' + $pdf.Name
$param = "-sOutputFile=$tif"
& $tool -q -dNOPAUSE -sDEVICE=tiffg4 $param -r300 $pdf.FullName -c quit
}
Move-Item $pdf $outputDirPDF
}
After the script runs, all the PDFs show up in the original input directory and not in any sub directories.
So for example, if C:\Temp\Test_ED_Data\1\ has 1 PDF in it, it gets converted to TIFF and saved in C:\Temp\Test_ED_Data\1\, but any PDFs in a sub directory such as C:\Temp\Test_ED_Data\1\Progress\ also get saved in the original sub directory of C:\Temp\Test_ED_Data\1.
How do I get this script to make sure the converted files are saved in the directory they are retrieved from? It seems as if Powershell doesn't remember the recursed path when it refers to the section $outputDir = $inputDir. What do I need to do to correct that?
Thank you.
So a quick look at the scripts shows
$outputDir = $inputDir
But also
$pdfs = get-childitem $inputDir -recurse | where {$_.Extension -match "pdf"}
This basically means find all files with a PDF extension in $inputDir and search all other folders inside $inputDir. But where you save is a static location of the $inputDir
Give this a shot
function CovertPDF-TIFF($InputDirectory, $OutputPDFLocation){
$tool = 'C:\Program Files\gs\gs9.25\bin\gswin64c.exe'
get-childitem $InputDirectory -include "*.pdf" -recurse | %{
$tiff = "$($_.Directory)\$($_.BaseName).tiff"
if(test-path $tiff)
{
"tiff file already exists " + $tiff
}
else
{
'Processing ' + $_.Name
$param = "-sOutputFile=$tiff"
& $tool -q -dNOPAUSE -sDEVICE=tiffg4 $param -r300 $_.FullName -c quit
}
Move-Item $pdf $OutputPDFLocation
}
}
CovertPDF-TIFF -InputDirectory C:\Temp\Test_ED_Data\1\ -OutputPDFLocation C:\Temp\PDF_Out\
Whats happening here is piping. Piping is basically where you take the output and push it to another command the symbol for pipe is |.
In the Get-ChildItem we will -include all files that end in *.pdf
We Pipe | each item to a foreach-object otherwise known as %
There we create a variable $Tiff to store where and what name to call the tiff based on the PDF we found. In a pipe the $_ is the variable for the information that was piped (in this case its the Child Item Information aka the PDF file information). In powershell $() allows you to add separate commands to a string or another command called a expression its proper name is a Sub Expression. So $Tiff holds the string of the Child Item Directory then adds the Child Item File name then adds the .tiff to the end.
It then checks to see if the Item exists with the command Test-Path.
If it does then it returns a message. If it doesnt then it creates the parameters and runs the gswin64c.exe executable. In one of the Parameters you will see -sOutputFile=$tiff This is where we difine where the new Tiff file will be saved. Lastly the Move the PDF file to a new location with Move-Item
All you need to do is, exchange this line:
$tif = $outputDir + $pdf.BaseName + ".tiff"
with this:
$tif = $pdf.FullName -Replace $pdf.Extension,".tiff"

Code for automating incremented ZIP compression?

I'm trying to ZIP a folder of 800 pictures, with each ZIP file containing only 10 or less pictures, so I should end up with 80 ZIP files. If anyone knows the BAT file code to do this, I would be very appreciative. I also do NOT want to delete the files after they've been zipped.
I know that I'll probably be using 7-Zip, but I just can't seem to find an answer for this anywhere. Thanks!
Try the following PowerShell:
# Setup variables (Change)
$ZipFolder = "T:\YourFolder\WithFiles\ToZip"
$7Zip = "C:\Program Files\7-Zip\7z.exe"
$NewZipsFolder = "T:\FolderToPut\AllOfThe\ZipsIn"
# Script Variables
$pendingFiles = #()
$fileNumber = 1
# Get a list of all the files to be zipped
Get-ChildItem $ZipFolder | sort $_.FullName | ForEach-Object { $pendingFiles += $_.FullName }
# While there are files still to zip
While($pendingFiles){
# Select first 10 files to zip and zip them
$ToZip = $pendingFiles | Select -First 10
& $7Zip "a" "$NewZipsFolder\File-$fileNumber.7z" $ToZip
# Remove first 10 zipped files from pending files array
$pendingFiles = $pendingFiles | Where-Object { $ToZip -notcontains $_ }
$fileNumber++
}
This will create a list of all the file that need to be zipped. Then zip them up in batches of 10 files using 7z.exe (7-zip).
Note: For the variables $ZipFolder & $NewZipsFolder do not put a trailing backslash on the folder paths (\).
You could store an list of files in Powershell using something along the lines of
$fileList = Get-Item -Path "C:\MyPhotosDir\*"
Then set an alias for 7zip
set-alias sz "$env:ProgramFiles\7-Zip\7z.exe"
Then create a loop with a counter along the lines of
$i = 1
foreach $file in $fileList
#Build foder name name
$folderDir = "C:\MyPhotoArchive$($i - ($i % 10) + 1).7z"
sz a -t7z $folderDir $file.filename
end for
I have been writing in VB for a short while and so apologies if the Powershell syntax is a bit off. Essentially that should add 10 files to "C:\MyPhotoArchive1", 10 files to "C:\MyPhotoArchive2". I haven't added files to an archive using 7zip for a long time but I think the call just uses a a and should add files to an archive, creating one when needed.

Executing external command from PowerShell is not accepting a parameter

I am executing the following code attempting to execute the 7z.exe command to unzip files.
$dir contains the user input of the path to the zip file which can contain spaces of course! And $dir\temp2 below is a directory that I previously created.
Get-ChildItem -path $dir -Filter *.zip |
ForEach-Object {
$zip_path = """" + $dir + "\" + $_.name + """"
$output = " -o""$dir\temp2"""
&7z e $zip_path $output
}
When I execute it I get the following from 7z.exe:
7-Zip [64] 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
Processing archive: C:\test dir\test.zip
No files to process
Files: 0
Size: 0
Compressed: 50219965
If I then copy the value from $zip_path and $output to form my own cmd line it works!
For example:
7z e "c:\test dir\test.zip" -o"c:\test output"
Now, I can reproduce the same message "no files to process" I get when I execute within PowerShell by using the following cmd in cli.
7z e "c:\test dir\test.zip" o"c:\test output"
So, it seems that PowerShell is removing the dash char from my -o option. And yes, it needs to be -o"C:\test output" and not -o "c:\test output" with 7z.exe there is no space between the -o parameter and its value.
I am stumped. Am I doing something wrong or should I be doing this a different way?
I can never get Invoke-Expression (alias = &) to work right either, so I learned how to use a process object
$7ZExe = (Get-Command -CommandType Application -Name 7z )
$7ZArgs = #(
('-o"{0}\{1}"' -f $dir, $_.Name),
('"{0}\{1}"' -f $dir, 'temp2')
)
[Diagnostics.ProcessStartInfo]$7Zpsi = New-Object -TypeName:System.Diagnostics.ProcessStartInfo -Property:#{
CreateNoWindow = $false;
UseShellExecute = $false;
Filename = $7ZExe.Path;
Arguments = $7ZArgs;
WindowStyle = 'Hidden';
RedirectStandardOutput = $true
RedirectStandardError = $true
WorkingDirectory = $(Get-Location).Path
}
$proc = [System.Diagnostics.Process]::Start($7zpsi)
$7ZOut = $proc.StandardOutput
$7ZErr = $proc.StandardError
$proc.WaitForExit()
I was able to duplicate the exact issue and tried numerous combinations escaping the -o switch and escaping quotes " and what not.
But as one answer mentioned Sysinternals, and I used Process Monitor to find out the format it was passing to 7z.exe. Things that work on a plain commandline doesn't work inside PowerShell the same way.
For example, if I tried to construct parameters inside PowerShell just like cmdline it would fail. I.e., -o"C:\scripts\so\new folder" doesn't work. But if you include the -o switch inside quotes then PowerShell passes the string "-oC:\scripts\so\new folder" which 7z.exe is happy to accept. So I learned that 7z.exe would accept both the formats such as
"C:\Program Files\7-zip\7z.exe" e "C:\scripts\so\new folder.zip" -o"C:\scripts\so\new folder"
and
"C:\Program Files\7-zip\7z.exe" e "C:\scripts\so\new folder.zip" "-oC:\scripts\so\new folder"
And both examples contain spaces in them.
[string]$pathtoexe = "C:\Program Files\7-Zip\7z.exe"
$dir = "C:\scripts\so"
$output = "$dir\new folder"
Get-ChildItem -path $dir -Filter *.zip | % {
[array]$marguments = "e",$_.FullName,"-o$output";
& $pathtoexe $marguments
}
Another approach in PowerShell V3 is to escape the PowerShell parsing feature. You can use the --% command to tell PowerShell to stop parsing any more commands like this.
$zipfile = "C:\scripts\so\newfolder.zip"
$destinationfolder = "C:\scripts\so\New Folder"
[string]$pathtoexe = "C:\Program Files\7-Zip\7z.exe"
& $pathtoexe --% e "C:\scripts\so\newfolder.zip" -o"C:\scripts\so\new folder"
Using the --% syntax, you type commands just like you would type them on the command line. I tested this logic, and it extracts files to the destination folder.
To learn more about --%, check PS> help about_parsing.
The issue with this approach is after --% it is not possible to include a variable. The solution to this issue is to just include the --% as another string variable and pass it like this. And this approach is similar to the commandline approach which wasn't working originally.
[string]$pathtoexe = "C:\Program Files\7-Zip\7z.exe"
$dir = "C:\scripts\so"
$output = "$dir\new folder"
Get-ChildItem -path $dir -Filter *.zip | % {
$zipfile = $_.FullName;
[string]$formatted = [System.String]::Concat("e ", """$zipfile"""," -o""$output""");
[string]$stopparser = '--%';
& $pathtoexe $stopparser $formatted;
}
Using the excellent Process Explorer from the Windows Sysinternals suite I was able to observe some very interesting behavior. I simplified your command line a little as seen below:
dir -Path $dir -Filter *.zip |
select FullName |
% { & 7za.exe e $_ "-o$dir\tmp" }
This was actually invoking the following command line according to Process Explorer:
C:\temp\7za.exe #{FullName="C:\temp\test.zip"} -oC:\temp\test
Telling PowerShell to expand the FullName property forces it out of the hashmap and treats it as a regular string which 7-Zip can deal with:
dir -Path $dir -Filter *.zip |
select -ExpandProperty FullName |
% { & 7za.exe e $_ "-o$dir\tmp" }
There may still be other issues like dealing with spaces in file names that I really didn't consider or account for, but I thought it was worth adding a note that PowerShell (v2 in this case) wasn't quite passing the parameters as you might expect.

A PowerShell script to list all files and folders within a directory

I've been trying to find a script that recursively prints all files and folders within a directory like this where the backslash is used to indicate directories:
Source code\
Source code\Base\
Source code\Base\main.c
Source code\Base\print.c
List.txt
I'm using PowerShell 3.0 and most other scripts I've found do not work (though they didn't anything like what I'm asking).
Additionally: I need it to be recursive.
What you are likely looking for is something to help distinguish a file from a folder. Luckily there is a property call PSIsContainer that is true for folder and false for files.
dir -r | % { if ($_.PsIsContainer) { $_.FullName + "\" } else { $_.FullName } }
C:\Source code\Base\
C:\Source code\List.txt
C:\Source code\Base\main.c
C:\Source code\Base\print.c
If the leading path information is not desirable, you can remove it easily enough using -replace:
dir | % { $_.FullName -replace "C:\\","" }
Hopefully this gets you headed off in the right direction.
It could be like:
$path = "c:\Source code"
DIR $path -Recurse | % {
$_.fullname -replace [regex]::escape($path), (split-path $path -leaf)
}
Following the #Goyuix idea:
$path = "c:\source code"
DIR $path -Recurse | % {
$d = "\"
$o = $_.fullname -replace [regex]::escape($path), (split-path $path -leaf)
if ( -not $_.psiscontainer) {
$d = [string]::Empty
}
"$o$d"
}
dir | % {
$p= (split-path -noqualifier $_.fullname).substring(1)
if($_.psiscontainer) {$p+'\'} else {$p}
}
This one shows full paths, as some of the other answers do, but is shorter:
ls -r | % { $_.FullName + $(if($_.PsIsContainer){'\'}) }
However, the OP I believe asked for relative paths (i.e. relative to the current directory) and only #C.B.'s answer addressed that point. So by just adding a substring we have this:
ls -r | % { $_.FullName.substring($pwd.Path.length+1) + $(if($_.PsIsContainer){'\'}) }
PowerShell Command For Directory List into Txt File:
For Full Path Directory List (Folder & File) to text file:
ls -r | % { $_.FullName + $(if($_.PsIsContainer){'\'}) } > filelist.txt
For Relative Path Directory List (Folder & File) to text file:
ls -r | % { $_.FullName.substring($pwd.Path.length+1) + $(if($_.PsIsContainer){'\'}) } > filelist.txt
Not powershell, but you can use the following within command prompt to recursively list files into a textfile:
dir *.* /s /b /a:-d > filelist.txt
You can achieve this through the get-childitem command in PowerShell. Refer to the below syntax:
Get-ChildItem "Folder name or Path" -Recurse | select FullName > list.txt
This will help you write all the plain files and folders names recursively onto a file called list.txt
Refer to this for more information. https://ss64.com/ps/get-childitem.html
Answering late, but it might help someone!
(ls $path -r).FullName | % {if((get-item "$_").psiscontainer){"$_\"}else{$_}}
Only use in PS 3.0
I made an improved version of the code submitted (since the code output are inside powershell which has an output limit)
Shift + Right Click in the folder you're trying to scan files and folder on
copy and paste this (just edit your_pc_name)
dir -r | % { if ($.PsIsContainer) { $.FullName + "" } else { $_.FullName } } | Out-File -FilePath c:\users\your_pc_name\desktop\OUTPUT.txt
This will print all the files and folders into a txt file in your dekstop.
extra tips:
copy the output and paste it in excel
use ctrl + f to search for the filename you wanted.
This help me a lot in searching for a large database of files.