Powershell Zip Folder Contents

11,239

Solution 1

As per @mjolinor "H:\Stuff\", if you have .NET 4.5 installed you can run the following:

$src = "H:\Stuff\"
$dst = "H:\Stuff.zip"
[Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" )
[System.IO.Compression.ZipFile]::CreateFromDirectory($src, $dst)

Solution 2

If you use PSCX Module you will use the line code below to obtain what you need:

write-zip h:\Stuff\* myzipfile.zip 

Solution 3

New solution available with WMF 5 (well not that new ^^)

Compress-Archive -Path H:\stuff\* -DestinationPath H:\stuff.zip -Force
Share:
11,239
user3402227
Author by

user3402227

Updated on July 04, 2022

Comments

  • user3402227
    user3402227 almost 2 years

    I know a lot has been covered on zipping files using Powershell however I cannot find a method which does exactly what I need.

    I want to be able to zip folders AND files into a .zip folder without having the parent folder inside the zip. So for example I have a folder named STUFF which contains files/folders, I want to zip this into a folder called STUFF.zip. This folders structure would then be STUFF.zip>files/folders NOT STUFF.zip>STUFF>files/folders as I currently get using this code...

    function CountZipItems(
    [__ComObject] $zipFile)
    {
    If ($zipFile -eq $null)
    {
        Throw "Value cannot be null: zipFile"
    }
    
    Write-Host ("Counting items in zip file (" + $zipFile.Self.Path + ")...")
    
    [int] $count = CountZipItemsRecursive($zipFile)
    
    Write-Host ($count.ToString() + " items in zip file (" `
        + $zipFile.Self.Path + ").")
    
    return $count
    }
    
    function CountZipItemsRecursive(
    [__ComObject] $parent)
    {
    If ($parent -eq $null)
    {
        Throw "Value cannot be null: parent"
    }
    
    [int] $count = 0
    
    $parent.Items() |
        ForEach-Object {
            $count += 1
    
            If ($_.IsFolder -eq $true)
            {
                $count += CountZipItemsRecursive($_.GetFolder)
            }
        }
    
    return $count
    }
    
    function IsFileLocked(
    [string] $path)
    {
    If ([string]::IsNullOrEmpty($path) -eq $true)
    {
        Throw "The path must be specified."
    }
    
    [bool] $fileExists = Test-Path $path
    
    If ($fileExists -eq $false)
    {
        Throw "File does not exist (" + $path + ")"
    }
    
    [bool] $isFileLocked = $true
    
    $file = $null
    
    Try
    {
        $file = [IO.File]::Open(
            $path,
            [IO.FileMode]::Open,
            [IO.FileAccess]::Read,
            [IO.FileShare]::None)
    
        $isFileLocked = $false
    }
    Catch [IO.IOException]
    {
        If ($_.Exception.Message.EndsWith(
            "it is being used by another process.") -eq $false)
        {
            Throw $_.Exception
        }
    }
    Finally
    {
        If ($file -ne $null)
        {
            $file.Close()
        }
    }
    
    return $isFileLocked
    }
    
    function GetWaitInterval(
    [int] $waitTime)
    {
    If ($waitTime -lt 1000)
    {
        return 100
    }
    ElseIf ($waitTime -lt 5000)
    {
        return 1000
    }
    Else
    {
        return 5000
    }
    }
    
    function WaitForZipOperationToFinish(
    [__ComObject] $zipFile,
    [int] $expectedNumberOfItemsInZipFile)
    {
    If ($zipFile -eq $null)
    {
        Throw "Value cannot be null: zipFile"
    }
    ElseIf ($expectedNumberOfItemsInZipFile -lt 1)
    {
        Throw "The expected number of items in the zip file must be specified."
    }
    
    Write-Host -NoNewLine "Waiting for zip operation to finish..."
    Start-Sleep -Milliseconds 1000 # ensure zip operation had time to start
    
    [int] $waitTime = 0
    [int] $maxWaitTime = 60 * 1000 # [milliseconds]
    while($waitTime -lt $maxWaitTime)
    {
        [int] $waitInterval = GetWaitInterval($waitTime)
    
        Write-Host -NoNewLine "."
        Start-Sleep -Milliseconds $waitInterval
        $waitTime += $waitInterval
    
        Write-Debug ("Wait time: " + $waitTime / 1000 + " seconds")
    
        [bool] $isFileLocked = IsFileLocked($zipFile.Self.Path)
    
        If ($isFileLocked -eq $true)
        {
            Write-Debug "Zip file is locked by another process."
            Continue
        }
        Else
        {
            Break
        }
    }
    
    Write-Host                           
    
    If ($waitTime -ge $maxWaitTime)
    {
        Throw "Timeout exceeded waiting for zip operation"
    }
    
    [int] $count = CountZipItems($zipFile)
    
    If ($count -eq $expectedNumberOfItemsInZipFile)
    {
        Write-Debug "The zip operation completed succesfully."
    }
    ElseIf ($count -eq 0)
    {
        Throw ("Zip file is empty. This can occur if the operation is" `
            + " cancelled by the user.")
    }
    ElseIf ($count -gt $expectedCount)
    {
        Throw "Zip file contains more than the expected number of items."
    }
    }
    
    function ZipFolder(
    [IO.DirectoryInfo] $directory)
    {
    If ($directory -eq $null)
    {
        Throw "Value cannot be null: directory"
    }
    
    Write-Host ("Creating zip file for folder (" + $directory.FullName + ")...")
    
    [IO.DirectoryInfo] $parentDir = $directory.Parent
    
    [string] $zipFileName
    
    If ($parentDir.FullName.EndsWith("\") -eq $true)
    {
        # e.g. $parentDir = "C:\"
        $zipFileName = $parentDir.FullName + $directory.Name + ".zip"
    }
    Else
    {
        $zipFileName = $parentDir.FullName + "\" + $directory.Name + ".zip"
        #$zipFileName = $directory.Name + ".zip"
        #$zipFileName = $parentDir.FullName + ".zip"
    }
    
    If (Test-Path $zipFileName)
    {
        Throw "Zip file already exists ($zipFileName)."
    }
    
    Set-Content $zipFileName ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
    
    $shellApp = New-Object -ComObject Shell.Application
    $zipFile = $shellApp.NameSpace($zipFileName)
    
    If ($zipFile -eq $null)
    {
        Throw "Failed to get zip file object."
    }
    
    [int] $expectedCount = (Get-ChildItem $directory -Force -Recurse).Count
    $expectedCount += 1 # account for the top-level folder
    
    $zipFile.CopyHere($directory.FullName)
    #Get-ChildItem $directory | foreach {$zipFile.CopyHere($_.fullname)}
    
    # wait for CopyHere operation to complete
    WaitForZipOperationToFinish $zipFile $expectedCount
    
    Write-Host -Fore Green ("Successfully created zip file for folder (" `
        + $directory.FullName + ").")
    }
    

    Usage

    Remove-Item "H:\STUFF.zip"
    
    [IO.DirectoryInfo] $directory = Get-Item "H:\STUFF"
    ZipFolder $directory
    

    Complete credit goes here for this code. I really appreciate any help I get, this capability is crucial to my project! Unfortunately I cannot use the Community Extension module as other PC's this will be run on does not have this module installed.

    Thanks!