UNZIP massivo di n file compressi

Come estrarre più file ZIP contemporaneamente su Windows usando PowerShell

Ti è mai capitato di scaricare decine di file .zip (magari backup, foto o documenti di lavoro) e doverli estrarre uno ad uno? Fare clic destro, selezionare “Estrai tutto…”, confermare la cartella e ripetere l’operazione per ogni singolo archivio è un’operazione noiosa e che fa perdere un sacco di tempo.

Se usi Windows, non hai bisogno di scaricare programmi esterni o script complicati per automatizzare questo processo. Hai già a disposizione uno strumento potentissimo e integrato nel sistema: PowerShell.

In questo articolo vedremo come scompattare decine o centinaia di archivi ZIP con una singola riga di comando.

La procedura passo dopo passo

Il nostro obiettivo è estrarre ogni file .zip all’interno di una sua cartella dedicata, in modo da mantenere tutto il tuo spazio di lavoro perfettamente in ordine e non mischiare i file.

Ecco come fare:

  1. Apri la cartella dei tuoi ZIP: Naviga usando Esplora Risorse (la normale finestra di Windows) fino alla cartella che contiene tutti i file compressi.
  2. Avvia PowerShell: Fai clic destro in un punto vuoto della cartella e seleziona “Apri nel terminale” (su Windows 11). Se usi Windows 10, puoi tenere premuto il tasto Shift sulla tastiera, fare clic destro e selezionare “Apri finestra PowerShell qui”.
  3. Lancia il comando magico: Copia la riga di codice che trovi qui sotto, incollala nella finestra blu di PowerShell e premi Invio.

PowerShell

Get-ChildItem *.zip | ForEach-Object { Expand-Archive $_.FullName -DestinationPath $_.BaseName }

Fatto! Ora vedrai il terminale lavorare per te, creando magicamente una nuova cartella per ogni file ZIP ed estraendone il contenuto all’interno.

Come funziona questo comando?

Se ti piace capire cosa succede “sotto il cofano” del tuo computer, ecco una rapida spiegazione di come è composto questo script:

  • Get-ChildItem *.zip: Dice a PowerShell di guardare nella cartella corrente e selezionare esclusivamente i file che terminano con l’estensione .zip.
  • | ForEach-Object: Prende la lista di file trovata nel passaggio precedente e dice al sistema: “Per ogni file che hai trovato, esegui l’azione seguente”.
  • Expand-Archive $_.FullName: È il comando effettivo che si occupa di decomprimere (estrarre) il singolo file.
  • -DestinationPath $_.BaseName: Questa è la parte più intelligente dello script. Dice a PowerShell di creare una cartella di destinazione che ha esattamente lo stesso nome del file originale (escludendo però la scritta “.zip”).

💡 Il vero vantaggio: L’uso della variabile BaseName salva la tua cartella dal caos. Se hai 50 file ZIP e li estrai tutti assieme senza creare sottocartelle, potresti ritrovarti con migliaia di documenti sparsi ovunque. Questo comando mantiene un’organizzazione impeccabile.

Carica la libreria .NET per gestire gli ZIP

Add-Type -AssemblyName System.IO.Compression.FileSystem

Dove verrà creato il grande merge: una cartella “takeout” nella posizione corrente

$destinationRoot = Join-Path -Path (Get-Location).Path -ChildPath “takeout”
Write-Host “La cartella di destinazione unica sarà: $destinationRoot” -ForegroundColor Yellow

Crea la cartella “takeout” principale se non esiste

if (-not (Test-Path $destinationRoot)) {
New-Item -ItemType Directory -Path $destinationRoot -Force | Out-Null
}

Prende tutti i file .zip nella cartella corrente

$zipFiles = Get-ChildItem -Path . -Filter *.zip

Variabili globali per le risposte “Si a tutti” e “Salta tutti” (valide per TUTTI gli ZIP)

$overwriteAll = $false
$skipAll = $false

