Déboguer des scripts PowerShell exécutés par extension de script personnalisé ou exécuter la commande

Applies to : ✔️ machines virtuelles Windows

Résumé

Cet article explique comment tester et corriger une défaillance dans un script PowerShell qui utilise la fonctionnalité Extension de script personnalisé ou Exécuter la commande.

Important

Nouveau! Essayez l’assistance de machine virtuelle pour résoudre les principaux problèmes. Nous vous recommandons d’exécuter Assistance VM pour Windows ou Assistance VM pour Linux. Ces outils de diagnostic basés sur des scripts vous aident à identifier les problèmes courants qui affectent l’agent invité de machine virtuelle Azure et l’intégrité globale de la machine virtuelle.

Si vous rencontrez des problèmes de performances sur des machines virtuelles, exécutez d'abord ces outils avant de contacter Support Microsoft.

Prerequisites

Aperçu

Supposons que vous avez utilisé l'extension de script personnalisé ou la fonction de commande d’exécution pour exécuter un script PowerShell. Que faites-vous si le script échoue ? Vous disposez de plusieurs méthodes disponibles pour déterminer la cause de l’échec.

PowerShell a plusieurs flux de sortie. Les journaux d’activité de l’extension de script personnalisé et d’exécution de scripts de commande envoient le flux de réussite au StdOut sous-état et au flux d’erreur vers le StdErr sous-état. Ces sous-statuts appartiennent à l'extension utilisée pour exécuter le script d'extension personnalisée ou le script de commande d'exécution.

Les StdOut et StdErr sous-statuts sont dans l'affichage d'instance du point d'enregistrement de certificat (CRP) pour la machine virtuelle. Ces sous-statuts sont visibles à plusieurs emplacements, comme indiqué dans le tableau suivant.

Interface Comment afficher le sous-état
portail Azure
  1. Recherchez et sélectionnez Machines virtuelles.
  2. Sélectionnez votre machine virtuelle dans la liste.
  3. Dans la page vue d’ensemble de la machine virtuelle, sélectionnez Extensions + Extensions d’applications>.
  4. Sélectionnez l’extension utilisée pour exécuter la commande. (Il sera nommé soit CustomScriptExtension ou RunCommand.)
  5. Sélectionnez Afficher l’état détaillé.
Azure PowerShell Entrez l’applet de commande Get-AzVM pour obtenir les propriétés d’une machine virtuelle Azure, comme suit :
Get-AzVM -ResourceGroupName <resource-group-name> -Name <vm-name> -Status
Azure CLI Entrez la commande az vm get-instance-view pour obtenir des informations d’instance sur une machine virtuelle Azure, comme suit :
az vm get-instance-view --resource-group <resource-group-name> --name <vm-name> --query instanceView.extensions

L’erreur qui provoque généralement l’échec du script s’affiche dans le StdErr sous-état. Toutefois, les scripts peuvent également échouer sans journaliser une entrée d'erreur fatale dans ce sous-statut.

Tester le script manuellement et à l’aide de PsExec

Vérifiez manuellement que le script s’exécute correctement à partir d’une console PowerShell d’administration sur la machine virtuelle.

Si le script fonctionne manuellement, utilisez PsExec pour exécuter le script à l’aide du compte système local. Pour l’extension de script personnalisé et la commande d’exécution, les scripts sont exécutés à l’aide de ce compte. En entrant psexec -s, vous pouvez tester le script à l’aide du compte système local, mais sans utiliser l’extension de script personnalisé ou exécuter la commande. Si l’échec est reproduit à l’aide de psexec -s, alors Extension de Script Personnalisé et Run Command ne sont pas la cause du problème.

Tester à l’aide de PsExec

Vous pouvez utiliser PsExec pour exécuter un script de test PowerShell à distance. Ouvrez une fenêtre d’invite de commandes d’administration, puis entrez la commande PsExec suivante. Remplacez l’espace réservé par le nom complet du script PowerShell :

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

