Отладка сценариев PowerShell, выполняемых с помощью расширения пользовательского скрипта или команды run

Применимо к виртуальным машинам ✔️ Windows

Сводка

В этой статье описывается, как проверить и исправить сбой в скрипте PowerShell, использующего расширение пользовательского скрипта или функцию запуска команды.

Это важно

Новое! Попробуйте использовать инструмент VM Assist для решения наиболее часто встречающихся проблем. Мы рекомендуем запустить Помощник VM для Windows или Помощник VM для Linux. Эти средства диагностики на основе скриптов помогают выявить распространенные проблемы, влияющие на Azure гостевого агента виртуальной машины и общую работоспособность виртуальных машин.

Если у вас возникли проблемы с производительностью на виртуальных машинах, запустите эти средства перед обращением к служба поддержки Майкрософт.

Предварительные требования

Обзор

Предположим, что вы использовали расширение пользовательского скрипта или функцию запуска команды для запуска скрипта PowerShell. Что делать, если скрипт завершается сбоем? Существует несколько доступных методов для определения причины сбоя.

PowerShell имеет несколько выходных потоков. Журналы для расширения пользовательских скриптов и скриптов запуска команд отправляют поток Success в StdOut подстатус, а поток Error в StdErr подстатус. Эти подстатусы относятся к расширению, использованному для запуска скрипта расширения Custom Script или скрипта Run Command.

Подстатусы StdOut и StdErr находятся в представлении экземпляра точки регистрации сертификатов (CRP) для виртуальной машины. Эти подстатусы отображаются в нескольких местах, как показано в следующей таблице.

Интерфейс Как просмотреть подстатус
портал Azure
  1. Найдите и выберите Виртуальные машины.
  2. Выберите нужную виртуальную машину из списка.
  3. На странице обзора виртуальной машины выберите Расширения + приложения>Расширения.
  4. Выберите расширение, которое использовалось для выполнения команды. (Оно будет называться либо CustomScriptExtension или RunCommand.)
  5. Выберите "Просмотреть подробное состояние".
Azure PowerShell Введите командлет Get-AzVM, чтобы получить свойства виртуальной машины Azure следующим образом:
Get-AzVM -ResourceGroupName <resource-group-name> -Name <vm-name> -Status
Azure CLI Введите команду az vm get-instance-view, чтобы получить сведения об экземпляре виртуальной машины Azure следующим образом:
az vm get-instance-view --resource-group <resource-group-name> --name <vm-name> --query instanceView.extensions

Ошибка, которая обычно вызывает сбой скрипта, отображается в подстатусе StdErr. Однако скрипты также могут завершиться ошибкой без записи фатальной ошибки в журнал в этом подстатусе.

Тестирование скрипта вручную и с помощью PsExec

Вручную убедитесь, что скрипт успешно выполняется из административной консоли PowerShell на виртуальной машине.

Если скрипт работает вручную, используйте PsExec для запуска скрипта с помощью локальной системной учетной записи. Для расширения пользовательских скриптов и команды выполнения, скрипты запускаются с помощью этой учетной записи. Введя psexec -s, вы можете протестировать скрипт, используя локальную системную учетную запись, но без использования расширения пользовательского скрипта или команды Run Command. Если сбой воспроизводится с помощью psexec -s, расширение пользовательского скрипта и команда запуска не являются причиной проблемы.

Тестирование с помощью PsExec

Вы можете использовать PsExec для удаленного запуска тестового скрипта PowerShell. Откройте окно командной строки администратора и введите следующую команду PsExec. Замените заполнитель полностью квалифицированным именем скрипта PowerShell.

psexec -accepteula -nobanner -s powershell.exe -NoLogo -NoProfile -File <C:\path\script-name.ps1>

Кроме того, вы можете использовать PsExec в интерактивном режиме. В следующем примере введите команду whoami , чтобы показать, что PowerShell выполняется в учетной записи локальной системы (NT AUTHORITY\SYSTEM).

C:\>psexec -accepteula -nobanner -s powershell.exe -NoLogo -NoProfile

PS C:\Windows\system32> whoami
nt authority\system 

Включение ведения журнала выполнения скрипта PowerShell

StdErr Если подстатус не отображает причину проблемы, можно включить несколько типов ведения журнала, чтобы коллективно отобразить содержимое и выходные данные скрипта. Данный лог показывает, что скрипт пытается осуществить, и результат выполнения скрипта.

