PowerShell: разрыв вложенных циклов


В PowerShell должна быть команда break, которая может выходить из вложенных циклов, назначая метку. Просто это не работает. Вот мой код:

$timestampServers = @(
    "http://timestamp.verisign.com/scripts/timstamp.dll",
    "http://timestamp.comodoca.com/authenticode",
    "http://timestamp.globalsign.com/scripts/timstamp.dll",
    "http://www.startssl.com/timestamp"
)

:outer for ($retry = 2; $retry -gt 0; $retry--)
{
    Write-Host retry $retry
    foreach ($timestampServer in $timestampServers)
    {
        Write-Host timestampServer $timestampServer
        & $signtoolBin sign /f $keyFile /p "$password" /t $timestampServer $file
        if ($?)
        {
            Write-Host OK
            break :outer
        }
    }
}
if ($retry -eq 0)
{
    WaitError "Digitally signing failed"
    exit 1
}

Выводится следующее:

retry 2
timestampServer http://timestamp.verisign.com/scripts/timstamp.dll
Done Adding Additional Store
Successfully signed and timestamped: C:\myfile.dll
OK
retry 1
timestampServer http://timestamp.verisign.com/scripts/timstamp.dll
Done Adding Additional Store
Successfully signed and timestamped: C:\myfile.dll
OK

ERROR: Digitally signing failed

Что я сделал не так?

Можно мне Гото и этикетки, пожалуйста?

Используя Windows 7 и, я думаю, PS 2.0. Этот скрипт должен работать по крайней мере на PS 2.

2   4   2014-06-04 21:38:23

2 ответа:

Двоеточие не добавляется при использовании break с меткой цикла. Эта строка:

break :outer

Должно быть написано так:

break outer

Для дальнейшей демонстрации рассмотрим этот простой сценарий:

:loop while ($true)
{
    while ($true)
    {
        break :loop
    }
}

Когда он будет выполнен, он будет работать вечно, не ломаясь. Однако этот сценарий:

:loop while ($true)
{
    while ($true)
    {
        break loop
    }
}

Выходит как надо, потому что я изменил break :loop на break loop.

Итак, я немного изменил код, чтобы сделать его понятным

$timestampServers = @(
    "http://timestamp.verisign.com/scripts/timstamp.dll",
    "http://timestamp.comodoca.com/authenticode",
    "http://timestamp.globalsign.com/scripts/timstamp.dll",
    "http://www.startssl.com/timestamp"
)


:outer for ($retry = 2; $retry -gt 0; $retry--)
{
    Write-Host retry $retry
    foreach ($timestampServer in $timestampServers)
    {
        Write-Host timestampServer $timestampServer
        #& $signtoolBin sign /f $keyFile /p "$password" /t $timestampServer $file

        if ($true)
        {

            break :outer
            Write-Host OK
        }
    }
}
if ($retry -eq 0)
{
    Write-Error "Digitally signing failed"  ## you have a typo there
    exit 1
}

Это приводит к следующему:

retry 2
timestampServer http://timestamp.verisign.com/scripts/timstamp.dll
retry 1
timestampServer http://timestamp.verisign.com/scripts/timstamp.dll
C:\temp\t.ps1 : Digitally signing failed
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,t.ps1

Итак, пропускает Write-Host OK,но также, кажется, продолжает цикл. Другими словами, он действует как утверждение "продолжить".

Изменил его, как и упомянутые люди, чтобы удалить ':', хотя документация PowerShell не исключает этого:

 if ($true)
        {

            break outer
            Write-Host OK
        }

Я получаю правильное поведение.

retry 2
timestampServer http://timestamp.verisign.com/scripts/timstamp.dll

Короче говоря... не используйте ': '