Вопрос по – Powershell: отладка в производстве / хорошая обработка исключений

1

Каков наилучший способ анализа командлетов powershell в рабочей среде? Предположим, вы пишете скрипт, который выполняет следующее:

Write lof of registry values Register COM Dlls Make IIS AppPools Start Windows Services

& amp; ... между ними что-то идет не так, каковы наилучшие способы информирования пользователей, чтобы можно было отследить и устранить проблему с корнем?

Suppose, user credentials fail for AppPool creation for some reason and I want to stop processing at that time plus I want to rollback what I had done earlier.

Является ли подробный режим + логирование элегантным способом сбора каждой детали на каждом этапе?

какое-нибудь окончательное решение с полным примером исходного кода об этом? Kiquenet

Ваш Ответ

2   ответа
2

Для непосредственной манипуляции с реестром вы можете использовать поддержку транзакций PowerShell, чтобы либо зафиксировать изменения при общем успехе сценария, либо отменить транзакцию для отката изменений реестра, например:

try {
    $ErrorActionPreference = 'Stop' # convert all errors to terminating errors
    Start-Transaction
    Set-ItemProperty Acme -Name Count -Value 99 -UseTransaction
    Remove-ItemProperty Acme -Name InstallDir -UseTransaction
    New-Item Acme2 -UseTransaction
    New-ItemProperty Acme2 -Name Count -Value 2 -UseTransaction
    New-ItemProperty Acme2 -Name InstallDir -Value 'C:\Program Files\Acme2' -UseTx

    ... do other stuff ...

    Complete-Transaction
}
catch {
    Undo-Transaction
    ... Log failure ...
}
2

Я написалWrite-Log функция, которую я выложил на почтовый индекс (http://poshcode.org/3270 ), который я использую для программ PowerShell производственного уровня. В качестве альтернативы вы можете использоватьStart-Transcript который записывает почти все, что отображается на консоли в файл. Есть пара ошибок оStart-Transcript -

  1. It won't log external program output unless you force it through the host output API by piping it to Out-Host such as ping.exe localhost | Out-Host.
  2. It's not supported on all hosts. For example PowerGUI doesn't support it so you have to add a host check using $host.

Шаблон, который я обычно использую для обработки ошибок - это обернуть все в try / catch. Объект исключения будет доступен как$_ в блоке улова. Он будет содержать все об ошибке, сообщение, номер строки и столбца и т.д ...

Я также установил$ErrorActionPreference вStop чтобы все командлеты выдавали завершающую ошибку, чтобы сценарий не продолжался. Это выглядит так:

$ErrorActionPreference = "Stop"
try {
    # Write lof of registry values
    New-Item -Path HKCU:\Software\MyTest -ItemType Directory
    New-ItemProperty -Path HKCU:\Software\MyTest -Name MyTestValue -Value Test

    # Register COM Dlls
    regsrv32 my.dll
    if ($LASTEXITCODE -ne 0) { throw "Failed to register my.dll" }

    # Make IIS AppPools
    IIS:\>New-WebAppPool NewAppPool

    # Start Windows Services
    Start-Service -Name MyService
} catch {
    Write-Log ("Script failed. The error was: '{0}'." -f $_)
}

Откат - это не просто ... Единственное, что может быть легко откатить, - это операции реестра, поскольку реестр поддерживает транзакции (при условии, что Vista или более поздняя версия). Вы можете просто создать транзакцию (например, базу данных) и откатить ее в случае возникновения ошибки. Остальным операциям, которые вы упомянули, потребуется специальный код для их отката. Вы можете добавить код отката в блок catch следующим образом:

} catch {
    # Undo the registry transaction.
    # Unregister the DLL.
    # Delete the App pool if it exists.
    # Stop the windows service.
}
хм .. имеет смысл Angshuman Agarwal
@AngshumanAgarwal Шаблон, который я обычно использую, заключается в использовании try / catch в функциях модуля. Если в них что-то идет не так, я просто выкидываю сообщение с сообщением об исключении. Он будет перехвачен в блоке перехвата вызывающего абонента, и вы можете перебросить его к тому моменту, когда он окажется в главном, у вас будет возможность оценить псевдостекладку.
Использовал функцию Write-Log. Не думаете ли вы, что эту функцию следует изменить следующим образом - [Parameter ()] [Switch] $ NoConsoleOut = $ true, Angshuman Agarwal
Одно - у меня 35 разных вложенных модулей. И все модули загружаются через вызов Import-Module, а затем по очереди вызывается определенная функция, связанная с конкретной операцией. Итак, я все еще должен помещать try / catch внутри каждой функции в модуле, или я должен обернуть все последовательности вызова в один tr / catch ...? Angshuman Agarwal
@AngshumanAgarwal Одна из моих целей заключалась в том, чтобы одновременно регистрировать и отображать информацию, чтобы у пользователя был статус того, что происходит во время работы программы.

Похожие вопросы