Vous pouvez également utiliser PsExec de manière interactive. Dans l’exemple suivant, vous entrez la commande Whoami pour montrer que PowerShell s’exécute sous le compte système local (NT AUTHORITY\SYSTEM) :

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

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

Activer la journalisation de l’exécution du script PowerShell

Si le StdErr sous-état n’affiche pas la cause du problème, vous pouvez activer plusieurs types de journalisation pour afficher collectivement le contenu et la sortie du script. Cette journalisation montre ce que le script tente d’accomplir et le résultat de l’exécution du script.

Pour activer différents types de journalisation, suivez les étapes décrites dans les sections suivantes.

Avertissement

Certaines instructions impliquent la modification du registre Windows. De graves problèmes peuvent se produire si vous vous trompez en modifiant le Registre à l’aide de l’Éditeur du Registre ou toute autre méthode. Vous risquez même de devoir réinstaller le système d’exploitation. Microsoft ne peut pas garantir que ces problèmes peuvent être résolus. Sauvegardez d’abord vos entrées de Registre existantes, puis modifiez le Registre à votre propre risque.

Augmenter la taille maximale des journaux des événements

Un grand nombre d’événements peuvent être générés dans le journal de sécurité et dans le journal des événements Microsoft-Windows-PowerShell/Operational. Pour éviter la perte de ces événements journalisés, augmentez la taille maximale des journaux. Toutefois, si l’un de ces journaux est de taille maximale de 100 Mo ou supérieur (valeur maxSize de 104 857 600 ou plus), conservez le paramètre de taille maximale tel qu’il en est.

Pour vérifier la taille maximale du journal, utilisez la commande wevtutil et l’option get-log permettant de récupérer des informations sur les journaux d’événements :

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

Vous verrez une sortie semblable au texte suivant. Dans ces cas, la taille maximale du journal est beaucoup inférieure à 100 Mo.

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

Pour augmenter la taille maximale du journal de sécurité ou du journal des événements Microsoft-Windows-PowerShell/Operational à 100 Mo, exécutez wevtutil avec l’option set-log :

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

Activer l’audit de création de processus

Utilisez la commande suivante pour activer l’audit de création de processus :

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

Activer la transcription 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

Activer la journalisation des modules 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 *

Activer la journalisation des blocs de script PowerShell

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

Comprendre le résultat

L’audit de la création du processus écrit l’ID d’événement 4688 et l’ID d’événement 4689 dans le journal des événements de sécurité. L’ID d’événement 4688 est destiné à la création du processus et inclut la ligne de commande processus. L’ID d’événement 4689 est destiné à l’arrêt du processus.

La transcription crée un fichier texte dans le répertoire C :\Transcripts\<output-date> . Le répertoire est créé automatiquement s’il n’existe pas déjà.

Par exemple :

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

La journalisation des modules journalisera l’ID d’événement 4103 dans le journal des événements Microsoft-Windows-PowerShell/Operational. L’événement « 4103 » inclut le nom et la sortie de l’applet de commande.

Si vous exécutez Write-Host $Env:ComputerName, la partie supérieure de l’ID d’événement 4013 affiche le texte suivant, où value="<vm-name>" indique que la sortie de la commande était le nom de votre machine virtuelle :

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

La journalisation des blocs de script journalisera l’ID d’événement 4104 dans le journal des événements Microsoft-Windows-PowerShell/Operational. Les événements « 4104 » contiennent le contenu du script. Les scripts qui dépassent la taille maximale de message d’un événement sont enregistrés sous la forme de plusieurs événements « 4104 ».

Une fois que vous avez activé la journalisation et reproduit l’échec du script, exécutez le script suivant pour exporter les événements pertinents vers un fichier csv (valeur séparée par des virgules). La requête suivante examine les 24 heures précédentes (86 400 000 millisecondes) de données. Entrez la valeur 36000000 pour récupérer uniquement l’heure la plus récente. La valeur 6048000000 récupère la semaine la plus récente.

