El script de PowerShell no comprime los archivos correctos
Function Zip
{
Param
(
[string]$zipFile
,
[string[]]$toBeZipped
)
$CurDir = Get-Location
Set-Location "C:\Program Files\7-Zip"
.\7z.exe A -tzip $zipFile $toBeZipped | Out-Null
Set-Location $CurDir
}
$Now = Get-Date
$Days = "60"
$TargetFolder = "C:\users\Admin\Downloads\*.*"
$LastWrite = $Now.AddDays(-$Days)
$Files = Get-Childitem $TargetFolder -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
$Files
Zip C:\Users\Admin\Desktop\TEST.zip $Files
Estoy probando este script que encontré en línea. Mi problema es que en lugar de comprimir los archivos en la carpeta de destino, copia y comprime el contenido de la carpeta de archivos del programa 7-zip. Que podria causar esto? gracias de antemano
Pase los archivos como rutas completas a la Zip
función, usando su .FullName
propiedad (sintaxis de PSv3+):
Zip C:\Users\Admin\Desktop\TEST.zip $Files.FullName
El problema es que, en Windows PowerShell , las [System.IO.FileInfo]
instancias devueltas situacionalmente [1] se encadenan solo a sus nombres de archivoGet-ChildItem
, que es lo que sucedió en su caso, por lo que su Zip
función interpretó los $toBeZipped
valores como relativos a la ubicación actual , que es C:\Program Files\7-Zip
en ese punto.
Dicho esto, es mejor no usarlo Set-Location
en tu función por completo , de modo que en caso de que quieras pasar rutas relativas reales , se interpreten correctamente como relativas a la ubicación actual :
Function Zip {
Param
(
[Parameter(Mandatory)] # make sure a value is passed
[string]$zipFile
,
[Parameter(Mandatory)] # make sure a value is passed
[string[]]$toBeZipped
)
# Don't change the location, use & to invoke 7z by its full path.
$null = & "C:\Program Files\7-Zip\7z.exe" A -tzip $zipFile $toBeZipped
# You may want to add error handling here.
}
[1] Cuando la salida se refiere únicamente Get-ChildItem
a nombres de archivos:
Nota:
Si
Get-ChildItem
la salida se va a pasar a otros cmdlets de procesamiento de archivos , por ejemploRename-Item
, el problema se puede evitar proporcionándoles entrada a través de la canalización , que implícitamente se vincula al-LiteralPath
parámetro del cmdlet de destino mediante la ruta completa; consulte esta respuesta para obtener más información.Get-Item
Afortunadamente, la salida del cmdlet relacionado siempre incluye la ruta completa .Afortunadamente, en PowerShell (Core) v6.1+,
Get-ChildItem
también siempre se especifica la ruta completa .
Por lo tanto, lo siguiente sólo se aplica Get-ChildItem
en Windows PowerShell :
El problema es doble:
Incluso los cmdlets integrados de PowerShell vinculan los argumentos de archivos/directorios (valores de parámetros, a diferencia de la entrada a través de la canalización ) no como objetos , sino como cadenas (el cambio de este comportamiento se analiza en el número 6057 de GitHub ).
Por lo tanto, para un paso de argumentos sólido, debe asegurarse de que su
Get-ChildItem
salida se encadene consistentemente a rutas completas , lo cualGet-ChildItem
no garantiza , y es fácil olvidar cuando se produce una encadenamiento de solo nombre o incluso que debe prestarle atención.
Pasar siempre los .FullName
valores de las propiedades es la solución más sencilla o, para un funcionamiento fiable con cualquier proveedor de PowerShell, no solo con el sistema de archivos, .PSPath
.
[System.IO.FileInfo]
y [System.IO.DirectoryInfo]
las instancias generadas por un Get-ChildItem
comando se encadenan a sus nombres de archivo solo, si y solo si :
Si se pasan una o más rutas de directorio literales
-LiteralPath
a o-Path
(posiblemente como el primer argumento posicional) o no se pasa ninguna ruta (apunta a la ubicación actual); es decir, si se enumeran los contenidos de los directorios.y tampoco usa los parámetros /
-Include
-Exclude
(si se usan no-Filter
hacediferencia).Por el contrario, no importa si están presentes o no los siguientes :
-Filter
(opcionalmente como segundo argumento posicional, pero tenga en cuenta que especificar una expresión comodín como*.txt
el primer (y posiblemente único) argumento posicional se vincula al-Path
parámetro)-Recurse
(por sí solo , pero tenga en cuenta que a menudo se combina con-Include
/-Exclude
)
Comandos de ejemplo:
# NAME-ONLY stringification:
Get-ChildItem | % ToString # no target path
Get-ChildItem . | % ToString # path is literal dir.
Get-ChildItem . *.txt | % ToString # path is literal dir., combined with -Filter
# FULL PATH stringification:
Get-ChildItem foo* | % ToString # non-literal path (wildcard)
Get-ChildItem -Recurse -Include *.txt | % ToString # use of -Include
Get-ChildItem file.txt | % ToString # *file* path
Si desactiva (temporalmente) |Out-Null
verá qué mensaje de error pasa.
$Files contiene objetos, no solo una matriz de nombres de archivos.
De forma predeterminada, PowerShell intenta encadenar esto usando la Name
propiedad que no contiene la ruta, por lo que 7zip no puede encontrar los archivos ya que también cambia la ruta a la carpeta 7zip (y -recurse recopila $files)
Así que cambia la línea
$Files = Get-Childitem $TargetFolder -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
y agregar
| Select-Object -ExpandProperty FullName
Una versión ligeramente reformateada de su fuente:
Function Zip{
Param (
[string]$zipFile,
[string[]]$toBeZipped
)
& "C:\Program Files\7-Zip\7z.exe" A -tzip $zipFile $toBeZipped | Out-Null
}
$Days = "60"
$LastWrite = (Get-Date).Date.AddDays(-$Days)
$TargetFolder = "$($ENV:USERPROFILE)\Downloads\*"
$Files = Get-Childitem $TargetFolder -Recurse |
Where {$_.LastWriteTime -le $LastWrite} |
Select-Object -ExpandProperty FullName
$Files
Zip "$($ENV:USERPROFILE)\Desktop\TEST.zip" $Files