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:
- Apri la cartella dei tuoi ZIP: Naviga usando Esplora Risorse (la normale finestra di Windows) fino alla cartella che contiene tutti i file compressi.
- 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
Shiftsulla tastiera, fare clic destro e selezionare “Apri finestra PowerShell qui”. - 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
BaseNamesalva 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
| Elemento | Comportamento |
|---|---|
| Destinazione | Crea un’unica cartella takeout nella cartella corrente. |
| Estrazione | Per 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. |
| Merge | I file di ZIP1/takeout/Documenti/ e ZIP2/takeout/Documenti/ finiscono entrambi in takeout/Documenti/. |
| Conflitti | Se un file esiste già (perché è stato estratto da uno ZIP precedente), ti chiede cosa fare. |
| Scelte | Y (solo questo), N (salta questo), A (sovrascrivi tutti i prossimi senza chiedere), S (salta tutti i prossimi senza chiedere). |