$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

Désactiver la journalisation de l’exécution du script PowerShell

Pour annuler les modifications que vous avez apportées pour activer la journalisation des scripts PowerShell sur votre machine virtuelle, procédez comme suit :

  1. Si vous avez précédemment augmenté la taille maximale du journal de sécurité ou du journal Microsoft-Windows-PowerShell/Operational, rétablissez ces valeurs aux tailles maximales par défaut :

    wevtutil set-log "Security" /ms:20971520
    wevtutil set-log "Microsoft-Windows-PowerShell/Operational" /ms:15728640
    
  2. Désactivez l’audit de création de processus :

    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v "ProcessCreationIncludeCmdLine_Enabled" /t REG_DWORD /d 0 /f
    
  3. Désactiver la transcription :

    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. Désactivez la journalisation des modules :

    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. Désactivez la journalisation des blocs de script :

    reg add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v "EnableScriptBlockLogging" /t REG_DWORD /d 0 /f
    
  6. Supprimez le dossier de transcription :

    Remove-Item -Path 'C:\Transcripts' -Force -Recurse
    
  7. Sauvegardez et effacez le journal de sécurité et le journal Microsoft-Windows-PowerShell/Opérationnel :

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

    Ou effacez le journal de sécurité et le journal Microsoft-Windows-PowerShell/Operational sans les sauvegarder :

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

Journalisation des commandes d’exécution de test sur votre machine virtuelle

Téléchargez le script de test Test-CustomScriptExtension.ps1 dans le répertoire local actuel. Exécutez ensuite le script sur votre machine virtuelle à l’aide de l’applet de commande Invoke-AzVMRunCommand . Utilisez les propriétés de votre machine virtuelle pour remplacer les espaces réservés pour le nom du groupe de ressources et le nom de la machine virtuelle.

$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

Testez la journalisation de l'extension de script personnalisé sur votre machine virtuelle.

Exécutez le script de test Test-CustomScriptExtension.ps1 sur votre machine virtuelle à l’aide de l’applet de commande Set-AzVMCustomScriptExtension. Utilisez les propriétés de votre machine virtuelle pour remplacer les espaces réservés pour le nom du groupe de ressources, le nom de la machine virtuelle et l’emplacement.

$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

Vous pouvez également exécuter ce script de test sur votre machine virtuelle à l’aide de l’applet de commande Set-AzVMExtension . Vous devez spécifier un paramètre ExtensionType de CustomScriptExtension, ainsi que plusieurs autres modifications de paramètres. Utilisez les propriétés de votre machine virtuelle pour remplacer les espaces réservés pour le nom du groupe de ressources, le nom de la machine virtuelle et l’emplacement.

$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