foreach ($zipFile in $zipFiles) {
Write-Host “Elaborazione di $($zipFile.Name) …” -ForegroundColor Cyan

Approfondiamo…

Ora immaginate di avere molte cartelle con la stessa struttura di filesystem all’interno. Tipo TakeOut di Google.

try {
    # Apre il file ZIP in lettura
    $zip = [System.IO.Compression.ZipFile]::OpenRead($zipFile.FullName)

    foreach ($entry in $zip.Entries) {
        # Salta le voci che sono solo cartelle (verranno create automaticamente)
        if ($entry.FullName.EndsWith('/') -or $entry.FullName.EndsWith('\')) {
            continue
        }

        # Estrae il percorso relativo all'interno dello ZIP
        $relativePath = $entry.FullName

        # Verifica se il percorso inizia con "takeout/" (o "takeout\")
        if ($relativePath -match "^takeout[/\\]") {
            # Rimuove il prefisso "takeout/" in modo che i file finiscano DENTRO la nostra unica cartella takeout
            $relativePath = $relativePath -replace "^takeout[/\\]", ""
        } else {
            # Se per qualche strano caso un file non è dentro "takeout", lo mettiamo comunque nella radice di "takeout"
            # (ma lascio un avviso)
            Write-Host "Attenzione: $($entry.FullName) non è in una cartella takeout, verrà estratto nella root di takeout" -ForegroundColor Yellow
        }

        # Se dopo la rimozione la stringa è vuota (caso raro), salta
        if ([string]::IsNullOrEmpty($relativePath)) {
            continue
        }

        # Costruisce il percorso finale DENTRO la cartella "takeout" unica
        $targetPath = Join-Path -Path $destinationRoot -ChildPath $relativePath
        $targetDir = Split-Path -Path $targetPath -Parent

        # Crea le sottocartelle se non esistono
        if (-not (Test-Path $targetDir)) {
            New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
        }

        $fileExists = Test-Path $targetPath

        # Se il file esiste e non abbiamo già deciso per tutti...
        if ($fileExists -and -not $overwriteAll -and -not $skipAll) {
            # Mostra il nome del file e da quale ZIP proviene per aiutare la scelta
            Write-Host "Conflitto per il file: '$relativePath'" -ForegroundColor Red
            Write-Host "  (presente in: $($zipFile.Name))" -ForegroundColor Gray
            do {
                $choice = Read-Host -Prompt "Sovrascrivere? (Y=Si, N=No, A=Si a tutti, S=Salta tutti)"
            } while ($choice -notin 'Y', 'N', 'A', 'S')

            switch ($choice) {
                'A' { $overwriteAll = $true }  # Da ora in poi sovrascrive sempre
                'S' { $skipAll = $true }       # Da ora in poi salta sempre
                'N' { continue }               # Salta solo questo file
                'Y' {                          # Sovrascrive solo questo file
                }
            }
        }

        # Se è stato attivato "Salta tutti" e il file esiste, salta questo file
        if ($fileExists -and $skipAll) {
            continue
        }

        # Estrae il file (il terzo parametro $true significa "sovrascrivi se esiste")
        [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $targetPath, $true)
    }
}
finally {
    if ($zip) { $zip.Dispose() }
}
}

Write-Host "Operazione completata! Tutti i file sono stati uniti in: $destinationRoot" -ForegroundColor Green

Questo è quello che potrebbe fare al caso vostro.

Cosa fa questo script

ElementoComportamento
DestinazioneCrea un’unica cartella takeout nella cartella corrente.
EstrazionePer ogni ZIP, prende tutto ciò che sta dentro la sua takeout e lo copia nella takeout unica, saltando il livello takeout all’interno dello ZIP.
MergeI file di ZIP1/takeout/Documenti/ e ZIP2/takeout/Documenti/ finiscono entrambi in takeout/Documenti/.
ConflittiSe un file esiste già (perché è stato estratto da uno ZIP precedente), ti chiede cosa fare.
ScelteY (solo questo), N (salta questo), A (sovrascrivi tutti i prossimi senza chiedere), S (salta tutti i prossimi senza chiedere).

Lascia un commento