Как зациклить в powershell до успешного? - PullRequest
3 голосов
/ 01 декабря 2011
%WINDIR%\system32\inetsrv\appcmd.exe set site /site.name:"WebRole_IN_0_CB" /[Path='/'].applicationPool:"ASP.NET v4.0" >>CBLog.log
powershell.exe -command Set-ExecutionPolicy Unrestricted
powershell.exe .\CheckIfSuccessful.ps1

Я бы хотел запустить приведенный выше сценарий, и если appcmd.exe не может его выполнить из-за того, что веб-сайт еще не запущен и не готов, я получу следующее сообщение об ошибке в файле CBLog.log.

ОШИБКА (сообщение: не удается найти объект SITE с идентификатором "WebRole_IN_0_CB". )

В CheckIfSuccessful.ps1 я хотел бы создать скрипт для цикла Powershell, который запускает команду appcmd и снова проверяет ошибку. Затем спит в течение 5 секунд, а затем повторяет попытку, пока это не удастся.

Как бы я сделал это в Powershell?

высоко ценится,

UPDATE

Хорошо, большое спасибо за подсказку с $ lastexitcode, хотя она выглядит многообещающе. Кажется, у меня проблемы с преобразованием одинарных кавычек в Powershell: (ниже приведена часть моей первоначальной команды appcmd)

/[Path='/'].applicationPool:"ASP.NET v4.0"

Как мне процитировать это в powershell? Я попытался упростить его, чтобы у PowerShell было меньше проблем, но теперь моя команда неверна, как говорится:

ОШИБКА (сообщение: не удается найти объект SITE с идентификатором "v4.0".)

 & $Env:WinDir\system32\inetsrv\appcmd.exe set site '/site.name:"WebRole_IN_0_CB"' "/[Path='/'].applicationPool:`"ASP.NET v4.0`"" >CBLog.log
if($lastexitcode -ne '0')
{
    while($lastexitcode -ne '0')
    {
        Start-Sleep -s 5
        & $Env:WinDir\system32\inetsrv\appcmd.exe set site '/site.name:"WebRole_IN_0_CB"' "/[Path='/'].applicationPool:`"ASP.NET v4.0`"" >CBLog.log
    }
}

ОБНОВЛЕНИЕ II: Я избежал этого должным образом. Но все равно я получаю сообщение об ошибке. Если я запускаю appcmd в одиночку после создания этого сайта, файл журнала будет в порядке. Любые предложения, пожалуйста?

Ответы [ 2 ]

4 голосов
/ 01 декабря 2011

Специальная переменная $lastexitcode предоставляет код завершения последнего собственного исполняемого файла (т.е. не командлета), который был запущен.Это будет иметь разные значения в зависимости от результатов операции.Например, это будет 5, если appcmd обнаружит, что доступ запрещен.Должно быть 0, если последняя команда выполнена успешно.

Обязательно проверяйте эту переменную сразу после запуска appcmd и в том же сценарии.В противном случае вы рискуете получить код выхода из powershell.exe, а не из appcmd.exe

1 голос
/ 18 апреля 2016

Я понимаю, что первоначальная проблема, вероятно, давно решена, но ради того, чтобы гуглеры задавали этот вопрос, я написал универсальную (расширенную) функцию для повторного запуска команд оболочки (cmd).В дополнение к $ LASTEXITCODE он также может анализировать поток ошибок (с некоторыми инструментами код выхода может быть ложью).

function Call-CommandWithRetries
{
 [CmdletBinding()]
 param( 
     [Parameter(Mandatory=$True)]
     [string]$Command,
     [Array]$Arguments,
     [bool]$TrustExitCode = $True,
     [int]$RetrySleepSeconds = 10,
     [int]$MaxAttempts = 10,
     [bool]$PrintCommand = $True
 )

 Process
 {
  $attempt = 0
  while ($true)
  {   
   Write-Host $(if ($PrintCommand) {"Executing: $Command $Arguments"} else {"Executing command..."}) 
   & $Command $Arguments 2>&1 | tee -Variable output | Write-Host

   $stderr = $output | where { $_ -is [System.Management.Automation.ErrorRecord] }
   if ( ($LASTEXITCODE -eq 0) -and ($TrustExitCode -or !($stderr)) )
   {
    Write-Host "Command executed successfully"
    return $output
   }

   Write-Host "Command failed with exit code ($LASTEXITCODE) and stderr: $stderr" -ForegroundColor Yellow
   if ($attempt -eq $MaxAttempts)
   {
    $ex = new-object System.Management.Automation.CmdletInvocationException "All retry attempts exhausted"
    $category = [System.Management.Automation.ErrorCategory]::LimitsExceeded
    $errRecord = new-object System.Management.Automation.ErrorRecord $ex, "CommandFailed", $category, $Command
    $psCmdlet.WriteError($errRecord)
    return $output
   }

   $attempt++;
   Write-Host "Retrying test execution [#$attempt/$MaxAttempts] in $RetrySleepSeconds seconds..."
   Start-Sleep -s $RetrySleepSeconds
  }
 }
}

Для получения дополнительной информации (включая полную документацию) см. https://www.ohadsoft.com/2016/04/invoking-arbitrary-shell-cmd-commands-in-powershell.

В вашем случае вы бы сделали что-то вроде

$appCmd = [io.path]::combine($env:WINDIR, 'system32', 'inetsrv', 'appcmd.exe')
$appCmdArg = @('set', 'site', '/site.name:"WebRole_IN_0_CB"', '/[Path=''/''].applicationPool:"ASP.NET v4.0"')
$output = Call-CommandWithRetries $appCmd $appCmdArgs
# write $output to log etc
...