Erreurs courantes dans le script de test d’extension de script personnalisé

  • Code de sortie différent de zéro : après avoir exécuté le script Test-CustomScriptExtension.ps1 , attendez-vous à recevoir le message d’erreur suivant :

    Échec de l’opération de longue durée avec l’état « Échoué ».
    Informations supplémentaires : la machine virtuelle a signalé un échec lors du traitement de l’extension « CustomScriptExtension ».
    Message d’erreur : « L’exécution de la commande a terminé, mais a échoué, car elle a retourné un code de sortie différent de zéro de : « 2 »

    Le script de test exécute la Exit 2 commande et l’extension de script personnalisé est censée échouer par conception si le script retourne un code de sortie différent de zéro. (Dans cet exemple, 2 est le code de sortie différent de zéro.) Cet exemple montre comment un échec s’affiche dans la journalisation PowerShell supplémentaire que vous avez activée.

  • Le changement est en conflit : cette erreur indique que l’extension de script personnalisé est déjà installée en tant que nom de ressource Microsoft.Compute.CustomScriptExtension, mais vous spécifiez un nom de ressource différent de CustomScriptExtension pour l'exécution actuelle :

    Impossible de mettre à jour handlerVersion ou autoUpgradeMinorVersion pour l’extension de machine virtuelle « CustomScriptExtension ».
    La modification est en conflit avec d'autres extensions sous le gestionnaire ' Microsoft. Compute.CustomScriptExtension », avec typeHandler version « 1.10 » et autoUpgradeMinorVersion « True ».
    CodeErreur : OpérationNonAutorisée
    ErrorMessage : Impossible de mettre à jour handlerVersion ou autoUpgradeMinorVersion pour l’extension de machine virtuelle « CustomScriptExtension ».
    La modification est en conflit avec d'autres extensions sous le gestionnaire ' Microsoft. Compute.CustomScriptExtension », avec typeHandler version « 1.10 » et autoUpgradeMinorVersion « True ».
    ErrorTarget :
    StatusCode : 409
    ReasonPhrase : Conflit

    Vous pouvez spécifier ce que vous souhaitez pour le nom de la ressource. Toutefois, si l’extension de script personnalisé est déjà installée, vous devez effectuer l’une des actions suivantes :

    • Utilisez le même nom pour les exécutions suivantes.
    • Commencez par supprimer cette ressource d’extension avant d’utiliser un autre nom de ressource.
  • Configuration d’URI de fichier non valide : cette erreur indique que l’extension de script personnalisé a été installée à l’origine avec les URI de fichier spécifiés dans les paramètres protégés, mais sont désormais spécifiés dans les paramètres publics (ou vice versa) :

    Échec de l’opération de longue durée avec l’état « Failed ».
    Informations supplémentaires : la machine virtuelle a signalé un échec lors du traitement de l’extension « CustomScriptExtension ».
    Message d’erreur : « Configuration non valide - FileUris est présent dans les sections de configuration protégée et publique ; elle doit être spécifiée dans une seule section.

Solutions aux erreurs courantes dans le script de test de l'Extension de Script Personnalisé

  • Pour corriger l’erreur « Modification en conflit », essayez de réexécuter Set-AzVMCustomScriptExtension ou Set-AzVMExtension, mais définissez le paramètre -Name sur le nom de la ressource d'Extension de script personnalisé déjà présente sur la machine virtuelle. Pour l’exemple d’erreur, lorsque vous supprimez l’extension, spécifiez un paramètre -Name de Microsoft. Compute.CustomScriptExtension. Toutefois, le -Name paramètre doit être le nom de la ressource d’extension déjà installée sur la machine virtuelle.

    Le nom à utiliser -Name sera le nom de la ressource dans cette partie de l’erreur : « La modification est en conflit avec d’autres extensions sous le gestionnaire «< nom-ressource> ».

    Vous pouvez également vérifier le nom de ressource approprié à utiliser en l’obtenant à partir de l’état de la machine virtuelle. Entrez l’applet de commande Get-AzVM , comme suit :

    $status = Get-AzVM -ResourceGroupName <resource-group> -Name <vm-name> -Status
    $status.Extensions |
    Where-Object Type -EQ 'Microsoft.Compute.CustomScriptExtension' |
    Select-Object Name
    
  • Pour atténuer l’erreur « Modification en conflit » et l’erreur « FileUris », vous pouvez supprimer l’extension de script personnalisé existante en entrant l’applet de commande Remove-AzVMCustomScriptExtension :

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

    Si vous spécifiez le nom de ressource incorrect, la valeur retournée StatusCode est NoContent:

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

    Si vous spécifiez le nom de ressource approprié, la valeur retournée StatusCode est OK:

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

Références

Exclusion de responsabilité sur les coordonnées externes

Microsoft fournit des informations de contact tierces pour vous aider à trouver des informations supplémentaires sur cette rubrique. Ces informations de contact peuvent changer sans préavis. Microsoft ne garantit pas l’exactitude des informations de contact tierces.