0

将文件项传递给函数然后在 foreach 循环中使用 $input 时,我遇到了一些奇怪的行为(如在非确定性中)。

我这样调用我的函数...

get-childitem Stuff | Create-Zip C:\Stuff.zip

其中“Stuff”包含一堆包含目录和子目录的文件夹。问题是,在重复运行时,一些顶级目录不会被复制,无论它们是否为空。

该功能几乎是http://blogs.msdn.com/b/daiken/archive/2007/02/12/compress-files-with-windows-powershell-then-package-a-windows的直接副本-vista-sidebar-gadget.aspx

function Create-Zip
{
    param([string]$zipfile)
    set-content $zipfile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
    (dir $zipfile).IsReadOnly = $false  

    $shellApplication = new-object -comObject Shell.Application
    $zipPackage = $shellApplication.NameSpace($zipfile)

    foreach($item in $input)
    { 
        $zipPackage.CopyHere($item.FullName)
        Start-sleep -milliseconds 500
    }
}

问题似乎出在 Start-Sleep 行 - 如果我完全省略它,则 zip 文件是空的……如果我将它增加到 10 秒,则 zip 文件通常是满的。为什么会这样,有没有更好的方法来编写它而不依赖于睡眠值?

4

2 回答 2

0

$input应该在脚本块的上下文中进行评估,process {}例如:

function Create-Zip
{
    param([string]$zipfile)
     set-content $zipfile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
     (dir $zipfile).IsReadOnly = $false 

    $shellApplication = new-object -comObject Shell.Application
    $zipPackage = $shellApplication.NameSpace($zipfile)

    process {
        foreach($item in $input)
        { 
            $zipPackage.CopyHere($item.FullName)
            Start-sleep -milliseconds 500
        }
    }
}

但是,如果您使用的是 PowerShell V2,这是传递与文件(字符串路径、FileInfo 等)相关的管道输入的更好方法:

function Verb-Noun
{
    [CmdletBinding(DefaultParameterSetName="Path")]
    param(
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="Path", 
                   ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true,
                   HelpMessage="Path to ...")]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $Path,

        [Alias("PSPath")]
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="LiteralPath", 
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage="Path to ...")]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $LiteralPath
    )

    Begin { Set-StrictMode -Version latest }

    Process {
        if ($psCmdlet.ParameterSetName -eq "Path")
        {
            # In the -Path (non-literal) case we may need to resolve a wildcarded path
            $resolvedPaths = @($Path | Resolve-Path | Convert-Path)
        }
        else 
        {
            # Must be -LiteralPath
            $resolvedPaths = @($LiteralPath | Convert-Path)
        }

        foreach ($rpath in $resolvedPaths) 
        {
            Write-Verbose "Processing $rpath"
            # ... Do something with the raw, resolved $rpath here ...
        }  
    }
}
于 2012-10-02T14:43:36.867 回答
0

我注意到 ParseName 在处理项目时返回 null,因此您可以使用以下代码:

function Create-Zip
{
    param([string]$zipfile)
         set-content $zipfile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
         (dir $zipfile).IsReadOnly = $false 

    $shellApplication = new-object -comObject Shell.Application
    $zipPackage = $shellApplication.NameSpace($zipfile)

    foreach($item in $input)
    { 
             $zipPackage.CopyHere($item.FullName)
             do {
                $i = $zipPackage.ParseName($item.Name)
                Start-Sleep -milliseconds 10
            } while ($i -eq $null)
    }
}

它在这里工作没有问题,即使没有 Start-Sleep 只是为了不烧坏 CPU。

于 2012-10-02T17:58:13.487 回答