Чтобы включить различные типы ведения журнала, выполните действия, описанные в следующих нескольких разделах.

Предупреждение

Некоторые инструкции включают изменение реестра Windows. При неправильном изменении реестра с использованием редактора реестра или другого способа могут случиться серьезные проблемы. Для решения этих проблем может потребоваться переустановка операционной системы. Майкрософт не может гарантировать, что эти проблемы можно решить. Сначала создайте резервную копию существующих записей реестра, а затем измените реестр с собственным риском.

Увеличьте максимальный размер журналов событий

Большое количество событий можно создать как в журнале безопасности, так и в журнале событий Майкрософт-Windows-PowerShell/Operations. Чтобы предотвратить потерю этих зарегистрированных событий, увеличьте максимальный размер журналов. Но если любой из этих журналов имеет максимальный размер 100 МБ или больше ( maxSize значение 104 857 600 или более), оставьте максимальный размер как есть.

Чтобы проверить максимальный размер журнала, используйте команду wevtutil и get-log параметр для получения сведений о журналах событий:

wevtutil get-log "Security"
wevtutil get-log "Microsoft-Windows-PowerShell/Operational"

Вы увидите выходные данные, похожие на следующий текст. В таких случаях максимальный размер журнала гораздо меньше 100 МБ.

name: Security
enabled: true
type: Admin
owningPublisher:
isolation: Custom
channelAccess: O:BAG:SYD:(A;;CCLCSDRCWDWO;;;SY)(A;;CCLC;;;BA)(A;;CC;;;ER)(A;;CC;;;NS)
logging:
  logFileName: %SystemRoot%\System32\Winevt\Logs\Security.evtx
  retention: false
  autoBackup: false
  maxSize: 20971520
publishing:
  fileMax: 1
name: Microsoft-Windows-PowerShell/Operational
enabled: true
type: Operational
owningPublisher: Microsoft-Windows-PowerShell
isolation: Application
channelAccess: O:BAG:SYD:(A;;0x2;;;S-1-15-2-1)(A;;0x2;;;S-1-15-3-1024-3153509613-960666767-3724611135-2725662640-12138253-543910227-1950414635-4190290187)(A;;0xf0007;;;SY)(A;;0x7;;;BA)(A;;0x7;;;SO)(A;;0x3;;;IU)(A;;0x3;;;SU)(A;;0x3;;;S-1-5-3)(A;;0x3;;;S-1-5-33)(A;;0x1;;;S-1-5-32-573)
logging:
  logFileName: %SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtx
  retention: false
  autoBackup: false
  maxSize: 15728640
publishing:
  fileMax: 1

Чтобы увеличить максимальный размер журнала безопасности или журнала событий Майкрософт-Windows-PowerShell/Operations, до 100 МБ, выполните wevtutil вместе с параметром set-log:

wevtutil set-log "Security" /ms:104857600
wevtutil set-log "Microsoft-Windows-PowerShell/Operational" /ms:104857600

Включите аудит создания процесса

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

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v "ProcessCreationIncludeCmdLine_Enabled" /t REG_DWORD /d 1 /f

Включите транскрибирование в PowerShell

reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\Transcription" /v "EnableTranscripting" /t REG_DWORD /d 1 /f
reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\Transcription" /v "EnableInvocationHeader" /t REG_DWORD /d 1 /f
reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\Transcription" /v "OutputDirectory" /t REG_SZ /d C:\Transcripts /f

Включение ведения журнала модулей PowerShell

reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging" /v "EnableModuleLogging" /t REG_DWORD /d 1 /f
reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames" /v "*" /t REG_SZ /d *

Включение ведения журнала блоков скриптов PowerShell

reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v "EnableScriptBlockLogging" /t REG_DWORD /d 1 /f

Понять выходные данные

Аудит создания процесса записывает идентификатор события 4688 и идентификатор события 4689 в журнал событий безопасности. Идентификатор события 4688 предназначен для создания процесса и включает командную строку процесса. Идентификатор события 4689 предназначен для завершения процесса.

Транскрибирование создает текстовый файл в каталоге C:\Transcripts\<output-date> . Каталог будет создан автоматически, если он еще не существует.

Например:

C:\transcripts\20201211\PowerShell_transcript.<vm-name>.a+BWp8CT.20201211034929.txt

Ведение журнала модулей регистрирует идентификатор события 4103 в журнал событий Майкрософт-Windows-PowerShell/Operations. Событие "4103" включает имя и выходные данные командлета.

