PowerShell 脚本没有压缩正确的文件

问题描述 投票:0回答:2
 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

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

powershell scripting zip target 7zip
2个回答
9
投票

将文件作为完整路径传递给

Zip
函数,使用它们的
.FullName
属性
(PSv3+语法):

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

问题是,Windows PowerShell中,由

[System.IO.FileInfo]
situationally
[1]返回的Get-ChildItem实例仅字符串化为它们的文件名
,这就是你的情况,因此您的
Zip
函数然后将
$toBeZipped
值解释为 relative 到当前位置,即
C:\Program Files\7-Zip
在那个点。

就是说,最好不要在你的函数中完全使用

Set-Location
,这样如果你do想要传递实际的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\7-Zip\7z.exe" A -tzip $zipFile $toBeZipped
    # You may want to add error handling here.
}

[1] When

Get-ChildItem
输出字符串化到文件 names 只有:

注:

  • 如果

    Get-ChildItem
    输出要传递给其他文件处理cmdlet,比如说
    Rename-Item
    可以通过管道向它们提供输入绕过问题,这通过完整路径隐式绑定到目标 cmdlet 的 -LiteralPath
     参数 - 有关更多信息,请参阅
    this answer

  • 相关的Get-Item

     cmdlet 输出always stringifies to the full path,幸运的是。
    

  • 在 PowerShell (Core) v6.1+ 中,Get-ChildItem

     
    always stringifies to the full path, 幸运的是。

因此

以下仅适用于Get-ChildItem

Windows PowerShell中:

问题是双重的:

  • 甚至 PowerShell 的内置 cmdlet 绑定文件/目录

    arguments(参数值 - 与通过pipeline输入相反)不是作为objects,而是作为strings(更改此行为正在讨论GitHub问题 #6057).

  • 因此,为了稳健的参数传递,您需要确保您的

    Get-ChildItem

     输出始终字符串化为 
    完整路径,而 Get-ChildItem
     确实 
    not 保证 - 而且当 name-only 字符串化时很容易忘记发生或什至你需要注意它。

始终传递 .FullName

 属性值是最简单的解决方法
或者,为了与 any PowerShell 提供程序(而不仅仅是文件系统)进行可靠操作,.PSPath
.

[System.IO.FileInfo]

[System.IO.DirectoryInfo]
 实例输出由 
Get-ChildItem
 命令字符串化到他们的文件 
names only, if and only if:

  • 如果

    一个或多个文字目录路径传递给-LiteralPath

    -Path
    (可能作为第一个位置参数)
    根本没有传递路径(定位当前位置) ;也就是说,如果枚举目录的contents

  • also使用-Include

     / 
    -Exclude
    参数
    (是否使用
    -Filter
    使得
    no不同)。

  • 相比之下,以下是否也存在使

    no不同:

    • -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
    

1
投票
如果你(暂时)禁用

|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\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
    
© www.soinside.com 2019 - 2024. All rights reserved.