PowerShell 脚本未压缩正确的文件

PowerShell script not zipping correct files

 Function Zip
{
    Param
    (
        [string]$zipFile
        ,
        [string[]]$toBeZipped
    )
    $CurDir = Get-Location
    Set-Location "C:\Program Files-Zip"
    .z.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

我正在测试我在网上找到的这个脚本。我的问题是,它没有压缩目标文件夹中的文件,而是复制并压缩 7-zip 程序文件夹的内容。什么会导致这个?提前致谢

将文件作为完整路径传递给Zip函数,使用它们的.FullName 属性(PSv3+语法):

Zip C:\Users\Admin\Desktop\TEST.zip $Files.FullName

问题是,Windows PowerShell 中,Get-ChildItem [=86] 返回的 [System.IO.FileInfo] 个实例=]situationally[1] stringify to their file names only,这就是你的情况,因此您的 Zip 函数随后将 $toBeZipped 值解释为 相对于当前位置 ,即当时的 C:\Program Files-Zip

也就是说,最好不要在你的函数中完全使用 Set-Location,这样万一你 想要传递实际的 relative 路径,它们被正确地解释为相对于 current 位置:

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-Zipz.exe" A -tzip $zipFile $toBeZipped
    # You may want to add error handling here.
}

[1] Get-ChildItem 输出字符串化到文件 names only:

注:

  • 如果要将 Get-ChildItem 输出传递给 其他文件处理 cmdlet,说 Rename-Item, the problem can be bypassed by providing input to them via the pipeline, which implicitly binds to the target cmdlet's -LiteralPath parameter by full path - see this answer了解更多信息。

  • 相关的Get-Item cmdlet输出总是字符串化为完整路径,还好。

  • 在 PowerShell (Core) v6.1+ 中,Get-ChildItem 也是 总是 字符串化为完整路径,还好。

因此仅适用于WindowsPowerShell中的Get-ChildItem:

问题是双重的:

  • 即使是 PowerShell 的内置 cmdlet 也会绑定文件/目录 arguments(参数值 - 与通过 pipeline) 不是 objects,而是 strings(更改此行为正在 GitHub issue #6057 中讨论)。

  • 因此,为了稳健的参数传递,您需要确保您的 Get-ChildItem 输出始终字符串化为 完整路径 ,其中 Get-ChildItem not 保证 - 很容易忘记什么时候发生 name-only 字符串化,甚至根本不需要注意它。

始终传递 .FullName 属性 值是最简单的解决方法 或者,对于 any[=154= 的可靠操作] PowerShell 提供程序,不仅仅是文件系统,.PSPath.

[System.IO.FileInfo][System.IO.DirectoryInfo]Get-ChildItem 命令输出的实例仅字符串化到它们的文件 names当且仅当:

  • 如果一个或多个文字目录路径传递给-LiteralPath-Path(可能作为第一个位置参数)根本没有路径被传递(目标当前地点);也就是说,如果枚举了目录的内容

  • andalso 使用 -Include / -Exclude参数(是否使用-Filter区别)。

  • 相比之下,以下是否也存在没有区别:

    • -Filter(可选地作为 2nd 位置参数,但请注意,将 *.txt 等通配符表达式指定为 1st (可能只有)位置参数绑定到 -Path 参数)
    • -Recurse(由本身,但注意它经常与-Include / -Exclude结合使用)

示例命令:

# 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

如果您(暂时)禁用 |Out-Null 您会看到传递的错误信息。
$Files 包含对象,而不仅仅是文件名数组。

默认情况下,powershell 尝试使用不包含路径的 Name 属性 对其进行字符串化 - 因此 7zip 无法找到文件,因为您还更改了 7zip 文件夹的路径(和递归收集 $files)

所以换行

$Files = Get-Childitem $TargetFolder -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}

并追加

| Select-Object -ExpandProperty FullName

你的来源的一个稍微重新格式化的版本:

Function Zip{
    Param (
        [string]$zipFile,
        [string[]]$toBeZipped
    )
    & "C:\Program Files-Zipz.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