0

I want to Compress-Archive a folder except for any files/subfolders that pass an array of regex. I'm trying something like this:

$FilesToExclude = @("**/*.*proj*", "**/obj/**", "**/bin/Debug/**", "**/bin/Release/**", "**/*.vb", "**/*.cs", "**/AssemblyInfo.vb", "**/AssemblyInfo.cs", "**/Properties/", "**/Debug/**", "**/Release/**", "**/My Project/**", "**/Web.Debug.config", "**/Web.Release.config", "**/*.pdb", "**/*.sln")

Get-ChildItem -Path <path> | Where-Object { $_ -notmatch $FilesToExclude } | Compress-Archive -DestinationPath destination -Update

But it doesn't seem to be doing anything. What am I doing wrong?

Do Yeon Kim
  • 119
  • 1
  • 9
  • Try `$_.fullname` in the `where-object` query. – Nico Nekoru Jun 05 '20 at 22:42
  • 4
    you are using regex [`-notmatch`] ... and asterisks are special chars in regex. they mean `zero or more of the previous char`. your pattern is not likely to work. plus, the `-notmatch` operator doesn't work with an _array_ of patterns. you need to use the `|` char [the regex version of OR]. – Lee_Dailey Jun 05 '20 at 23:17
  • @Lee_Dailey I've tried both of your suggestions and did Get-ChildItem -Path | Where-Object { $_.fullname -notmatch ".*\\bg\\.*" } | Compress-Archive -DestinationPath -Update. It doesn't seem to filter out any folder by the name bg. Is there anything I could change here? Thanks a lot. – Do Yeon Kim Jun 08 '20 at 14:50
  • @NekoMusume I've tried `\\bg\\` as well. – Do Yeon Kim Jun 08 '20 at 14:51
  • @DoYeonKim - at what point in the code do things not work as expected? test each stage and then add to your Question the code and the point where it fails to do what you need done. – Lee_Dailey Jun 08 '20 at 15:07
  • @Lee_Dailey It fails at the `Where-Object` call. So for an example I want any folder by the name `bg` to be excluded, I've tried `Where-Object {$_.fullname -notmatch ".*\\bg"}`, and this seems to only exclude `bg` folders at the root, but not subfolders (recursively). – Do Yeon Kim Jun 08 '20 at 15:26

2 Answers2

1

Personally, I would separate the paths to exclude and the extensions to exclude for this to make things a lot more redable.

Using the -Exclude parameter on Get-ChildItem it is easy enough to use an array of extensions where wildcards are permitted.

Mind you, This parameter can only be used if you also add the -Recurse switch or let the path end in \* for the Get-ChildItem cmdlet.

This will also help in reducing the number of items listed. (i.e. by excluding *.vb, you are automatically also excluding AssemblyInfo.vb)

The paths can be combined in a regex string. (for details, see below)

By doing so, the code could look like this:

$ExtensionsToExclude = '*.vb', '*.cs', '*.pdb', '*.sln', '*.*proj*'
$PathsToExclude      = '\\(obj|Debug|Release|Properties|My Project)\\|\\Web\.(Debug|Release)\.config\\'

Get-ChildItem -Path <path> -Recurse -Exclude $ExtensionsToExclude | 
    Where-Object { $_.FullName -notmatch $PathsToExclude } | 
    Compress-Archive -DestinationPath <destination> -Update

Regex details:

                           Match either the regular expression below (attempting the next alternative only if this one fails)
   \\                      Match the character “\” literally
   (                       Match the regular expression below and capture its match into backreference number 1
                           Match either the regular expression below (attempting the next alternative only if this one fails)
         obj               Match the characters “obj” literally
      |                    Or match regular expression number 2 below (attempting the next alternative only if this one fails)
         Debug             Match the characters “Debug” literally
      |                    Or match regular expression number 3 below (attempting the next alternative only if this one fails)
         Release           Match the characters “Release” literally
      |                    Or match regular expression number 4 below (attempting the next alternative only if this one fails)
         Properties        Match the characters “Properties” literally
      |                    Or match regular expression number 5 below (the entire group fails if this one fails to match)
         My\ Project       Match the characters “My Project” literally
   )                      
   \\                      Match the character “\” literally
|                          Or match regular expression number 2 below (the entire match attempt fails if this one fails to match)
   \\                      Match the character “\” literally
   Web                     Match the characters “Web” literally
   \.                      Match the character “.” literally
   (                       Match the regular expression below and capture its match into backreference number 2
                           Match either the regular expression below (attempting the next alternative only if this one fails)
         Debug             Match the characters “Debug” literally
      |                    Or match regular expression number 2 below (the entire group fails if this one fails to match)
         Release           Match the characters “Release” literally
   )                      
   \.                      Match the character “.” literally
   config                  Match the characters “config” literally
   \\                      Match the character “\” literally

Hope that helps

Theo
  • 57,719
  • 8
  • 24
  • 41
  • Thanks for your response. However it seems that `-Recurse` flattens everything, and I need to maintain my directory structure. – Do Yeon Kim Jun 08 '20 at 15:32
  • 1
    the builtin archive cmdlet WILL NOT preserve the path if you give it a file. it also WILL NOT preserve the full path if you give it a dir ... only the named dir & it's sub dirs will be preserved. – Lee_Dailey Jun 08 '20 at 16:04
  • I see. Looks like I'll need to look for a completely different solution then. Thank you! – Do Yeon Kim Jun 08 '20 at 17:21
  • @DoYeonKim But that wasn't your question. You asked how to **exclude files and paths** and that is what my answer is about. Not what Compress-Archive can or cannot do.. – Theo Jun 08 '20 at 19:09
  • Sorry, I should've specified in the question that I want to maintain the folder structure, and the -Recurse (as well as Compress-Archive) won't work. – Do Yeon Kim Jun 09 '20 at 18:55
0

While you asked how to use Compress-Archive for this purpose, I'd recommend instead using ZipFileExtensions.CreateEntryFromFile as it supports specifying the destination name within the zip file including a relative path. An error for a single file being inaccessible can be trapped and recovery is supported.

It's possible to filter files and store relative paths using Compress-Archive, but it usually involves copying the files to a temporary folder before compressing and cleaning them up afterwards. The extra copying makes this method much slower than ZipFileExtensions.CreateEntryFromFile and less reliable.

Here is an example that seems similar to your needs. You might choose to simplify the $filter code by using a regex similar to @Theo's above.

Rich Moss
  • 2,195
  • 1
  • 13
  • 18