PowerShell脚本无法压缩正确的文件

6yjfywim  于 12个月前  发布在  Shell
关注(0)|答案(2)|浏览(147)
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程序文件夹的内容。什么可能导致这种情况?提前感谢

xuo3flqw

xuo3flqw1#

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

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

字符串
问题是,Windows PowerShell 中,Get-ChildItem * 根据情况 [1]返回的[System.IO.FileInfo]示例仅字符串化为它们的 * 文件名,这就是您的情况,因此您的Zip函数将$toBeZipped值解释为 * 相对于当前位置 *,此时为C:\Program Files\7-Zip
也就是说,最好不要在你的函数中完全使用Set-Location,这样如果你 * 确实 * 想传递实际的 * 相对 * 路径,它们会被正确地解释为相对于 * 当前 * 位置的路径:

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]* 当 * Get-ChildItem输出仅字符串化为文件名 * 时:**
注意事项:

***如果Get-ChildItem输出要传递给 * 其他文件处理小程序 *,比如Rename-Item,**通过管道 * 向它们提供输入 * 可以 * 绕过 * 这个问题,管道通过完整路径隐式绑定到目标小程序的-LiteralPath参数-有关详细信息,请参阅this answer
***幸运的是,相关的Get-Item小程序输出 * 总是 * 串化为完整路径。
*幸运的是,在PowerShell (Core) v6.1+中,Get-ChildItem也 * 总是 * 字符串化为完整路径

因此,以下内容**仅适用于 Windows PowerShell 中的Get-ChildItem
问题是双重的:

  • 即使是PowerShell的内置插件也不会将文件/目录 * 参数 *(参数值-而不是通过 * 管道 * 输入)绑定为 * 对象 *,而是 * 字符串 *(在GitHub issue #6057中讨论了更改此行为)。
  • 因此,对于健壮的参数传递,您需要确保Get-ChildItem输出一致地字符串化为 * 完整路径 *,而Get-ChildItem * 不 * 保证-并且很容易忘记何时发生 * 仅名称 * 字符串化,甚至您需要注意它。
    始终传递.FullName属性值是最简单的解决方法,或者,为了可靠地操作 * 任何 * PowerShell提供程序,而不仅仅是文件系统,.PSPath
    **Get-ChildItem命令输出的[System.IO.FileInfo][System.IO.DirectoryInfo]示例仅字符串化为它们的文件名 当且仅当 *:
  • 如果**一个或多个 * 文字目录路径 * 被传递到-LiteralPath-Path(可能作为第一个位置参数)* 或 * 根本没有路径 * 被传递(目标是当前位置);也就是说,如果目录的 * 内容 * 被枚举。
  • and does * not also use the -Include/-Exclude parameters**(是否使用-Filter makes no difference).
  • 相比之下,是否存在以下内容也没有 * 区别:
  • -Filter(可选作为 * 第二 * 个位置参数,但请注意,将*.txt*.txt表达式指定为 * 第一 * 个(也可能是唯一一个)位置参数会绑定到-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

6za6bjd0

6za6bjd02#

如果您(暂时)禁用|Out-Null,您将看到沿着的错误消息。
$Files包含的对象不仅仅是一个文件名数组。
默认情况下,powershell尝试使用Name属性将其字符串化,该属性不包含路径-因此7zip无法找到文件,因为您还更改了7zip文件夹的路径(并-recurse收集$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

相关问题