0

I am using a PowerShell script to zip up files that are older than 60 days. Some of these files have really long filenames so I get the filename or extension is too long error.

I would rather not go into each file and change the names so I need a way to be able to apply something to all the files at the same time or have my script bypass the error somehow. This script is also going to be run on several computers so I would prefer not to download something on to each one.

This is the script:

#Set source and target
$Source = "D:\Testing\" 
$Target = "$ENV:USERPROFILE\Desktop\TEST.zip"

#Set time parameters
$Days = 60    
$LastWrite = (Get-Date).Date.AddDays(-$Days)

#Invoke 7-zip
if (-not (test-path "$env:ProgramFiles\7-Zip\7z.exe")) {throw 
"$env:ProgramFiles\7-Zip\7z.exe needed"} 
set-alias zip "$env:ProgramFiles\7-Zip\7z.exe"  

$Target = Get-Childitem $Source -Recurse | Where-Object -FilterScript 
{($_.LastWriteTime -ge $LastWrite)}

zip a -mx=9 $Target $Source

I am using 7-zip to zip up the files and I have PS version 5.1.

techguy1029
  • 743
  • 10
  • 29
  • one option would be to enable long file names. that can be done directly via a registry entry OR you can use Group Policy to make the change. the reg key is easily found with a search for `win10 enable long file names`. – Lee_Dailey Jan 14 '19 at 22:35
  • Thanks for the response. Did that and I still got the same thing. 7z failed to run: filename or extension too long – techguy1029 Jan 14 '19 at 22:57
  • ouch! i have no other viable ideas. the usual one is to map a drive into the dirtree deeply enuf to shorten the effective path, but that is not workable for anything other than a few computers. – Lee_Dailey Jan 14 '19 at 23:34
  • First of all, the re-use of $Target variable for the zip file name and the files to be zipped is confusing (to me at least). Maybe you meant something like this: `$Files = Get-Childitem $Source -Recurse | Where-Object -FilterScript {($_.LastWriteTime -ge $LastWrite)} $files | %{ zip a -mx=9 $Target $_ } #zip each file ` Also, try to store a shorter path to the file by switching into a deeper folder and getting the relative path. See [my script] (https://stackoverflow.com/questions/53740869/how-to-compress-log-files-older-than-30-days-in-windows/53752330#53752330) for an example. – Rich Moss Jan 15 '19 at 00:13
  • Ok. Would something like this work: $Files = Get-ChildItem -LiteralPath $TargetFolder -Recurse | Where {$_.LastWriteTime -le "$LastWrite"} Zip "$($ENV:USERPROFILE)\Desktop\TEST.zip" $Files – techguy1029 Jan 15 '19 at 00:36
  • And what part of your script is for getting the relative path? It's kinda hard to make out for me, I'm sorta new to PowerShell. – techguy1029 Jan 15 '19 at 00:41
  • Which version of 7-zip you're using? – montonero Jan 15 '19 at 08:03
  • This line gets the file's path relative to the current folder: `$RelativePath = (Resolve-Path -LiteralPath "$($File.FullName)" -Relative).TrimStart(".\")` Removing the .\ at the beginning will allow the path to be used inside the zip file. – Rich Moss Jan 15 '19 at 17:28
  • The problem with `Zip "$($ENV:USERPROFILE)\Desktop\TEST.zip" $Files` is that 7Zip.exe is expecting a filespec like *.txt, not a Powershell file object collection. `$files | %{ zip a -mx=9 "$($ENV:USERPROFILE)\Desktop\TEST.zip" $_ }` pipes the $files array to the % (foreach alias) and runs the zip command line for each. – Rich Moss Jan 15 '19 at 18:14
  • Tried what you commented above and it doesn't give me the error. However it does create multiple archive files over and over again. – techguy1029 Jan 16 '19 at 20:55

1 Answers1

2

As mentioned in the comments, one way around long file names is to store relative paths. 7Zip will store relative paths if you specify an input file with the relative paths and they resolve to the files you want to archive, as described in this answer.

Intermediate files can be messy, so I've written a script that uses the ZipFileExtensions' CreateEntryFromFile method to store a relative path in a zip file. You can specify -ParentFolder on the command line to store paths relative to the parent, including a UNC path if you want to archive files on another computer. If -ParentFolder is not specified it will choose the script's folder as the parent and store paths relative to the script.

Copy the code to a new script named ArchiveOldLogs.ps1 and run it with this command line:

 .\ArchiveOldLogs.ps1 -ParentFolder "D:\Testing\" -FileSpecs @("*.*") -Filter { $_.LastWriteTime -lt (Get-Date).AddDays(-60)} -DeleteAfterArchiving:$false

That will get you 11 more characters at the end of the path to store, which should be enough to get around the 10 character difference between Windows and Zip path length limits. Try a deeper folder if you still get errors. The files that can't be archived, or are already archived will be skipped.

Remove -DeleteAfterArchiving:$false from the command line when you're comfortable that it's archiving only what you want.

Rich Moss
  • 2,195
  • 1
  • 13
  • 18
  • Thanks for the response.Tried it. It makes the zip archive but the archive doesn't contain anything. – techguy1029 Jan 16 '19 at 00:37
  • Do you have any files under d:\Testing\ that are >60 days old? Try opening the script in Powershell ISE, and hit F9 to add a breakpoint on the `$FileList = (Get-ChildItem ..` line. Run the script with F5 and step through that line with the F11 key. Mouse over each variable to see the values. – Rich Moss Jan 16 '19 at 22:33
  • Tried it again. Seemed to work this time. Thanks for the help. – techguy1029 Jan 16 '19 at 23:47