打破foreach循环

时间:2013-02-18 18:55:32

标签: powershell foreach try-catch powershell-v2.0

目前使用以下代码搜索目录并将找到的任何.msi复制到另一个目录。如果它被其他程序使用,我不想复制.msi。我在StackExchange上看到了其他问题,它们显示了检查文件是否正在使用的其他方法,但在Rename-Item命令周围使用try / catch块似乎是一个更简单的解决方案。如果脚本无法重命名我想要的项目,请转到$file中的下一个$listoffiles。我能让它工作的唯一方法是使用下面列出的代码。但是,我似乎无法按照我想要的方式格式化生成的错误消息,似乎-ErrorAction Stop似乎不是必需的。如果try块中发生错误,错误不应该转到catch块吗?此外,我的错误消息中的3个变量中只有2个被写入日志文件。

当前代码:

$listofFiles=(Get-ChildItem -Path $outputPath -Filter "*.msi" | where {$_.Name -notlike "*.Context.msi" -and $_.LastAccessTime -gt (Get-Date).AddMinutes(-15)})

foreach ($file in $listofFiles){
    $y = ($file -split ("\\"))
    $msiFolder = $y[4]

    #Tests to see if $file currently in use
    try{
        Rename-Item -Path $file -NewName $file -ErrorVariable renameError -ErrorAction Stop 
    }
    catch{
        "$logTime ERROR Could not copy $msiFolder: $renameError.Exception.Message()" >> $copyLog
        continue
    }   

    #Code that copies files that are not in use.

目前错误显示如下:

02/18/13 13:43:25 ERROR Could not copy  System.Management.Automation.ActionPreferenceStopException: Command execution stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: The process cannot access the file because it is being used by another process.
   at System.Management.Automation.StatementListNode.ExecuteStatement(ParseTreeNode statement, Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext context)
   at System.Management.Automation.StatementListNode.Execute(Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext context)
   at System.Management.Automation.TryStatementNode.Execute(Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext context).Exception.Message()

我希望它看起来像:

02/18/13 13:34:34 ERROR Could not copy ABC_CLIENT: The process cannot access the file because it is being used by another process.

问题

  1. 为什么$ msiFolder没有出现在日志消息中?
  2. 如何简化错误消息?
  3. 有没有更好的方法来使用try / catch块来打破foreach循环的迭代?
  4. 更新1:

    我清除$error并运行:

    Rename-Item -Path $file -NewName $file -ErrorAction SilentlyContinue
    if (!$?){"$logTime ERROR Could not copy $file: $error[0].Exception.Message()" >> $copyLog}
    

    结果是:

    02/18/13 14:52:59 ERROR Could not copy  The process cannot access the file because it is being used by another process.[0].Exception.Message()
    

    为什么$logTime被打印但其他变量没有?

    更新2: 我用过的最终代码:

    Rename-Item -Path $file -NewName $file -ErrorAction SilentlyContinue 
    if (!$?){
        "$logTime ERROR Could not copy ${msiFolder}: $($error[0].Exception.Message)" >> $copyLog
        continue
    }
    

1 个答案:

答案 0 :(得分:1)

如果要使用try / catch,则需要将从Rename-Item获得的非终止错误转换为终止错误。这就是为什么你需要使用-ErrorAction Stop来调用你的catch块。但是,你可以用另一种方式做到这一点,例如:

foreach ($file in $listofFiles){
    $y = ($file -split ("\\"))
    $msiFolder = $y[4]

    #Tests to see if $file currently in use
    Rename-Item -Path $file -NewName $file -ErrorVariable renameError -ErrorAction SilentlyContinue
    if (!$?) {
        "$logTime ERROR Could not copy ${msiFolder}: $($error[0].Exception.Message)" >> $copyLog
        continue
    }   

    #Code that copies files that are not in use.
}

自动变量$?表示最后一个命令是否成功。

至于为什么$ msiFolder没有得到输出,我会检查拆分操作。检查$ y.count是否> = 5.