При выполнении Write-Host $Env:ComputerName в верхней части идентификатора события 4013 отображается следующий текст, причём value="<vm-name>" показывает, что выходные данные команды были именем вашей виртуальной машины.

CommandInvocation(Write-Host): "Write-Host"
ParameterBinding(Write-Host): name="Object"; value="<vm-name>"

Ведение журнала блоков скрипта регистрирует идентификатор события 4104 в журнал событий Майкрософт-Windows-PowerShell/Operational. События "4104" содержат содержимое скрипта. Скрипты, превышающие максимальный размер сообщения события, регистрируются как несколько событий "4104".

После включения ведения журнала и воспроизведения сбоя скрипта выполните следующий скрипт, чтобы экспортировать соответствующие события в CSV-файл с разделием запятыми. Следующий запрос проверяет данные за предыдущие 24 часа (86 400 000 миллисекунд). Введите значение 3600000, чтобы получить только последний час. Значение 604800000 будет извлекать самую последнюю неделю.

$path = "PSEvents_$($env:COMPUTERNAME)_$(Get-Date ((Get-Date).ToUniversalTime()) -Format yyyyMMddHHmmss).csv"

$hours = 1 # Increase this to have it query more than just the last 1 hour
$now = Get-Date
$startTimeUtc = Get-Date ($now.AddHours(-$hours).ToUniversalTime()) -Format 'yyyy-MM-ddTHH:mm:ssZ'
$endTimeUtc = Get-Date ($now.ToUniversalTime()) -Format 'yyyy-MM-ddTHH:mm:ssZ'

$filterXML = @"
<QueryList>
    <Query Id="0" Path="Security">
        <Select Path="Security">
            Event
            [
                System
                [
                    (EventID = '4688' or EventID = '4689')
                    and
                    TimeCreated
                    [
                        @SystemTime &gt;= '$startTimeUtc'
                        and
                        @SystemTime &lt;= '$endTimeUtc'
                    ]
                ]
                and
                EventData
                [
                    Data[@Name="SubjectUserSid"] = "S-1-5-18"
                ]
            ]
        </Select>
    </Query>
    <Query Id="1" Path="Microsoft-Windows-PowerShell/Operational">
        <Select Path="Microsoft-Windows-PowerShell/Operational">
            Event
            [
                System
                [
                    (EventID ='4103' or EventID ='4104')
                    and
                    Security
                    [
                        @UserID ='S-1-5-18'
                    ]
                    and
                    TimeCreated
                    [
                        @SystemTime &gt;= '$startTimeUtc'
                        and
                        @SystemTime &lt;= '$endTimeUtc'
                    ]
                ]
            ]
        </Select>
    </Query>
</QueryList>
"@

$events = Get-WinEvent -FilterXml $filterXML | Sort-Object -Property RecordId
$events = $events | Select-Object -Property RecordId,
    TimeCreated, Id, MachineName, LogName, TaskDisplayName, Message
$events | Export-Csv -Path $path -NoTypeInformation

Отключение ведения журнала выполнения скрипта PowerShell

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

  1. Если вы ранее увеличили максимальный размер журнала безопасности или журнала Майкрософт-Windows-PowerShell/Operations, отверните эти значения до максимального размера по умолчанию:

    wevtutil set-log "Security" /ms:20971520
    wevtutil set-log "Microsoft-Windows-PowerShell/Operational" /ms:15728640
    
  2. Выключить аудит создания процессов:

    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v "ProcessCreationIncludeCmdLine_Enabled" /t REG_DWORD /d 0 /f
    
  3. Отключите транскрибирование:

    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" /v "EnableTranscripting" /t REG_DWORD /d 0 /f
    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" /v "EnableInvocationHeader" /t REG_DWORD /d 0 /f
    reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" /v "OutputDirectory"
    
  4. Отключение ведения журнала модулей:

    reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging" /v "EnableModuleLogging" /t REG_DWORD /d 0 /f
    reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames" /v "*"
    
  5. Отключение ведения журнала блоков скриптов:

    reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v "EnableScriptBlockLogging" /t REG_DWORD /d 0 /f
    
  6. Удалите папку транскрибирования:

    Remove-Item -Path 'C:\Transcripts' -Force -Recurse
    
  7. Создайте резервную копию и очистите журнал безопасности, а также журнал Майкрософт-Windows-PowerShell/Оперативный.

    wevtutil clear-log Security /bu:Security.evtx
    wevtutil clear-log Microsoft-Windows-PowerShell/Operational /bu:Microsoft-Windows-PowerShell_Operational.evtx
    

    Или снимите журнал безопасности и журнал Майкрософт-Windows-PowerShell/Operations без их резервного копирования:

    wevtutil clear-log Security
    wevtutil clear-log Microsoft-Windows-PowerShell/Operational
    

