PowerShell脚本未压缩正确的文件

PowerShell脚本未压缩正确的文件,powershell,scripting,zip,target,7zip,Powershell,Scripting,Zip,Target,7zip,我正在测试我在网上找到的这个脚本。我的问题是,它不是压缩目标文件夹中的文件,而是复制和压缩7-zip程序文件文件夹的内容。这是什么原因造成的?提前感谢使用文件的.FullName属性(PSv3+语法),将文件作为完整路径传递给Zip函数: 问题是,通过情景[1]返回的[System.IO.FileInfo]实例只将其文件名字符串化,这就是您的情况,因此您的Zip函数随后将$toBeZipped值解释为相对于当前位置的值,这是C:\ProgramFiles\7-Zip 也就是说,最好不要在函数中

我正在测试我在网上找到的这个脚本。我的问题是,它不是压缩目标文件夹中的文件,而是复制和压缩7-zip程序文件文件夹的内容。这是什么原因造成的?提前感谢

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


问题是,通过情景[1]返回的
[System.IO.FileInfo]
实例只将其文件名字符串化
,这就是您的情况,因此您的
Zip
函数随后将
$toBeZipped
值解释为相对于当前位置的值,这是
C:\ProgramFiles\7-Zip

也就是说,最好不要在函数中使用
设置位置
,这样在您确实希望传递实际相对路径的情况下,它们会被正确地解释为相对于当前位置:

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

[1]
Get ChildItem
输出字符串化为仅文件名时:

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.
}
注:

  • 相关cmdlet输出始终字符串化为完整路径,
  • 幸运的是,在PowerShell[Core]v6.1+中,
    Get ChildItem
    总是字符串化到完整路径
因此,以下仅适用于Windows PowerShell中的
Get ChildItem

问题有两方面:

  • 即使是PowerShell的内置cmdlet也不会将文件/目录参数(参数值-而不是通过管道输入)绑定为对象,而是绑定为字符串(更改此行为将在中讨论)

  • 因此,对于健壮的参数传递,您需要确保您的
    Get ChildItem
    输出一致地字符串化到完整路径,而
    Get ChildItem
    并不能保证这一点,而且当只使用名称字符串化时,即使您需要注意它,也很容易忘记

始终传递
.FullName
属性值是最简单的解决方法
或者,对于任何PowerShell提供程序(而不仅仅是文件系统)的可靠操作,
.PSPath

[System.IO.FileInfo]
[System.IO.DirectoryInfo]
通过
Get ChildItem
命令输出的实例仅字符串化为其文件名,当且仅当

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

  • 并且不使用
    -Include
    /
    -Exclude
    参数(是否使用
    -Filter
    ,没有区别)

  • 相比之下,以下各项是否也存在并无区别:

    • -Filter
      (可选作为第二个位置参数,但请注意,将通配符表达式(如
      *.txt
      指定为第一个(可能是唯一的)位置参数将绑定到
      -Path
      参数)
    • -Recurse
      (它本身,但请注意,它通常与
      -Include
      /
      -Exclude
      结合使用)
命令示例:

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.
}
如果(临时)禁用
| Out Null
,您将看到消息传递的错误。
$Files包含对象,而不仅仅是文件名数组

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

那就换线吧

# 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
并附加

$Files = Get-Childitem $TargetFolder -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
源代码中稍微重新格式化的韵文:

| Select-Object -ExpandProperty FullName

你在哪里找到剧本的?当文件对象被强制转换为字符串时,它们只是成为文件名。。。不是完整的路径。我认为您需要逐个处理每个文件。您还可以删除
Out Null
,以帮助自己获得更多关于正在发生的事情的信息。@Matt:这里他们确实只对文件名进行字符串化,这就是问题所在,但他们是对文件名进行字符串化还是对完整路径进行字符串化通常取决于
get ChildItem
调用的具体情况,(非常)不幸的是,我试图在我的回答中总结规则。我看到了。给我留下深刻印象。它前后不一致使我恼火。我只是习惯用全名now@Matt:是的,这是一种非常不幸的行为,会导致潜伏的bug。我很高兴这个问题不再出现在PS Core中(我们希望这个变化,从技术上讲是一个破坏性的变化,是有意的,或者至少会保留下来)。好的。成功了。但是,如果我再试一次,并且没有任何文件夹符合要压缩的标准,它将压缩7zip程序的内容。有什么办法可以防止吗?对不起,我没法跟上。我刚刚用建议编辑测试了我发布的版本,它在这里运行,并没有任何缺陷。我同意mklement0的观点,最好不要像@mklement0Yes建议的那样,将7zip文件夹的路径更改为avid压缩该文件夹。发布的版本可以工作。但是,假设我在一个没有任何要压缩文件的文件中运行此操作,将发生的情况是7-zip程序的所有内容都复制到zip文件夹中。将参数设置为必需的
Param([Parameter(Position=0,mandatory=$true)][string]$zipFile,[Parameter(Position=1,mandatory=$true)][string[]$toBeZipped)
@LotPings:这里的对象确实只字符串化为文件名,这就是问题所在,但它们是否字符串化为仅文件名(
.Name
)或
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