적용 대상: ✔️ Windows VM
요약
이 문서에서는 사용자 지정 스크립트 확장 또는 명령 실행 기능을 사용하는 PowerShell 스크립트에서 오류를 테스트하고 수정하는 방법을 설명합니다.
중요합니다
새로운! VM 지원을 사용하여 주요 문제를 해결합니다. 우리는 Windows용 VM 지원 또는 Linux용 VM 지원을 실행할 것을 권장합니다. 이러한 스크립트 기반 진단 도구는 Azure VM 게스트 에이전트 및 전체 VM 상태에 영향을 주는 일반적인 문제를 식별하는 데 도움이 됩니다.
VM에서 성능 문제가 발생하는 경우 Microsoft 지원 문의하기 전에 먼저 이러한 도구를 실행합니다.
필수 조건
개요
사용자 지정 스크립트 확장 또는 명령 실행 기능을 사용하여 PowerShell 스크립트를 실행한다고 가정합니다. 스크립트가 실패하면 어떻게 해야 할까요? 오류의 원인을 확인하는 데 사용할 수 있는 몇 가지 방법이 있습니다.
PowerShell에는 둘 이상의 출력 스트림이 있습니다. 사용자 지정 스크립트 확장 및 명령 실행 스크립트에 대한 로그는 성공 스트림을 StdOut 하위 상태로 보내고 오류 스트림을 StdErr 하위 상태로 보냅니다. 이러한 하위 상태는 사용자 지정 스크립트 확장 스크립트 또는 명령 실행 스크립트를 실행하는 데 사용된 확장에 속합니다.
StdOut 및 StdErr 하위 상태는 VM(가상 머신)에 대한 CRP(인증서 등록 지점) 인스턴스 보기에 있습니다. 이러한 하위 통계는 다음 표에 따라 여러 위치에 표시됩니다.
| 인터페이스 | 하위 통계를 보는 방법 |
|---|---|
| Azure 포털 |
|
| Azure PowerShell | 다음과 같이 Get-AzVM cmdlet을 입력하여 Azure VM의 속성을 가져옵니다.Get-AzVM -ResourceGroupName <resource-group-name> -Name <vm-name> -Status |
| Azure CLI | 다음과 같이 az vm get-instance-view 명령을 입력하여 Azure VM에 대한 인스턴스 정보를 가져옵니다.az vm get-instance-view --resource-group <resource-group-name> --name <vm-name> --query instanceView.extensions |
일반적으로 스크립트를 실패하게 만드는 오류는 StdErr 하위 상태에서 나타납니다. 그러나 스크립트는 해당 하위 통계에서 치명적인 오류 항목을 로깅하지 않고도 실패할 수 있습니다.
PsExec를 사용하여 수동으로 스크립트 테스트
VM의 관리 PowerShell 콘솔에서 스크립트가 성공적으로 실행되는지 수동으로 확인합니다.
스크립트가 수동으로 작동하는 경우 PsExec를 사용하여 로컬 시스템 계정을 사용하여 스크립트를 실행합니다. 사용자 지정 스크립트 확장 및 실행 명령 모두에 대해 해당 계정을 사용하여 스크립트를 실행합니다. 입력 psexec -s하면 로컬 시스템 계정을 사용하지만 사용자 지정 스크립트 확장 또는 실행 명령을 사용하지 않고 스크립트를 테스트할 수 있습니다.
psexec -s을 사용하여 오류를 재현하는 경우, 사용자 지정 스크립트 확장 및 실행 명령 기능이 문제의 원인이 아닙니다.
PsExec를 사용하여 테스트
PsExec를 사용하여 PowerShell 테스트 스크립트를 원격으로 실행할 수 있습니다. 관리 명령 프롬프트 창을 열고 다음 PsExec 명령을 입력합니다. 자리 표시자를 PowerShell 스크립트의 정규화된 이름으로 바꿉합니다.
psexec -accepteula -nobanner -s powershell.exe -NoLogo -NoProfile -File <C:\path\script-name.ps1>
또는 PsExec를 대화형으로 사용할 수 있습니다. 예를 들어, 다음 예제에서는 PowerShell이 로컬 시스템 계정에서 실행되고 있음을 보여주기 위해 whoami 명령을 입력합니다.
C:\>psexec -accepteula -nobanner -s powershell.exe -NoLogo -NoProfile
PS C:\Windows\system32> whoami
nt authority\system
PowerShell 스크립트 실행 로깅 켜기
하위 통계가 StdErr 문제의 원인을 표시하지 않는 경우 여러 유형의 로깅을 켜서 스크립트 콘텐츠와 출력을 전체적으로 표시할 수 있습니다. 이 로깅은 스크립트가 수행하려는 작업과 스크립트 실행 결과를 보여 줍니다.
다양한 유형의 로깅을 켜려면 다음 몇 섹션의 단계를 수행합니다.
경고
일부 지침에는 Windows 레지스트리 변경이 포함됩니다. 레지스트리 편집기 또는 다른 방법을 사용하여 레지스트리를 잘못 수정하는 경우 심각한 문제가 발생할 수 있습니다. 이러한 문제를 해결하려면 운영 체제를 다시 설치해야 할 수 있습니다. Microsoft 이러한 문제를 해결할 수 있다고 보장할 수 없습니다. 먼저 기존 레지스트리 항목을 백업한 다음 사용자 고유의 위험으로 레지스트리를 수정합니다.
이벤트 로그의 최대 크기 늘리기
보안 로그와 Microsoft-Windows-PowerShell/Operational 이벤트 로그 모두에서 많은 수의 이벤트를 생성할 수 있습니다. 이러한 기록된 이벤트의 손실을 방지하려면 로그의 최대 크기를 늘입니다. 그러나 이러한 로그 중 하나가 최대 크기 100MB 이상( maxSize 값 104,857,600 이상)인 경우 최대 크기 설정을 그대로 둡니다.
로그의 최대 크기를 확인하려면 wevtutil 명령과 get-log 옵션을 사용하여 이벤트 로그에 대한 정보를 검색하십시오.
wevtutil get-log "Security"
wevtutil get-log "Microsoft-Windows-PowerShell/Operational"
다음 텍스트와 유사한 출력이 표시됩니다. 이러한 경우 최대 로그 크기는 100MB보다 훨씬 작습니다.
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
보안 로그 또는 Microsoft-Windows-PowerShell/Operational 이벤트 로그의 최대 크기를 100MB로 늘리려면 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
출력 이해하기
프로세스 생성 감사 시 이벤트 ID 4688 및 이벤트 ID 4689를 보안 이벤트 로그에 기록합니다. 이벤트 ID 4688은 프로세스를 만들기 위한 것이며 프로세스 명령줄을 포함합니다. 이벤트 ID 4689는 프로세스 종료를 위한 것입니다.
전사는 C:\Transcripts\<output-date> 디렉터리에 텍스트 파일을 만듭니다. 디렉터리가 아직 없는 경우 자동으로 만들어집니다.
예시:
C:\transcripts\20201211\PowerShell_transcript.<vm-name>.a+BWp8CT.20201211034929.txt
모듈 로깅은 이벤트 ID 4103을 Microsoft-Windows-PowerShell/Operational 이벤트 로그에 기록합니다. "4103" 이벤트에는 cmdlet 이름과 출력이 포함됩니다.
실행하는 Write-Host $Env:ComputerName경우 이벤트 ID 4013의 맨 위에 다음 텍스트가 표시됩니다. 여기서 value="<vm-name>" 명령의 출력이 VM의 이름임을 나타냅니다.
CommandInvocation(Write-Host): "Write-Host"
ParameterBinding(Write-Host): name="Object"; value="<vm-name>"
스크립트 블록 로깅은 이벤트 ID 4104를 Microsoft-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 >= '$startTimeUtc'
and
@SystemTime <= '$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 >= '$startTimeUtc'
and
@SystemTime <= '$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 스크립트 실행 로깅 해제
VM에서 PowerShell 스크립팅 로깅을 사용하도록 설정하기 위해 변경한 내용을 실행 취소하려면 다음 단계를 수행합니다.
이전에 보안 로그 또는 Microsoft-Windows-PowerShell/작동 로그의 최대 크기를 늘인 경우 해당 값을 기본 최대 크기로 되돌려 줍니다.
wevtutil set-log "Security" /ms:20971520 wevtutil set-log "Microsoft-Windows-PowerShell/Operational" /ms:15728640프로세스 생성 감사를 끄십시오.
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v "ProcessCreationIncludeCmdLine_Enabled" /t REG_DWORD /d 0 /f전사 기능 끄기:
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"모듈 로깅 끄기:
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 "*"스크립트 블록 로깅 끄기:
reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v "EnableScriptBlockLogging" /t REG_DWORD /d 0 /f기록 폴더를 제거합니다.
Remove-Item -Path 'C:\Transcripts' -Force -Recurse보안 로그 및 Microsoft-Windows-PowerShell/작동 로그를 백업하고 지웁
wevtutil clear-log Security /bu:Security.evtx wevtutil clear-log Microsoft-Windows-PowerShell/Operational /bu:Microsoft-Windows-PowerShell_Operational.evtx또는 백업하지 않고 보안 로그 및 Microsoft-Windows-PowerShell/운영 로그를 지웁합니다.
wevtutil clear-log Security wevtutil clear-log Microsoft-Windows-PowerShell/Operational
VM에서 실행 명령 로깅 테스트
Test-CustomScriptExtension.ps1 테스트 스크립트를 현재 로컬 디렉터리에 다운로드합니다. 그런 다음 Invoke-AzVMRunCommand cmdlet을 사용하여 VM에서 스크립트를 실행합니다. VM의 속성을 사용하여 리소스 그룹 이름 및 VM 이름의 자리 표시자를 바꿉니다.
$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
VM에서 사용자 지정 스크립트 확장 로깅 테스트
$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 cmdlet을 사용하여 VM에서 해당 테스트 스크립트를 실행할 수 있습니다. 필수적인 다른 여러 매개변수 변경 사항과 함께 ExtensionType 매개변수를 CustomScriptExtension 반드시 지정해야 합니다. VM의 속성을 사용하여 리소스 그룹 이름, VM 이름 및 위치에 대한 자리 표시자를 바꿉니다.
$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
사용자 지정 스크립트 확장 테스트 스크립트의 일반적인 오류
0이 아닌 종료 코드: Test-CustomScriptExtension.ps1 스크립트를 실행한 후 다음 오류 메시지가 표시됩니다.
장기 실행 작업이 '실패' 상태로 완료되지 못했습니다.
추가 정보: 확장 프로그램 'CustomScriptExtension'을 처리할 때 VM에서 오류를 보고했습니다.
오류 메시지: "명령 실행이 완료되었지만 0이 아닌 종료 코드 '2'를 반환했기 때문에 실패했습니다."테스트 스크립트는
Exit 2명령을 실행하며, 스크립트가 0이 아닌 종료 코드를 반환하는 경우 사용자 지정 스크립트 확장은 의도적으로 실패하도록 설계되었습니다. (이 예제에서 2는 0이 아닌 종료 코드입니다.) 이 예제에서는 사용하도록 설정한 추가 PowerShell 로깅에 오류가 표시되는 방법을 보여 줍니다.변경 사항이 충돌함: 이 오류는 VM에 리소스 이름 Microsoft.Compute.CustomScriptExtension이 이미 설치된 것으로 나타납니다. 하지만 현재 실행에서는 CustomScriptExtension이라는 다른 리소스 이름을 지정하고 있습니다.
VM 확장 'CustomScriptExtension'에 대한 handlerVersion 또는 autoUpgradeMinorVersion을 업데이트할 수 없습니다.
변경 사항이 'Microsoft.Compute.CustomScriptExtension' 처리기에서 typeHandler 버전 '1.10' 및 autoUpgradeMinorVersion 'True'와 함께 다른 확장과 충돌합니다.
오류코드: 작업이 허용되지 않음
ErrorMessage: VM 확장 'CustomScriptExtension'에 대한 handlerVersion 또는 autoUpgradeMinorVersion을 업데이트할 수 없습니다.
변경 내용이 처리기 'Microsoft.Compute.CustomScriptExtension'의 다른 확장과 충돌하고 있으며, typeHandler 버전 '1.10', autoUpgradeMinorVersion 'True'입니다.
ErrorTarget:
StatusCode: 409
사유구문: 충돌리소스 이름에 원하는 대로 지정할 수 있습니다. 그러나 사용자 지정 스크립트 확장이 이미 설치된 경우 다음 작업 중 하나를 수행해야 합니다.
- 후속 실행에 동일한 이름을 사용합니다.
- 먼저 다른 리소스 이름을 사용하기 전에 해당 확장 리소스를 제거합니다.
잘못된 파일 URI 구성: 이 오류는 사용자 지정 스크립트 확장이 원래 보호된 설정에 지정된 파일 URI와 함께 설치되었지만 지금은 공용 설정에서 지정되었음을 나타냅니다(또는 그 반대의 경우도 마찬가지임).
긴 시간 실행된 작업의 상태가 '실패'로 표시되어 실패했습니다.
추가 정보: 확장 프로그램 'CustomScriptExtension'을 처리할 때 VM에서 오류를 보고했습니다.
오류 메시지: "잘못된 구성 - FileUris가 보호된 구성 섹션과 공용 구성 섹션 모두에 있습니다. 단 한 섹션에만 지정해야 합니다."
사용자 지정 스크립트 확장 테스트 스크립트의 일반적인 오류에 대한 해결 방법
"변경 내용이 충돌 중" 오류를 해결하려면
Set-AzVMCustomScriptExtension또는Set-AzVMExtension을 다시 실행하되, 매개 변수를 이미 VM에 설치된 사용자 지정 스크립트 확장 리소스의 리소스 이름으로 설정하십시오-Name. 샘플 오류의 경우 확장을 제거할 때 `Microsoft.Compute.CustomScriptExtension`의 `-Name` 매개 변수를 지정합니다.-Name그러나 매개 변수는 VM에 이미 설치된 확장 리소스에 대한 리소스 이름이 무엇이든 되어야 합니다.사용할
-Name이름은 오류의 이 부분에 있는 리소스 이름입니다. "변경 내용이 처리기 'resource-name<'>의 다른 확장과 충돌합니다."VM 상태에서 가져오면 사용할 올바른 리소스 이름을 확인할 수도 있습니다. 다음과 같이 Get-AzVM cmdlet을 입력합니다.
$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 cmdlet을 입력하여 기존 사용자 지정 스크립트 확장을 제거할 수 있습니다.
$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
참조
- Azure Windows VM 확장 실패 문제 해결
- 스크립팅 추적 및 로깅
- Windows 운영 체제에서 알려진 보안 식별자
- Windows 로깅
- 감사 성공 프로세스 생성 이벤트
- Windows 구성 - 피해자 시스템 설정
타사 연락처 고지
Microsoft 이 항목에 대한 추가 정보를 찾는 데 도움이 되는 타사 연락처 정보를 제공합니다. 이 연락처 정보는 공지 없이 변경될 수 있습니다. Microsoft 타사 연락처 정보의 정확도를 보장하지 않습니다.