Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
629 views
in Technique[技术] by (71.8m points)

scripting - PowerShell script not zipping correct files

 Function Zip
{
    Param
    (
        [string]$zipFile
        ,
        [string[]]$toBeZipped
    )
    $CurDir = Get-Location
    Set-Location "C:Program Files7-Zip"
    .7z.exe A -tzip $zipFile $toBeZipped | Out-Null
    Set-Location $CurDir
}
$Now = Get-Date
$Days = "60"
$TargetFolder = "C:usersAdminDownloads*.*"
$LastWrite = $Now.AddDays(-$Days)
$Files = Get-Childitem $TargetFolder -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
$Files
Zip C:UsersAdminDesktopTEST.zip $Files

I am testing out this script I found online. My problem is that instead of zipping the files in the target folder, it is copying and zipping the contents of the 7-zip program file folder. What could cause this? Thanks in advance

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Pass the files as full paths to the Zip function, using their .FullName property (PSv3+ syntax):

Zip C:UsersAdminDesktopTEST.zip $Files.FullName

The problem is that the [System.IO.FileInfo] instances returned by Get-ChildItem situationally[1] stringify to their file names only, which is what happened in your case, so your Zip function then interpreted the $toBeZipped values as relative to the current location, which is C:Program Files7-Zip at that point.

That said, it's better not to use Set-Location in your function altogether, so that in the event that you do want to pass actual relative paths, they are correctly interpreted as relative to the current 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 Files7-Zip7z.exe" A -tzip $zipFile $toBeZipped
    # You may want to add error handling here.
}

[1] When Get-ChildItem output stringifies to file names only:

Note:

  • The related Get-Item cmdlet output always stringifies to the full path, fortunately.
  • In PowerShell [Core] v6.1+, Get-ChildItem too always stringifies to the full path, fortunately.

The following therefore only applies to Get-ChildItem in Windows PowerShell:

The problem is twofold:

  • Even PowerShell's built-in cmdlets bind file / directory arguments (parameter values - as opposed to input via the pipeline) not as objects, but as strings (changing this behavior is being discussed in GitHub issue #6057).

  • Therefore, for robust argument-passing, you need to ensure that your Get-ChildItem output consistently stringifies to full paths, which Get-ChildItem does not guarantee - and it's easy to forget when name-only stringification occurs of even that you need to pay attention to it at all.

Always passing the .FullName property values instead is the simplest workaround or, for reliable operation with any PowerShell provider, not just the filesystem, .PSPath.

[System.IO.FileInfo] and [System.IO.DirectoryInfo] instances output by a Get-ChildItem command stringify to their file names only, if and only if:

  • If one or more literal directory paths are passed to -LiteralPath or -Path (possibly as the 1st positional argument) or no path at all is passed (target the current location); that is, if the contents of directories are enumerated.

  • and does not also use the -Include / -Exclude parameters (whether -Filter is used makes no difference).

  • By contrast, whether or not the following are also present makes no difference:

    • -Filter (optionally as the 2nd positional argument, but note that specifying a wildcard expression such as *.txt as the 1st (and possibly only) positional argument binds to the -Path parameter)
    • -Recurse (by itself, but note that it is often combined with -Include / -Exclude)

Example commands:

# 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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...