Hey, Scripting Guy! Weekend Scripter: Using Windows PowerShell to Compress Folders

Hey, Scripting Guy! Weekend Scripter: Using Windows PowerShell to Compress Folders

  • Comments 2
  • Likes

Bookmark and Share

 

Microsoft Scripting Guy Ed Wilson here. It is another beautiful weekend in Charlotte, North Carolina. I enjoy getting up early on the weekend, having a leisurely breakfast, reading for a little while, and then heading up to my office to write some scripts. I have a white board upon which I write down ideas for scripts that I wish to write. The idea for today’s script actually came from Twitter a few days ago. The question was “How can I use Windows PowerShell to compress a folder?” I did a search of the Scripting Guys blog, and found a VBScript that uses the compress method from the Win32_Directory WMI class. I decided to play around with that idea, and came up with a pretty cool script. The complete CreateCompressedFolderAndCopyFiles.ps1 script is seen here.

CreateCompressedFolderAndCopyFiles.ps1

Param(
 $compressedFolder = "C:\compressedFSO",
 $pathForFiles = "C:\fso",
 $computer = "localhost"
) #end param

function test-andCreateFolder($computer, $compressedFolder)
{
 if(-not(test-path -Path $compressedFolder))
  {
   New-Item -Path $compressedFolder -ItemType directory
   compress-folder -computer $computer -compressedFolder $compressedFolder
  }
 else { compress-folder -computer $computer -compressedFolder $compressedFolder }
} #end function test-andCreateFolder

function compress-folder($computer, $compressedFolder)
{
 $rtn = `
([wmi]"
\\$computer\root\cimv2:win32_directory.name='$compressedFolder'").`
compress()
 if($rtn.returnvalue -eq 0) { "$compressedFolder successfully compressed"}
 else { "$($rtn.returnvalue) error occurred compressing $compressedFolder";exit}
} #end function compress-folder


# *** entry point to script ***

test-andCreateFolder -compressedFolder $compressedFolder -computer $computer
Copy-Item -Path $pathForFiles -Destination $compressedFolder -Include * -Recurse


The CreateCompressedFolderAndCopyFiles.ps1 script accepts three parameters from the command line when it is run. The first parameter is the path to the folder you wish to compress. The second parameter is the path to the source files, and the last parameter is the name of your computer. The parameters are shown here:

Param(
 $compressedFolder = "C:\compressedFSO",
 $pathForFiles = "C:\fso",
 $computer = "localhost"
) #end param


After the parameters have been created, the script moves to the functions. The first function looks for the folder that will be compressed and that will store the files to be compressed. It initially uses the Test-Path cmdlet to see if the folder exists. If the folder does not exist, it creates the folder and calls the compress-folder function. If the folder does exist, it simply calls the compress-folder function. This function is shown here:

function test-andCreateFolder($computer, $compressedFolder)
{
 if(-not(test-path -Path $compressedFolder))
  {
   New-Item -Path $compressedFolder -ItemType directory
   compress-folder -computer $computer -compressedFolder $compressedFolder
  }
 else { compress-folder -computer $computer -compressedFolder $compressedFolder }
} #end function test-andCreateFolder


The compress-folder function accepts two parameters. The first is $computer and the second is $compressedFolder. The main part of the code is the [WMI] type accelerator. This is used to connect directly to an instance of a WMI class. In this example, the Win32_Directory WMI class refers to every single folder on the entire computer. That is a huge number in most cases. To improve performance, I do not want to search for folders; rather, I want to connect to a specific folder with WMI, and then compress that particular folder. The [WMI] type accelerator allows me to do just that. One thing I learned today is that on Windows 7, WMI allows me to connect to a folder without needing to use the double backward slashes. I found this out by accident when I put my folder path into a variable, and then passed the variable to WMI. Normally, I would type the command to connect to a folder as shown here:

PS C:\Users\ed.NWTRADERS> [wmi]"\\localhost\root\cimv2:win32_directory.name='c:\\fso'"


Hidden                : False
Archive               : False
EightDotThreeFileName : c:\fso
FileSize              :
Name                  : c:\fso
Compressed            : False
Encrypted             : False
Readable              : True


You might even be tempted to use double quotation marks to surround the path to the folder. In that case, the command would look like this command where the quotation mark is used to escape the quotation marks surrounding the path to the folder:

PS C:\Users\ed.NWTRADERS> [wmi]"\\localhost\root\cimv2:win32_directory.name=""c:\\fso"""


Hidden                : False
Archive               : False
EightDotThreeFileName : c:\fso
FileSize              :
Name                  : c:\fso
Compressed            : False
Encrypted             : False
Readable              : True


I access the returned Win32_Directory WMI class by using dotted notation, and I call the compress method. The return code is stored in the $rtn variable. If the returnvalue property is equal to 0, it means no errors occurred during the compress operation. If it is equal to anything else, I display the error number and a message that the error occurred. The WMI return code values are documented on MSDN.

function compress-folder($computer, $compressedFolder)
{
 $rtn = `
([wmi]"\\$computer\root\cimv2:win32_directory.name='$compressedFolder'").`
compress()
 if($rtn.returnvalue -eq 0) { "$compressedFolder successfully compressed"}
 else { "$($rtn.returnvalue) error occurred compressing $compressedFolder" ; exit }
} #end function compress-folder


The entry point to the script calls the Test-andCreateFolder function that in turn calls the Compress-Folder function. After that function has completed, it calls the Copy-Item cmdlet to copy the files to the compressed folder. This section of the script is shown here:

Test-andCreateFolder -compressedFolder $compressedFolder -computer $computer
Copy-Item -Path $pathForFiles -Destination $compressedFolder -Include * -Recurse


The advanced properties of the folder display the compressed state of the folder. This is shown in the following image.

Image of compressed state of folder


One thing you may wish to be aware of, is that if you try to copy content from the source folder to the compressed folder, an error will be generated the second time. This is because the destination folder will already exist. You can fix this problem by adding the –force parameter to the Copy-Item cmdlet. The line would look like the following:

Copy-Item -Path $pathForFiles -Destination $compressedFolder -Include * -Recurse –force


By using the -force parameter, you will overwrite any existing files with the new ones you are copying over. This may be fine according to your application. The error is seen in the following image.

Image of error displayed

 


Well, that is about enough fun for one morning. If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • <p>Sometimes the short-sightedness of the powershell developers is amazing, a simple Send-ToZip or an Out-Zip file built into the language when the OS provides this in the GUI..</p>

  • Is there a way to compress the entire C: drive? Like checking the &quot;Compress this drive to save disk space&quot; box on c: properties? I know this is a old post, hopefully I can still get some feedback. Thanks!