迭代PowerShell $输入

时间:2012-10-02 13:03:27

标签: powershell foreach comobject

我将文件项传递给函数然后在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文件通常是满的。为什么会这样,并且有更好的方法来写这个而不依赖于睡眠值?

2 个答案:

答案 0 :(得分: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 ...
        }  
    }
}

答案 1 :(得分: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。