Тестирование ведения журнала команд запуска на виртуальной машине

Скачайте скрипт теста Test-CustomScriptExtension.ps1 в текущий локальный каталог. Затем запустите сценарий на виртуальной машине с помощью командлета Invoke-AzVMRunCommand . Используйте свойства виртуальной машины, чтобы заменить заполнители для имени группы ресурсов и имени виртуальной машины.

$scriptUri = 'https://raw.githubusercontent.com/Azure/azure-support-scripts/blob/users/GitHubPolicyService/6294a303-e34d-4bad-b6cd-5ed54245f020/Images_Extensions/PowerShell/Test-CustomScriptExtension.ps1'
$localFileLocation = "$PWD\Test-CustomScriptExtension.ps1"
(New-Object System.Net.WebClient).DownloadFile($scriptUri, $localFileLocation)

$commandSettings = @{
    ResourceGroupName = '<resource-group-name>'
    VMName = '<vm-name>'
    CommandId = 'RunPowerShellScript'
    ScriptPath = $localFileLocation
}
Invoke-AzVMRunCommand @commandSettings

Проверка ведения логов расширения для пользовательских скриптов на виртуальной машине

Запустите тестовый скрипт Test-CustomScriptExtension.ps1 на виртуальной машине с помощью командлета Set-AzVMCustomScriptExtension. Используйте свойства виртуальной машины для замены заполнителей для имени группы ресурсов, имени виртуальной машины и расположения.

$commandSettings = @{
    ResourceGroupName = '<resource-group-name>'
    VMName = '<vm-name>'
    Name = 'CustomScriptExtension'
    FileUri = 'https://raw.githubusercontent.com/Azure/azure-support-scripts/blob/users/GitHubPolicyService/6294a303-e34d-4bad-b6cd-5ed54245f020/Images_Extensions/PowerShell/Test-CustomScriptExtension.ps1'
    Run = 'Test-CustomScriptExtension.ps1'
    Location = '<azure-region-name-or-code>'
    ForceRerun = (Get-Date).Ticks
}
Set-AzVMCustomScriptExtension @commandSettings

Кроме того, можно запустить этот тестовый скрипт на виртуальной машине с помощью командлета Set-AzVMExtension . Необходимо указать параметр ExtensionTypeCustomScriptExtension наряду с несколькими другими изменениями параметров. Используйте свойства виртуальной машины для замены заполнителей для имени группы ресурсов, имени виртуальной машины и расположения.

$publicConfigSettings = @{
    'fileUris' = @('https://raw.githubusercontent.com/Azure/azure-support-scripts/blob/users/GitHubPolicyService/6294a303-e34d-4bad-b6cd-5ed54245f020/Images_Extensions/PowerShell/Test-CustomScriptExtension.ps1')
    'commandToExecute' = 'powershell -File Test-CustomScriptExtension.ps1 -ExecutionPolicy Unrestricted'
}
$commandSettings = @{
    Publisher = 'Microsoft.Compute'
    ExtensionType = 'CustomScriptExtension'
    Settings = $publicConfigSettings
    ResourceGroupName = '<resource-group-name>'
    VMName = '<vm-name>'
    Name = 'CustomScriptExtension'
    TypeHandlerVersion = '1.10'
    Location = '<azure-region-name-or-code>'
}
Set-AzVMExtension @commandSettings

Распространенные ошибки в тестовом скрипте расширения сценариев настраиваемого скрипта

  • Ненулевой код выхода: После запуска скрипта Test-CustomScriptExtension.ps1 ожидается следующее сообщение об ошибке:

    Операция длительного выполнения завершилась со статусом "Сбой".
    Дополнительные сведения: виртуальная машина сообщила о сбое при обработке расширения CustomScriptExtension.
    Сообщение об ошибке: "Выполнение команды завершено, но завершилось сбоем, так как он вернул ненулевой код выхода: "2"

    Тестовый скрипт выполняет Exit 2 команду, и расширение пользовательского скрипта, как ожидается, завершится ошибкой, если скрипт возвращает ненулевой код выхода. (В этом примере 2 — ненулевой код выхода.) В этом примере показано, как отображается сбой в дополнительном ведении журнала PowerShell, которое вы включили.

  • Изменение находится в конфликте. Эта ошибка указывает, что на виртуальной машине уже установлено расширение пользовательского скрипта с именем ресурса Майкрософт.Compute.CustomScriptExtension, но вы указываете другое имя ресурса CustomScriptExtension для текущего выполнения.

    Не удается обновить handlerVersion или autoUpgradeMinorVersion для расширения виртуальной машины 'CustomScriptExtension'.
    Изменение конфликтует с другими расширениями под обработчиком 'Майкрософт.Compute.CustomScriptExtension' с версией typeHandler '1.10' и autoUpgradeMinorVersion 'True'.
    Код ошибки: Операция запрещена
    ErrorMessage: не удается обновить handlerVersion или autoUpgradeMinorVersion для расширения виртуальной машины 'CustomScriptExtension'.
    Изменение конфликтует с другими расширениями в обработчике 'Майкрософт.Compute.CustomScriptExtension' с версией typeHandler '1.10' и autoUpgradeMinorVersion 'True'.
    ErrorTarget:
    StatusCode: 409
    ReasonPhrase: Конфликт

    Можно указать любое имя ресурса. Однако если у вас уже установлено расширение пользовательского скрипта, необходимо выполнить одно из следующих действий:

    • Используйте то же имя для последующих запусков.
    • Сначала удалите этот ресурс расширения перед использованием другого имени ресурса.
  • Некорректная конфигурация URI файла: эта ошибка означает, что расширение пользовательского скрипта изначально было установлено с файлами URI, которые были указаны в защищенных параметрах, но теперь они указаны в общедоступных параметрах (или наоборот):

    Операция длительного выполнения завершилась со статусом "Сбой".
    Дополнительные сведения: виртуальная машина сообщила о сбое при обработке расширения CustomScriptExtension.
    Сообщение об ошибке: "Недопустимая конфигурация — FileUris присутствует как в защищенных, так и в общедоступных разделах конфигурации; он должен быть указан только в одном разделе".

Решения распространенных ошибок в скрипте тестирования расширения пользовательского скрипта

  • Чтобы устранить ошибку "Изменение в конфликте", попробуйте повторно выполнить Set-AzVMCustomScriptExtension или Set-AzVMExtension, но задайте параметр -Name как имя ресурса расширения пользовательского скрипта, который уже установлен на виртуальной машине. Для примера ошибки при удалении расширения укажите параметр -NameМайкрософт. Compute.CustomScriptExtension. Параметр -Name должен точно совпадать с именем ресурса расширения, который уже установлен на виртуальной машине.

    Имя, используемое для -Name, будет ресурсным именем в этой части ошибки: "Изменение конфликтует с другими расширениями в обработчике '<resource-name>'."

    Вы также можете проверить правильное имя ресурса, используемое, получив его из состояния виртуальной машины. Введите командлет Get-AzVM следующим образом:

    $status = Get-AzVM -ResourceGroupName <resource-group> -Name <vm-name> -Status
    $status.Extensions |
    Where-Object Type -EQ 'Microsoft.Compute.CustomScriptExtension' |
    Select-Object Name
    
  • Чтобы устранить ошибку "Изменение в конфликте" и ошибку "FileUris", можно удалить расширение пользовательского скрипта, введя командлет Remove-AzVMCustomScriptExtension:

    $params = @{
        ResourceGroupName = '<resourceGroupName>'
        VMName = '<vm-name>'
        Name = '<extension-resource-name>'
        Force = $True
    }
    Remove-AzVMCustomScriptExtension @params
    

    Если указать неверное имя ресурса, возвращаемое StatusCode значение равно NoContent:

    RequestId IsSuccessStatusCode StatusCode ReasonPhrase
    --------- ------------------- ---------- ------------
                             True  NoContent No Content
    

    Если указать правильное имя ресурса, возвращаемое StatusCode значение равно OK:

    RequestId IsSuccessStatusCode StatusCode ReasonPhrase
    --------- ------------------- ---------- ------------
                             True         OK OK
    

Ссылки

Заявление об отказе от ответственности за контактные данные сторонней организации

Майкрософт предоставляет сторонние контактные данные, которые помогут вам найти дополнительные сведения об этом разделе. Эти данные могут быть изменены без предварительного уведомления. Майкрософт не гарантирует точность сторонних контактных данных.