

• Das AWS Systems Manager CloudWatch Dashboard wird nach dem 30. April 2026 nicht mehr verfügbar sein. Kunden können weiterhin die CloudWatch Amazon-Konsole verwenden, um ihre CloudWatch Amazon-Dashboards anzusehen, zu erstellen und zu verwalten, so wie sie es heute tun. Weitere Informationen finden Sie in der [Amazon CloudWatch Dashboard-Dokumentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Dashboards.html). 

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Erstellen von Automation-Runbooks
<a name="automation-authoring-runbooks"></a>

Jedes Runbook in Automation, ein Tool in AWS Systems Manager, definiert eine Automatisierung. Automatisierungs-Runbooks definieren die Aktionen, die während einer Automatisierung ausgeführt werden. Im Runbook-Inhalt definieren Sie die Eingabeparameter, Ausgaben und Aktionen, die Systems Manager für Ihre verwalteten Instanzen und AWS Ressourcen ausführt. 

Automatisierung umfasst mehrere vordefinierte Runbooks, die Sie verwenden können, um allgemeine Aufgaben wie das Neustarten einer oder mehrerer Amazon Elastic Compute Cloud (Amazon EC2)-Instances oder das Erstellen eines Amazon Machine Image (AMI) auszuführen. Ihre Anwendungsfälle können jedoch über die Funktionen der vordefinierten Runbooks hinausgehen. In diesem Fall können Sie eigene Runbooks erstellen und an Ihre Bedürfnisse anpassen.

Ein Runbook besteht aus Automatisierungsaktionen, Parametern für diese Aktionen und Eingabeparametern, die Sie angeben. Der Inhalt eines Runbooks wird entweder in YAML oder JSON geschrieben. Wenn Sie mit YAML oder JSON nicht vertraut sind, empfehlen wir die Verwendung des visuellen Designers oder das Erlernen mehr über eine der Auszeichnungssprachen, bevor Sie versuchen, Ihr eigenes Runbook zu erstellen. Weitere Informationen zum visuellen Designer finden Sie unter [Visuelle Designerfahrung für Automation-Runbooks](automation-visual-designer.md).

Die folgenden Abschnitten helfen Ihnen, Ihr erstes Runbook erstellen.

## Identifizieren Sie Ihren Anwendungsfall
<a name="automation-authoring-runbooks-use-case"></a>

Der erste Schritt beim Erstellen eines Runbooks besteht darin, Ihren Anwendungsfall zu identifizieren. Beispielsweise haben Sie geplant, das `AWS-CreateImage`-Runbook täglich auf allen Ihren Amazon EC2 Produktions-Instances auszuführen.. Am Ende des Monats entscheiden Sie, dass Sie über mehr Images verfügen, als für Wiederherstellungspunkte erforderlich sind. Künftig möchten Sie automatisch die älteste AMI einer Amazon-EC2-Instance löschen, wenn eine neue AMI erstellt wird. Um dies zu erreichen, erstellen Sie ein neues Runbook, das folgende Funktionen erfüllt:

1. Führt die `aws:createImage`-Aktion aus und gibt die Instance-ID in der Image-Beschreibung an.

1. Führt die `aws:waitForAwsResourceProperty`-Aktion aus, um den Zustand des Images abzufragen, bis es `available` ist.

1. Nachdem der Image-Status `available` ist, führt die`aws:executeScript`-Aktion ein benutzerdefiniertes Python-Skript aus, das die IDs aller Images sammelt, die mit Ihrer Amazon-EC2-Instance verknüpft sind. Das Skript führt diese Filterung aus, indem es die Instance-ID in der Image-Beschreibung verwendet, die Sie bei der Erstellung angegeben haben. Anschließend sortiert das Skript die Liste der Bilder auf der IDs Grundlage `creationDate` des Bildes und gibt die ID des ältesten AMI Bildes aus.

1. Zu guter Letzt wird die `aws:deleteImage`-Aktion ausgeführt, um die älteste AMI zu löschen, mithilfe der ID aus der Ausgabe des vorherigen Schritts.

In diesem Szenario haben Sie bereits das `AWS-CreateImage`-Runbook verwendet, haben aber festgestellt, dass Ihr Anwendungsfall eine größere Flexibilität erforderte. Das kommt häufig vor, da es Überschneidungen zwischen Runbooks und Automatisierungsaktionen geben kann. Daher müssen Sie möglicherweise anpassen, welche Runbooks oder Aktionen Sie verwenden, um Ihren Anwendungsfall zu adressieren.

Zum Beispiel ermöglichen die `aws:executeScript`- und die `aws:invokeLambdaFunction`-Aktion es Ihnen, benutzerdefinierte Skripts als Teil Ihrer Automatisierung auszuführen. Sie bevorzugen vielleicht `aws:invokeLambdaFunction` aufgrund der zusätzlichen unterstützten Laufzeitsprachen. Möglicherweise bevorzugen Sie jedoch `aws:executeScript`, da Sie damit Ihre Skriptinhalte direkt in YAML Runbooks erstellen und Skriptinhalte als Anhänge für JSON-Runbooks bereitstellen können. Sie könnten auch `aws:executeScript` als einfacher in Bezug auf AWS Identity and Access Management (IAM)-Einrichtung empfinden. Da es die in der angegebenen Berechtigungen verwendet`AutomationAssumeRole`, `aws:executeScript` ist keine zusätzliche AWS Lambda Funktionsausführungsrolle erforderlich.

In einem bestimmten Szenario kann eine Aktion mehr Flexibilität oder zusätzliche Funktionalität gegenüber einer anderen bieten. Daher empfiehlt es sich, die verfügbaren Eingabeparameter für das Runbook oder die Aktion zu überprüfen, die Sie verwenden möchten, um zu bestimmen, welche am besten zu Ihrem Anwendungsfall und Ihren Voreinstellungen passt.

## Einrichten Ihrer Entwicklungsumgebung
<a name="automation-authoring-runbooks-environment"></a>

Nachdem Sie Ihren Anwendungsfall und die vordefinierten Runbooks oder Automatisierungsaktionen identifiziert haben, die Sie in Ihrem Runbook verwenden möchten, müssen Sie Ihre Entwicklungsumgebung für den Inhalt Ihres Runbooks einrichten. Für die Entwicklung Ihrer Runbook-Inhalte empfehlen wir die Verwendung der Systems Manager-Dokumentenkonsole AWS Toolkit for Visual Studio Code anstelle der Systems Manager Documents Console. 

Das Toolkit for VS Code ist eine Open-Source-Erweiterung für Visual Studio Code (VS Code), die mehr Funktionen bietet als die Systems Manager Dokumentenkonsole. Zu den hilfreichen Funktionen gehören die Schemavalidierung für YAML und JSON, Snippets für Automatisierungsaktionstypen und die automatische Vervollständigung verschiedener Optionen in YAML und JSON. 

Weitere Informationen zum Installieren des Toolkit for VS Code finden Sie unter[Installieren von AWS Toolkit for Visual Studio Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/setup-toolkit.html). Weitere Informationen zur Verwendung des Toolkit for VS Code zum Erstellen von Runbooks finden Sie unter [Arbeiten mit Systems Manager Automation-Dokumenten](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/systems-manager-automation-docs.html) im *AWS Toolkit for Visual Studio Code -Benutzerhandbuch*.

## Entwickeln von Runbook-Inhalten
<a name="automation-authoring-runbooks-developing-content"></a>

Nachdem Ihr Anwendungsfall identifiziert und die Umgebung eingerichtet ist, können Sie den Inhalt für Ihr Runbook entwickeln. Ihr Anwendungsfall und Ihre Einstellungen bestimmen weitgehend die Automatisierungsaktionen oder Runbooks, die Sie in Ihren Runbook-Inhalten verwenden. Einige Aktionen unterstützen nur eine Teilmenge von Eingabeparametern im Vergleich zu einer anderen Aktion, mit der Sie eine ähnliche Aufgabe ausführen können. Andere Aktionen haben spezifische Ausgaben, wie `aws:createImage`, wo einige Aktionen es Ihnen ermöglichen, eigene Ausgaben zu definieren, z. B. `aws:executeAwsApi`. 

Wenn Sie sich nicht sicher sind, wie Sie eine bestimmte Aktion in Ihrem Runbook verwenden, empfehlen wir Ihnen, den entsprechenden Eintrag für die Aktion im [Systems Manager Automation Aktionen-Referenz](automation-actions.md) nachzulesen. Wir empfehlen auch, den Inhalt vordefinierter Runbooks zu überprüfen, um Beispiele für die Verwendung dieser Aktionen zu sehen. Weitere Beispiele für Anwendungen von Runbooks in der Praxis finden Sie unter [Weitere Runbook-Beispiele](automation-document-examples.md).

Um die Unterschiede in Bezug auf Einfachheit und Flexibilität zu demonstrieren, die Runbook-Inhalte bieten, bieten die folgenden Tutorials ein Beispiel, wie Sie Gruppen von Amazon-EC2-Instances stufenweise patchen:
+ [Beispiel 1: Erstellen von über- und untergeordneten Runbooks](automation-authoring-runbooks-parent-child-example.md) – In diesem Beispiel werden zwei Runbooks in einer Untergeordnet-Übergeordnet-Beziehung verwendet. Das übergeordnete Runbook initiiert eine Automatisierung der Ratensteuerung des untergeordneten Runbooks. 
+ [Beispiel 2: Skriptbasiertes Runbook](automation-authoring-runbooks-scripted-example.md) – Dieses Beispiel zeigt, wie Sie die gleichen Aufgaben von Beispiel 1 ausführen können, indem Sie den Inhalt zu einem einzigen Runbook zusammenfassen und Skripte in Ihrem Runbook verwenden.

# Beispiel 1: Erstellen von über- und untergeordneten Runbooks
<a name="automation-authoring-runbooks-parent-child-example"></a>

Das folgende Beispiel erläutert, wie Sie zwei Runbooks erstellen, die getaggte Gruppen von Amazon Elastic Compute Cloud (Amazon EC2)-Instances stufenweise patchen. Diese Runbooks werden in einer Untergeordnet–Übergeordnet-Beziehung mit dem übergeordneten Runbook verwendet, das verwendet wird, um eine Kurssteuerungsautomatisierung des untergeordneten Runbooks zu initiieren. Weitere Informationen über die Ratenregelung-Automatisierungen finden Sie unter [Automatisierte Abläufe in großem Umfang ausführen](running-automations-scale.md). Weitere Informationen zu den hier verwendeten Automation-Aktionen finden Sie unter [Systems Manager Automation Aktionen-Referenz](automation-actions.md).

## Erstellen des untergeordneten Runbooks
<a name="automation-authoring-runbooks-child-runbook"></a>

In diesem Beispiel-Runbook wird das folgende Szenario behandelt. Emily ist Systemingenieurin bei AnyCompany Consultants, LLC. Sie muss Patches für Gruppen von Amazon Elastic Compute Cloud (Amazon EC2)-Instances konfigurieren, die primäre und sekundäre Datenbanken hosten. Anwendungen greifen 24 Stunden am Tag auf diese Datenbanken zu, sodass eine der Datenbankinstances immer verfügbar sein muss. 

Sie entscheidet, dass das Patchen der Instances stufenweise der beste Ansatz ist. Die primäre Gruppe von Datenbankinstances wird zuerst gepatcht, gefolgt von der sekundären Gruppe von Datenbankinstances. Um zusätzliche Kosten zu vermeiden, indem Instances ausgeführt werden, die zuvor gestoppt wurden, möchte Emily außerdem, dass die gepatchten Instances in ihren ursprünglichen Zustand zurückversetzt werden, bevor das Patchen stattgefunden hat. 

Emily identifiziert die primären und sekundären Gruppen von Datenbankinstances anhand der Tags, die den Instances zugeordnet sind. Sie beschließt, ein übergeordnetes Runbook zu erstellen, das eine Automatisierung der Ratenkontrolle eines untergeordneten Runbooks startet. Auf diese Weise kann sie die Tags ausrichten, die mit den primären und sekundären Gruppen von Datenbank-Instances verknüpft sind, und die Parallelität der untergeordneten Automatisierungen verwalten. Nachdem sie die verfügbaren Systems Manager (SSM)-Dokumente zum Patchen überprüft hat, wählt sie das `AWS-RunPatchBaseline`-Document. Mithilfe dieses SSM-Dokuments können ihre Kollegen die zugehörigen Patch-Compliance-Informationen überprüfen, nachdem der Patch-Vorgang abgeschlossen ist.

Um mit der Erstellung ihrer Runbook-Inhalte zu beginnen, überprüft Emily die verfügbaren Automatisierungsaktionen und beginnt mit der Erstellung des Inhalts für das untergeordnete Runbook wie folgt:

1. Zunächst stellt sie Werte für das Schema und die Beschreibung des Runbooks bereit und definiert die Eingabeparameter für das untergeordnete Runbook.

   Durch die Verwendung des `AutomationAssumeRole`-Parameters können Emily und ihre Kollegen eine vorhandene IAM-Rolle verwenden, die der Automatisierung erlaubt, die Aktionen im Runbook für sie auszuführen. Emily verwendet das `InstanceId`-Parameter, um die Instance zu bestimmen, die gepatcht werden soll. Optional können die `Operation`-,`RebootOption`- , und`SnapshotId`-Parameter verwendet werden, um Werte für Dokumentparameter für `AWS-RunPatchBaseline` bereitzustellen. Um zu verhindern, dass für diese Dokumentparameter ungültige Werte bereitgestellt werden, definiert sie die `allowedValues` nach Bedarf.

------
#### [ YAML ]

   ```
   schemaVersion: '0.3'
   description: 'An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.'
   assumeRole: '{{AutomationAssumeRole}}'
   parameters:
     AutomationAssumeRole:
       type: String
       description: >-
         '(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the
         actions on your behalf. If no role is specified, Systems Manager
         Automation uses your IAM permissions to operate this runbook.'
       default: ''
     InstanceId:
       type: String
       description: >-
         '(Required) The instance you want to patch.'
     SnapshotId:
       type: String
       description: '(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.'
       default: ''
     RebootOption:
       type: String
       description: '(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.'
       allowedValues:
         - NoReboot
         - RebootIfNeeded
       default: RebootIfNeeded
     Operation:
       type: String
       description: '(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.'
       allowedValues:
         - Install
         - Scan
       default: Install
   ```

------
#### [ JSON ]

   ```
   {
      "schemaVersion":"0.3",
      "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.",
      "assumeRole":"{{AutomationAssumeRole}}",
      "parameters":{
         "AutomationAssumeRole":{
            "type":"String",
            "description":"(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.",
            "default":""
         },
         "InstanceId":{
            "type":"String",
            "description":"(Required) The instance you want to patch."
         },
         "SnapshotId":{
            "type":"String",
            "description":"(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.",
            "default":""
         },
         "RebootOption":{
            "type":"String",
            "description":"(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.",
            "allowedValues":[
               "NoReboot",
               "RebootIfNeeded"
            ],
            "default":"RebootIfNeeded"
         },
         "Operation":{
            "type":"String",
            "description":"(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.",
            "allowedValues":[
               "Install",
               "Scan"
            ],
            "default":"Install"
         }
      }
   },
   ```

------

1. Wenn die Elemente der obersten Ebene definiert sind, arbeitet Emily mit der Erstellung der Aktionen, welche die `mainSteps` des Runbooks melden. Der erste Schritt gibt den aktuellen Status der Ziel-Instance aus, die im `InstanceId`-Eingabeparameter mit der `aws:executeAwsApi`-Aktion angegeben ist. Die Ausgabe dieser Aktion wird in späteren Aktionen verwendet.

------
#### [ YAML ]

   ```
   mainSteps:
     - name: getInstanceState
       action: 'aws:executeAwsApi'
       onFailure: Abort
       inputs:
         inputs:
         Service: ec2
         Api: DescribeInstances
         InstanceIds:
           - '{{InstanceId}}'
       outputs:
         - Name: instanceState
           Selector: '$.Reservations[0].Instances[0].State.Name'
           Type: String
       nextStep: branchOnInstanceState
   ```

------
#### [ JSON ]

   ```
   "mainSteps":[
         {
            "name":"getInstanceState",
            "action":"aws:executeAwsApi",
            "onFailure":"Abort",
            "inputs":{
               "inputs":null,
               "Service":"ec2",
               "Api":"DescribeInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ]
            },
            "outputs":[
               {
                  "Name":"instanceState",
                  "Selector":"$.Reservations[0].Instances[0].State.Name",
                  "Type":"String"
               }
            ],
            "nextStep":"branchOnInstanceState"
         },
   ```

------

1. Anstatt den ursprünglichen Zustand jeder Instance, die gepatcht werden muss, manuell zu starten und zu verfolgen, verwendet Emily die Ausgabe der vorherigen Aktion, um die Automatisierung basierend auf dem Status der Ziel-Instance zu verzweigen. Auf diese Weise kann die Automatisierung verschiedene Schritte ausführen, abhängig von den Bedingungen, die in der `aws:branch`-Aktion angegeben sind und verbessert die Gesamteffizienz der Automatisierung ohne manuellen Eingriff.

   Wenn der Instance-Status bereits `running` ist, schreitet die Automatisierung mit dem Patchen der Instance mit dem `AWS-RunPatchBaseline`-Dokument unter Verwendung der `aws:runCommand`-Aktion fort.

   Wenn der Instancestatus `stopping` ist, fragt die Automatisierung ab, ob die Instance den Status `stopped` mit der Aktion `aws:waitForAwsResourceProperty` erreicht, startet die Instance mit der Aktion `executeAwsApi` und fragt die Instance ab, um den Status `running` zu erreichen, bevor die Instance gepatcht wird.

   Wenn der Status der Instance `stopped` ist, startet die Automatisierung die Instance und fragt die Instance ab, einen `running`-Status vor dem Patchen der Instance unter Verwendung der gleichen Aktionen zu erreichen.

------
#### [ YAML ]

   ```
   - name: branchOnInstanceState
       action: 'aws:branch'
       onFailure: Abort
       inputs:
         Choices:
           - NextStep: startInstance
              Variable: '{{getInstanceState.instanceState}}'
              StringEquals: stopped
            - NextStep: verifyInstanceStopped
              Variable: '{{getInstanceState.instanceState}}'
              StringEquals: stopping
            - NextStep: patchInstance
              Variable: '{{getInstanceState.instanceState}}'
              StringEquals: running
       isEnd: true
     - name: startInstance
       action: 'aws:executeAwsApi'
       onFailure: Abort
       inputs:
         Service: ec2
         Api: StartInstances
         InstanceIds:
           - '{{InstanceId}}'
       nextStep: verifyInstanceRunning
     - name: verifyInstanceRunning
       action: 'aws:waitForAwsResourceProperty'
       timeoutSeconds: 120
       inputs:
         Service: ec2
         Api: DescribeInstances
         InstanceIds:
           - '{{InstanceId}}'
         PropertySelector: '$.Reservations[0].Instances[0].State.Name'
         DesiredValues:
           - running
       nextStep: patchInstance
     - name: verifyInstanceStopped
       action: 'aws:waitForAwsResourceProperty'
       timeoutSeconds: 120
       inputs:
         Service: ec2
         Api: DescribeInstances
         InstanceIds:
           - '{{InstanceId}}'
         PropertySelector: '$.Reservations[0].Instances[0].State.Name'
         DesiredValues:
           - stopped
         nextStep: startInstance
     - name: patchInstance
       action: 'aws:runCommand'
       onFailure: Abort
       timeoutSeconds: 5400
       inputs:
         DocumentName: 'AWS-RunPatchBaseline'
         InstanceIds: 
         - '{{InstanceId}}'
         Parameters:
           SnapshotId: '{{SnapshotId}}'
           RebootOption: '{{RebootOption}}'
           Operation: '{{Operation}}'
   ```

------
#### [ JSON ]

   ```
   {
            "name":"branchOnInstanceState",
            "action":"aws:branch",
            "onFailure":"Abort",
            "inputs":{
               "Choices":[
                  {
                     "NextStep":"startInstance",
                     "Variable":"{{getInstanceState.instanceState}}",
                     "StringEquals":"stopped"
                  },
                  {
                     "Or":[
                        {
                           "Variable":"{{getInstanceState.instanceState}}",
                           "StringEquals":"stopping"
                        }
                     ],
                     "NextStep":"verifyInstanceStopped"
                  },
                  {
                     "NextStep":"patchInstance",
                     "Variable":"{{getInstanceState.instanceState}}",
                     "StringEquals":"running"
                  }
               ]
            },
            "isEnd":true
         },
         {
            "name":"startInstance",
            "action":"aws:executeAwsApi",
            "onFailure":"Abort",
            "inputs":{
               "Service":"ec2",
               "Api":"StartInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ]
            },
            "nextStep":"verifyInstanceRunning"
         },
         {
            "name":"verifyInstanceRunning",
            "action":"aws:waitForAwsResourceProperty",
            "timeoutSeconds":120,
            "inputs":{
               "Service":"ec2",
               "Api":"DescribeInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ],
               "PropertySelector":"$.Reservations[0].Instances[0].State.Name",
               "DesiredValues":[
                  "running"
               ]
            },
            "nextStep":"patchInstance"
         },
         {
            "name":"verifyInstanceStopped",
            "action":"aws:waitForAwsResourceProperty",
            "timeoutSeconds":120,
            "inputs":{
               "Service":"ec2",
               "Api":"DescribeInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ],
               "PropertySelector":"$.Reservations[0].Instances[0].State.Name",
               "DesiredValues":[
                  "stopped"
               ],
               "nextStep":"startInstance"
            }
         },
         {
            "name":"patchInstance",
            "action":"aws:runCommand",
            "onFailure":"Abort",
            "timeoutSeconds":5400,
            "inputs":{
               "DocumentName":"AWS-RunPatchBaseline",
               "InstanceIds":[
                  "{{InstanceId}}"
               ],
               "Parameters":{
                  "SnapshotId":"{{SnapshotId}}",
                  "RebootOption":"{{RebootOption}}",
                  "Operation":"{{Operation}}"
               }
            }
         },
   ```

------

1. Nach Abschluss des Patching-Vorgangs möchte Emily, dass die Automatisierung die Ziel-Instance in denselben Zustand versetzt, in dem sie sich vor dem Automatisierungsstart befanden. Sie tut dies, indem sie erneut die Ausgabe der ersten Aktion verwendet. Die Automatisierung verzweigt sich basierend auf dem ursprünglichen Zustand der Ziel-Instance unter Verwendung der `aws:branch`-Aktion. Wenn sich die Instance zuvor in einem anderen Zustand als `running` befand, wird die Instance angehalten. Lautet der Status der Instance `running`, stoppt die Automatisierung.

------
#### [ YAML ]

   ```
   - name: branchOnOriginalInstanceState
       action: 'aws:branch'
       onFailure: Abort
       inputs:
         Choices:
           - NextStep: stopInstance
             Not: 
               Variable: '{{getInstanceState.instanceState}}'
               StringEquals: running
       isEnd: true
     - name: stopInstance
       action: 'aws:executeAwsApi'
       onFailure: Abort
       inputs:
         Service: ec2
         Api: StopInstances
         InstanceIds:
           - '{{InstanceId}}'
   ```

------
#### [ JSON ]

   ```
   {
            "name":"branchOnOriginalInstanceState",
            "action":"aws:branch",
            "onFailure":"Abort",
            "inputs":{
               "Choices":[
                  {
                     "NextStep":"stopInstance",
                     "Not":{
                        "Variable":"{{getInstanceState.instanceState}}",
                        "StringEquals":"running"
                     }
                  }
               ]
            },
            "isEnd":true
         },
         {
            "name":"stopInstance",
            "action":"aws:executeAwsApi",
            "onFailure":"Abort",
            "inputs":{
               "Service":"ec2",
               "Api":"StopInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ]
            }
         }
      ]
   }
   ```

------

1. Emily überprüft den vollständigen Inhalt des untergeordneten Runbooks und erstellt das Runbook in derselben AWS-Konto und in den AWS-Region Zielinstanzen. Jetzt ist sie bereit, mit der Erstellung des übergeordneten Runbooks fortzufahren. Im Folgenden finden Sie den vollständigen untergeordneten Runbook-Inhalt.

------
#### [ YAML ]

   ```
   schemaVersion: '0.3'
   description: 'An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.'
   assumeRole: '{{AutomationAssumeRole}}'
   parameters:
     AutomationAssumeRole:
       type: String
       description: >-
         '(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the
         actions on your behalf. If no role is specified, Systems Manager
         Automation uses your IAM permissions to operate this runbook.'
       default: ''
     InstanceId:
       type: String
       description: >-
         '(Required) The instance you want to patch.'
     SnapshotId:
       type: String
       description: '(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.'
       default: ''
     RebootOption:
       type: String
       description: '(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.'
       allowedValues:
         - NoReboot
         - RebootIfNeeded
       default: RebootIfNeeded
     Operation:
       type: String
       description: '(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.'
       allowedValues:
         - Install
         - Scan
       default: Install
   mainSteps:
     - name: getInstanceState
       action: 'aws:executeAwsApi'
       onFailure: Abort
       inputs:
         inputs:
         Service: ec2
         Api: DescribeInstances
         InstanceIds:
           - '{{InstanceId}}'
       outputs:
         - Name: instanceState
           Selector: '$.Reservations[0].Instances[0].State.Name'
           Type: String
       nextStep: branchOnInstanceState
     - name: branchOnInstanceState
       action: 'aws:branch'
       onFailure: Abort
       inputs:
         Choices:
           - NextStep: startInstance
             Variable: '{{getInstanceState.instanceState}}'
             StringEquals: stopped
           - Or:
               - Variable: '{{getInstanceState.instanceState}}'
                 StringEquals: stopping
             NextStep: verifyInstanceStopped
           - NextStep: patchInstance
             Variable: '{{getInstanceState.instanceState}}'
             StringEquals: running
       isEnd: true
     - name: startInstance
       action: 'aws:executeAwsApi'
       onFailure: Abort
       inputs:
         Service: ec2
         Api: StartInstances
         InstanceIds:
           - '{{InstanceId}}'
       nextStep: verifyInstanceRunning
     - name: verifyInstanceRunning
       action: 'aws:waitForAwsResourceProperty'
       timeoutSeconds: 120
       inputs:
         Service: ec2
         Api: DescribeInstances
         InstanceIds:
           - '{{InstanceId}}'
         PropertySelector: '$.Reservations[0].Instances[0].State.Name'
         DesiredValues:
           - running
       nextStep: patchInstance
     - name: verifyInstanceStopped
       action: 'aws:waitForAwsResourceProperty'
       timeoutSeconds: 120
       inputs:
         Service: ec2
         Api: DescribeInstances
         InstanceIds:
           - '{{InstanceId}}'
         PropertySelector: '$.Reservations[0].Instances[0].State.Name'
         DesiredValues:
           - stopped
         nextStep: startInstance
     - name: patchInstance
       action: 'aws:runCommand'
       onFailure: Abort
       timeoutSeconds: 5400
       inputs:
         DocumentName: 'AWS-RunPatchBaseline'
         InstanceIds: 
         - '{{InstanceId}}'
         Parameters:
           SnapshotId: '{{SnapshotId}}'
           RebootOption: '{{RebootOption}}'
           Operation: '{{Operation}}'
     - name: branchOnOriginalInstanceState
       action: 'aws:branch'
       onFailure: Abort
       inputs:
         Choices:
           - NextStep: stopInstance
             Not: 
               Variable: '{{getInstanceState.instanceState}}'
               StringEquals: running
       isEnd: true
     - name: stopInstance
       action: 'aws:executeAwsApi'
       onFailure: Abort
       inputs:
         Service: ec2
         Api: StopInstances
         InstanceIds:
           - '{{InstanceId}}'
   ```

------
#### [ JSON ]

   ```
   {
      "schemaVersion":"0.3",
      "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.",
      "assumeRole":"{{AutomationAssumeRole}}",
      "parameters":{
         "AutomationAssumeRole":{
            "type":"String",
            "description":"'(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.'",
            "default":""
         },
         "InstanceId":{
            "type":"String",
            "description":"'(Required) The instance you want to patch.'"
         },
         "SnapshotId":{
            "type":"String",
            "description":"(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.",
            "default":""
         },
         "RebootOption":{
            "type":"String",
            "description":"(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.",
            "allowedValues":[
               "NoReboot",
               "RebootIfNeeded"
            ],
            "default":"RebootIfNeeded"
         },
         "Operation":{
            "type":"String",
            "description":"(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.",
            "allowedValues":[
               "Install",
               "Scan"
            ],
            "default":"Install"
         }
      },
      "mainSteps":[
         {
            "name":"getInstanceState",
            "action":"aws:executeAwsApi",
            "onFailure":"Abort",
            "inputs":{
               "inputs":null,
               "Service":"ec2",
               "Api":"DescribeInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ]
            },
            "outputs":[
               {
                  "Name":"instanceState",
                  "Selector":"$.Reservations[0].Instances[0].State.Name",
                  "Type":"String"
               }
            ],
            "nextStep":"branchOnInstanceState"
         },
         {
            "name":"branchOnInstanceState",
            "action":"aws:branch",
            "onFailure":"Abort",
            "inputs":{
               "Choices":[
                  {
                     "NextStep":"startInstance",
                     "Variable":"{{getInstanceState.instanceState}}",
                     "StringEquals":"stopped"
                  },
                  {
                     "Or":[
                        {
                           "Variable":"{{getInstanceState.instanceState}}",
                           "StringEquals":"stopping"
                        }
                     ],
                     "NextStep":"verifyInstanceStopped"
                  },
                  {
                     "NextStep":"patchInstance",
                     "Variable":"{{getInstanceState.instanceState}}",
                     "StringEquals":"running"
                  }
               ]
            },
            "isEnd":true
         },
         {
            "name":"startInstance",
            "action":"aws:executeAwsApi",
            "onFailure":"Abort",
            "inputs":{
               "Service":"ec2",
               "Api":"StartInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ]
            },
            "nextStep":"verifyInstanceRunning"
         },
         {
            "name":"verifyInstanceRunning",
            "action":"aws:waitForAwsResourceProperty",
            "timeoutSeconds":120,
            "inputs":{
               "Service":"ec2",
               "Api":"DescribeInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ],
               "PropertySelector":"$.Reservations[0].Instances[0].State.Name",
               "DesiredValues":[
                  "running"
               ]
            },
            "nextStep":"patchInstance"
         },
         {
            "name":"verifyInstanceStopped",
            "action":"aws:waitForAwsResourceProperty",
            "timeoutSeconds":120,
            "inputs":{
               "Service":"ec2",
               "Api":"DescribeInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ],
               "PropertySelector":"$.Reservations[0].Instances[0].State.Name",
               "DesiredValues":[
                  "stopped"
               ],
               "nextStep":"startInstance"
            }
         },
         {
            "name":"patchInstance",
            "action":"aws:runCommand",
            "onFailure":"Abort",
            "timeoutSeconds":5400,
            "inputs":{
               "DocumentName":"AWS-RunPatchBaseline",
               "InstanceIds":[
                  "{{InstanceId}}"
               ],
               "Parameters":{
                  "SnapshotId":"{{SnapshotId}}",
                  "RebootOption":"{{RebootOption}}",
                  "Operation":"{{Operation}}"
               }
            }
         },
         {
            "name":"branchOnOriginalInstanceState",
            "action":"aws:branch",
            "onFailure":"Abort",
            "inputs":{
               "Choices":[
                  {
                     "NextStep":"stopInstance",
                     "Not":{
                        "Variable":"{{getInstanceState.instanceState}}",
                        "StringEquals":"running"
                     }
                  }
               ]
            },
            "isEnd":true
         },
         {
            "name":"stopInstance",
            "action":"aws:executeAwsApi",
            "onFailure":"Abort",
            "inputs":{
               "Service":"ec2",
               "Api":"StopInstances",
               "InstanceIds":[
                  "{{InstanceId}}"
               ]
            }
         }
      ]
   }
   ```

------

Weitere Informationen zu den hier verwendeten Automation-Aktionen finden Sie unter [Systems Manager Automation Aktionen-Referenz](automation-actions.md).

## Erstellen des übergeordneten Runbooks
<a name="automation-authoring-runbooks-parent-runbook"></a>

In diesem Beispiel-Runbook wird das Szenario fortgesetzt, das im vorherigen Abschnitt beschrieben wird. Nachdem Emily nun das untergeordnete Runbook erstellt hat, beginnt sie mit der Erstellung des Inhalts für das übergeordnete Runbook wie folgt:

1. Zunächst stellt sie Werte für das Schema und die Beschreibung des Runbooks bereit und definiert die Eingabeparameter für das übergeordnete Runbook.

   Durch die Verwendung des `AutomationAssumeRole`-Parameters können Emily und ihre Kollegen eine vorhandene IAM-Rolle verwenden, die der Automatisierung erlaubt, die Aktionen im Runbook für sie auszuführen. Emily verwendet die `PatchGroupPrimaryKey`- und `PatchGroupPrimaryValue`-Parameter, um das Tag anzugeben, das mit der primären Gruppe von Datenbankinstances verknüpft ist, die gepatcht werden sollen. Sie verwendet den `PatchGroupSecondaryKey`- und `PatchGroupSecondaryValue`-Parameter, um das Tag anzugeben, das mit der sekundären Gruppe von Datenbankinstances verknüpft ist, die gepatcht werden sollen.

------
#### [ YAML ]

   ```
   description: 'An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.'
   schemaVersion: '0.3'
   assumeRole: '{{AutomationAssumeRole}}'
   parameters:
     AutomationAssumeRole:
       type: String
       description: '(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.'
       default: ''
     PatchGroupPrimaryKey:
       type: String
       description: '(Required) The key of the tag for the primary group of instances you want to patch.''
     PatchGroupPrimaryValue:
       type: String
       description: '(Required) The value of the tag for the primary group of instances you want to patch.'
     PatchGroupSecondaryKey:
       type: String
       description: '(Required) The key of the tag for the secondary group of instances you want to patch.'
     PatchGroupSecondaryValue:
       type: String
       description: '(Required) The value of the tag for the secondary group of instances you want to patch.'
   ```

------
#### [ JSON ]

   ```
   {
      "schemaVersion": "0.3",
      "description": "An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.",
      "assumeRole": "{{AutomationAssumeRole}}",
      "parameters": {
         "AutomationAssumeRole": {
            "type": "String",
            "description": "(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.",
            "default": ""
         },
         "PatchGroupPrimaryKey": {
            "type": "String",
            "description": "(Required) The key of the tag for the primary group of instances you want to patch."
         },
         "PatchGroupPrimaryValue": {
            "type": "String",
            "description": "(Required) The value of the tag for the primary group of instances you want to patch."
         },
         "PatchGroupSecondaryKey": {
            "type": "String",
            "description": "(Required) The key of the tag for the secondary group of instances you want to patch."
         },
         "PatchGroupSecondaryValue": {
            "type": "String",
            "description": "(Required) The value of the tag for the secondary group of instances you want to patch."
         }
      }
   },
   ```

------

1. Wenn die Elemente der obersten Ebene definiert sind, arbeitet Emily mit der Erstellung der Aktionen, welche die `mainSteps` des Runbooks melden. 

   Bei der ersten Aktion wird eine Ratensteuerungsautomatisierung mit dem soeben erstellten untergeordneten Runbook gestartet, das Instances betrifft, die mit dem Tag verknüpft sind, das in den `PatchGroupPrimaryKey`- und `PatchGroupPrimaryValue`-Eingabeparametern angegeben ist. Sie verwendet die Werte, die den Eingabeparametern zur Verfügung gestellt werden, um den Schlüssel und den Wert des Tags anzugeben, welcher der primären Gruppe von Datenbankinstances zugeordnet ist, die sie patchen möchte.

   Nach der Fertigstellung der ersten Automatisierung, startet die zweite Aktion eine andere Ratensteuerungsautomatisierung unter Verwendung des untergeordneten Runbooks, das Instances betrifft, die mit dem Tag verknüpft sind, das in den `PatchGroupSecondaryKey`- und `PatchGroupSecondaryValue`-Eingabeparametern angegeben ist. Sie verwendet die Werte, die den Eingabeparametern zur Verfügung gestellt werden, um den Schlüssel und den Wert des Tags anzugeben, welcher der sekundären Gruppe von Datenbankinstances zugeordnet ist, die sie patchen möchte.

------
#### [ YAML ]

   ```
   mainSteps:
     - name: patchPrimaryTargets
       action: 'aws:executeAutomation'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: RunbookTutorialChildAutomation
         Targets:
           - Key: 'tag:{{PatchGroupPrimaryKey}}'
             Values:
               - '{{PatchGroupPrimaryValue}}'
         TargetParameterName: 'InstanceId'
     - name: patchSecondaryTargets
       action: 'aws:executeAutomation'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: RunbookTutorialChildAutomation
         Targets:
           - Key: 'tag:{{PatchGroupSecondaryKey}}'
             Values:
               - '{{PatchGroupSecondaryValue}}'
         TargetParameterName: 'InstanceId'
   ```

------
#### [ JSON ]

   ```
   "mainSteps":[
         {
            "name":"patchPrimaryTargets",
            "action":"aws:executeAutomation",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"RunbookTutorialChildAutomation",
               "Targets":[
                  {
                     "Key":"tag:{{PatchGroupPrimaryKey}}",
                     "Values":[
                        "{{PatchGroupPrimaryValue}}"
                     ]
                  }
               ],
               "TargetParameterName":"InstanceId"
            }
         },
         {
            "name":"patchSecondaryTargets",
            "action":"aws:executeAutomation",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"RunbookTutorialChildAutomation",
               "Targets":[
                  {
                     "Key":"tag:{{PatchGroupSecondaryKey}}",
                     "Values":[
                        "{{PatchGroupSecondaryValue}}"
                     ]
                  }
               ],
               "TargetParameterName":"InstanceId"
            }
         }
      ]
   }
   ```

------

1. Emily überprüft den vollständigen Inhalt des übergeordneten Runbooks und erstellt das Runbook in derselben AWS-Konto und in den Ziel-Instances AWS-Region . Jetzt ist sie bereit, ihre Runbooks zu testen, um sicherzustellen, dass die Automatisierung wie gewünscht funktioniert, bevor sie in ihre Produktionsumgebung implementiert werden. Im Folgenden finden Sie den vollständigen übergeordneten Runbook-Inhalt.

------
#### [ YAML ]

   ```
   description: An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.
   schemaVersion: '0.3'
   assumeRole: '{{AutomationAssumeRole}}'
   parameters:
     AutomationAssumeRole:
       type: String
       description: '(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.'
       default: ''
     PatchGroupPrimaryKey:
       type: String
       description: (Required) The key of the tag for the primary group of instances you want to patch.
     PatchGroupPrimaryValue:
       type: String
       description: '(Required) The value of the tag for the primary group of instances you want to patch. '
     PatchGroupSecondaryKey:
       type: String
       description: (Required) The key of the tag for the secondary group of instances you want to patch.
     PatchGroupSecondaryValue:
       type: String
       description: '(Required) The value of the tag for the secondary group of instances you want to patch.  '
   mainSteps:
     - name: patchPrimaryTargets
       action: 'aws:executeAutomation'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: RunbookTutorialChildAutomation
         Targets:
           - Key: 'tag:{{PatchGroupPrimaryKey}}'
             Values:
               - '{{PatchGroupPrimaryValue}}'
         TargetParameterName: 'InstanceId'
     - name: patchSecondaryTargets
       action: 'aws:executeAutomation'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: RunbookTutorialChildAutomation
         Targets:
           - Key: 'tag:{{PatchGroupSecondaryKey}}'
             Values:
               - '{{PatchGroupSecondaryValue}}'
         TargetParameterName: 'InstanceId'
   ```

------
#### [ JSON ]

   ```
   {
      "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.",
      "schemaVersion":"0.3",
      "assumeRole":"{{AutomationAssumeRole}}",
      "parameters":{
         "AutomationAssumeRole":{
            "type":"String",
            "description":"(Optional) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.",
            "default":""
         },
         "PatchGroupPrimaryKey":{
            "type":"String",
            "description":"(Required) The key of the tag for the primary group of instances you want to patch."
         },
         "PatchGroupPrimaryValue":{
            "type":"String",
            "description":"(Required) The value of the tag for the primary group of instances you want to patch. "
         },
         "PatchGroupSecondaryKey":{
            "type":"String",
            "description":"(Required) The key of the tag for the secondary group of instances you want to patch."
         },
         "PatchGroupSecondaryValue":{
            "type":"String",
            "description":"(Required) The value of the tag for the secondary group of instances you want to patch.  "
         }
      },
      "mainSteps":[
         {
            "name":"patchPrimaryTargets",
            "action":"aws:executeAutomation",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"RunbookTutorialChildAutomation",
               "Targets":[
                  {
                     "Key":"tag:{{PatchGroupPrimaryKey}}",
                     "Values":[
                        "{{PatchGroupPrimaryValue}}"
                     ]
                  }
               ],
               "TargetParameterName":"InstanceId"
            }
         },
         {
            "name":"patchSecondaryTargets",
            "action":"aws:executeAutomation",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"RunbookTutorialChildAutomation",
               "Targets":[
                  {
                     "Key":"tag:{{PatchGroupSecondaryKey}}",
                     "Values":[
                        "{{PatchGroupSecondaryValue}}"
                     ]
                  }
               ],
               "TargetParameterName":"InstanceId"
            }
         }
      ]
   }
   ```

------

Weitere Informationen zu den hier verwendeten Automation-Aktionen finden Sie unter [Systems Manager Automation Aktionen-Referenz](automation-actions.md).

# Beispiel 2: Skriptbasiertes Runbook
<a name="automation-authoring-runbooks-scripted-example"></a>

In diesem Beispiel-Runbook wird das folgende Szenario behandelt. Emily ist Systemingenieurin bei AnyCompany Consultants, LLC. Sie hat zuvor zwei Runbooks erstellt, die in einer Untergeordnet-Übergeordnet-Beziehung verwendet werden, um Patch-Gruppen von Amazon Elastic Compute Cloud (Amazon EC2)-Instances zu patchen, die primäre und sekundäre Datenbanken hosten. Anwendungen greifen 24 Stunden am Tag auf diese Datenbanken zu, sodass eine der Datenbankinstances immer verfügbar sein muss. 

Basierend auf dieser Anforderung hat sie eine Lösung entwickelt, welche die Instances stufenweise mit dem `AWS-RunPatchBaseline`-Systems Manager (SSM)-Dokument patcht. Mithilfe dieses SSM-Dokuments können ihre Kollegen die zugehörigen Patch-Compliance-Informationen überprüfen, nachdem der Patch-Vorgang abgeschlossen ist. 

Die primäre Gruppe von Datenbankinstances wird zuerst gepatcht, gefolgt von der sekundären Gruppe von Datenbankinstances. Um zusätzliche Kosten zu vermeiden, indem Instances ausgeführt werden, die zuvor gestoppt wurden, hat Emily sichergestellt, dass die Automatisierung die gepatchten Instances in ihren ursprünglichen Zustand zurückversetzte, bevor das Patchen stattgefunden hat. Emily verwendete Tags, die den primären und sekundären Gruppen von Datenbankinstances zugeordnet sind, um zu ermitteln, welche Instances in der gewünschten Reihenfolge gepatcht werden sollen.

Ihre bestehende automatisierte Lösung funktioniert, aber sie will ihre Lösung nach Möglichkeit verbessern. Um bei der Wartung des Runbook-Inhalts zu helfen und die Fehlerbehebung zu erleichtern, möchte sie die Automatisierung zu einem einzigen Runbook zusammenfassen und die Anzahl der Eingabeparameter vereinfachen. Außerdem möchte sie vermeiden, dass mehrere untergeordnete Automatisierungen erstellt werden. 

Nachdem Emily die verfügbaren Automatisierungsaktionen überprüft hat, stellt sie fest, dass sie ihre Lösung mithilfe der `aws:executeScript`-Aktion verbessern kann, um ihre benutzerdefinierten Python-Skripte auszuführen. Sie beginnt nun mit der Erstellung des Inhalts für das Runbook wie folgt:

1. Zunächst stellt sie Werte für das Schema und die Beschreibung des Runbooks bereit und definiert die Eingabeparameter für das übergeordnete Runbook.

   Durch die Verwendung des `AutomationAssumeRole`-Parameters können Emily und ihre Kollegen eine vorhandene IAM-Rolle verwenden, die der Automatisierung erlaubt, die Aktionen im Runbook für sie auszuführen. Im Gegensatz zum [Beispiel 1](automation-authoring-runbooks-parent-child-example.md) ist der `AutomationAssumeRole`-Parameter ist jetzt erforderlich und nicht optional. Da dieses Runbook `aws:executeScript` Aktionen enthält, ist immer eine AWS Identity and Access Management (IAM-) Dienstrolle (oder Rolle übernehmen) erforderlich. Diese Anforderung ist notwendig, da einige der Python-Skripte, die für die Aktionen angegeben sind, AWS -API-Operationen aufrufen.

   Emily verwendet die `PrimaryPatchGroupTag`- und `SecondaryPatchGroupTag`-Parameter, um die Tags anzugeben, die mit der primären und sekundären Gruppe von Datenbankinstances verknüpft sind, die gepatcht werden sollen. Um die erforderlichen Eingabeparameter zu vereinfachen, entscheidet sie sich, `StringMap`-Parameter anstatt mehrerer `String`-Parameter zu verwenden, wie sie im Runbook von Beispiel 1 verwendet wurde. Optional können die `Operation`-,`RebootOption`- , und`SnapshotId`-Parameter verwendet werden, um Werte für Dokumentparameter für `AWS-RunPatchBaseline` bereitzustellen. Um zu verhindern, dass für diese Dokumentparameter ungültige Werte bereitgestellt werden, definiert sie die `allowedValues` nach Bedarf.

------
#### [ YAML ]

   ```
   description: 'An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.'
   schemaVersion: '0.3'
   assumeRole: '{{AutomationAssumeRole}}'
   parameters:
     AutomationAssumeRole:
       type: String
       description: '(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.'
     PrimaryPatchGroupTag:
       type: StringMap
       description: '(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}'
     SecondaryPatchGroupTag:
       type: StringMap
       description: '(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}'
     SnapshotId:
       type: String
       description: '(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.'
       default: ''
     RebootOption:
       type: String
       description: '(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.'
       allowedValues:
         - NoReboot
         - RebootIfNeeded
       default: RebootIfNeeded
     Operation:
       type: String
       description: '(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.'
       allowedValues:
         - Install
         - Scan
       default: Install
   ```

------
#### [ JSON ]

   ```
   {
      "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.",
      "schemaVersion":"0.3",
      "assumeRole":"{{AutomationAssumeRole}}",
      "parameters":{
         "AutomationAssumeRole":{
            "type":"String",
            "description":"(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook."
         },
         "PrimaryPatchGroupTag":{
            "type":"StringMap",
            "description":"(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}"
         },
         "SecondaryPatchGroupTag":{
            "type":"StringMap",
            "description":"(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}"
         },
         "SnapshotId":{
            "type":"String",
            "description":"(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.",
            "default":""
         },
         "RebootOption":{
            "type":"String",
            "description":"(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.",
            "allowedValues":[
               "NoReboot",
               "RebootIfNeeded"
            ],
            "default":"RebootIfNeeded"
         },
         "Operation":{
            "type":"String",
            "description":"(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.",
            "allowedValues":[
               "Install",
               "Scan"
            ],
            "default":"Install"
         }
      }
   },
   ```

------

1. Wenn die Elemente der obersten Ebene definiert sind, arbeitet Emily mit der Erstellung der Aktionen, welche die `mainSteps` des Runbooks melden. Im ersten Schritt werden alle Instanzen erfasst, die IDs dem im Parameter angegebenen Tag zugeordnet sind, und es wird ein `PrimaryPatchGroupTag` `StringMap` Parameter ausgegeben, der die Instanz-ID und den aktuellen Status der Instanz enthält. Die Ausgabe dieser Aktion wird in späteren Aktionen verwendet. 

   Beachten Sie, dass die `script`-Eingabeparameter für JSON-Runbooks nicht unterstützt werden. JSON-Runbooks müssen Skriptinhalt mithilfe des `attachment`-Eingabeparameters bereitstellen.

------
#### [ YAML ]

   ```
   mainSteps:
     - name: getPrimaryInstanceState
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: getInstanceStates
         InputPayload:
           primaryTag: '{{PrimaryPatchGroupTag}}'
         Script: |-
           def getInstanceStates(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             tag = events['primaryTag']
             tagKey, tagValue = list(tag.items())[0]
             instanceQuery = ec2.describe_instances(
             Filters=[
                 {
                     "Name": "tag:" + tagKey,
                     "Values": [tagValue]
                 }]
             )
             if not instanceQuery['Reservations']:
                 noInstancesForTagString = "No instances found for specified tag."
                 return({ 'noInstancesFound' : noInstancesForTagString })
             else:
                 queryResponse = instanceQuery['Reservations']
                 originalInstanceStates = {}
                 for results in queryResponse:
                     instanceSet = results['Instances']
                     for instance in instanceSet:
                         instanceId = instance['InstanceId']
                         originalInstanceStates[instanceId] = instance['State']['Name']
                 return originalInstanceStates
       outputs:
         - Name: originalInstanceStates
           Selector: $.Payload
           Type: StringMap
       nextStep: verifyPrimaryInstancesRunning
   ```

------
#### [ JSON ]

   ```
   "mainSteps":[
         {
            "name":"getPrimaryInstanceState",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"getInstanceStates",
               "InputPayload":{
                  "primaryTag":"{{PrimaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"originalInstanceStates",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               }
            ],
            "nextStep":"verifyPrimaryInstancesRunning"
         },
   ```

------

1. Emily verwendet die Ausgabe der vorherigen Aktion in einer anderen `aws:executeScript`-Aktion, um zu überprüfen, ob alle Instances, die dem im `PrimaryPatchGroupTag`-Parameter angegebenen Tag zugeordnet sind, in einem `running`-Zustand sind.

   Wenn der Instance-Status bereits `running` oder `shutting-down` ist, durchläuft das Skript weiterhin die verbleibenden Instances.

   Wenn der Status der Instance `stopping` ist, fragt das Skript die Instance ab, den `stopped`-Status zu erreichen und startet die Instance.

   Wenn der Status der Instance `stopped` ist, startet das Skript die Instance.

------
#### [ YAML ]

   ```
   - name: verifyPrimaryInstancesRunning
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: verifyInstancesRunning
         InputPayload:
           targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}'
         Script: |-
           def verifyInstancesRunning(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped':
                   print("The target instance " + instance + " is stopped. The instance will now be started.")
                   ec2.start_instances(
                       InstanceIds=[instance]
                       )
               elif instanceDict[instance] == 'stopping':
                   print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.")
                   while instanceDict[instance] != 'stopped':
                       poll = ec2.get_waiter('instance_stopped')
                       poll.wait(
                           InstanceIds=[instance]
                       )
                   ec2.start_instances(
                       InstanceIds=[instance]
                   )
               else:
                 pass
       nextStep: waitForPrimaryRunningInstances
   ```

------
#### [ JSON ]

   ```
   {
            "name":"verifyPrimaryInstancesRunning",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"verifyInstancesRunning",
               "InputPayload":{
                  "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"waitForPrimaryRunningInstances"
         },
   ```

------

1. Emily überprüft, ob alle Instances, die dem im `PrimaryPatchGroupTag`-Parameter angegebenen Tag zugeordnet sind, gestartet wurden oder sich bereits in einem `running`-Zustand befinden. Dann verwendet sie ein anderes Skript, um zu überprüfen, ob alle Instances, einschließlich derjenigen, die in der vorherigen Aktion gestartet wurden, den `running`-Zustand erreicht haben.

------
#### [ YAML ]

   ```
   - name: waitForPrimaryRunningInstances
       action: 'aws:executeScript'
       timeoutSeconds: 300
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: waitForRunningInstances
         InputPayload:
           targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}'
         Script: |-
           def waitForRunningInstances(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
                 poll = ec2.get_waiter('instance_running')
                 poll.wait(
                     InstanceIds=[instance]
                 )
       nextStep: returnPrimaryTagKey
   ```

------
#### [ JSON ]

   ```
   {
            "name":"waitForPrimaryRunningInstances",
            "action":"aws:executeScript",
            "timeoutSeconds":300,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"waitForRunningInstances",
               "InputPayload":{
                  "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"returnPrimaryTagKey"
         },
   ```

------

1. Emily verwendet zwei weitere Skripte, um einzelne `String`-Werte des Schlüssels und des Werts des Tags zurückzugeben, das im `PrimaryPatchGroupTag`-Parameter angegeben ist. Die Werte, die von diesen Aktionen zurückgegeben werden, ermöglichen es ihr, Werte direkt für die `Targets`-Parameter für das `AWS-RunPatchBaseline`-Dokument bereitzustellen. Die Automatisierung schreitet dann mit dem Patchen der Instance mit dem `AWS-RunPatchBaseline`-Dokument unter Verwendung der `aws:runCommand`-Aktion fort.

------
#### [ YAML ]

   ```
   - name: returnPrimaryTagKey
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           primaryTag: '{{PrimaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['primaryTag']
             tagKey = list(tag)[0]
             stringKey = "tag:" + tagKey
             return {'tagKey' : stringKey}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: primaryPatchGroupKey
           Selector: $.Payload.tagKey
           Type: String
       nextStep: returnPrimaryTagValue
     - name: returnPrimaryTagValue
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           primaryTag: '{{PrimaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['primaryTag']
             tagKey = list(tag)[0]
             tagValue = tag[tagKey]
             return {'tagValue' : tagValue}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: primaryPatchGroupValue
           Selector: $.Payload.tagValue
           Type: String
       nextStep: patchPrimaryInstances
     - name: patchPrimaryInstances
       action: 'aws:runCommand'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: AWS-RunPatchBaseline
         Parameters:
           SnapshotId: '{{SnapshotId}}'
           RebootOption: '{{RebootOption}}'
           Operation: '{{Operation}}'
         Targets:
           - Key: '{{returnPrimaryTagKey.primaryPatchGroupKey}}'
             Values:
               - '{{returnPrimaryTagValue.primaryPatchGroupValue}}'
         MaxConcurrency: 10%
         MaxErrors: 10%
       nextStep: returnPrimaryToOriginalState
   ```

------
#### [ JSON ]

   ```
   {
            "name":"returnPrimaryTagKey",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "primaryTag":"{{PrimaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"primaryPatchGroupKey",
                  "Selector":"$.Payload.tagKey",
                  "Type":"String"
               }
            ],
            "nextStep":"returnPrimaryTagValue"
         },
         {
            "name":"returnPrimaryTagValue",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "primaryTag":"{{PrimaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"primaryPatchGroupValue",
                  "Selector":"$.Payload.tagValue",
                  "Type":"String"
               }
            ],
            "nextStep":"patchPrimaryInstances"
         },
         {
            "name":"patchPrimaryInstances",
            "action":"aws:runCommand",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"AWS-RunPatchBaseline",
               "Parameters":{
                  "SnapshotId":"{{SnapshotId}}",
                  "RebootOption":"{{RebootOption}}",
                  "Operation":"{{Operation}}"
               },
               "Targets":[
                  {
                     "Key":"{{returnPrimaryTagKey.primaryPatchGroupKey}}",
                     "Values":[
                        "{{returnPrimaryTagValue.primaryPatchGroupValue}}"
                     ]
                  }
               ],
               "MaxConcurrency":"10%",
               "MaxErrors":"10%"
            },
            "nextStep":"returnPrimaryToOriginalState"
         },
   ```

------

1. Nach Abschluss des Patching-Voragngs möchte Emily, dass die Automatisierung die Ziel-Instances, die dem im `PrimaryPatchGroupTag`-Parameter angegebenen Tag zugeordnet sind, in den Zustand zurückversetzt, in dem sie sich vor dem Automatisierungsstart befanden. Sie tut dies, indem sie erneut die Ausgabe der ersten Aktion in einem Skript verwendet. Basierend auf dem ursprünglichen Zustand der Ziel-Instance, wenn sich die Instance zuvor in einem anderen Zustand als `running` befand, wird die Instance angehalten. Wenn der Instance-Status bereits `running` ist, durchläuft das Skript weiterhin die verbleibenden Instances.

------
#### [ YAML ]

   ```
   - name: returnPrimaryToOriginalState
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnToOriginalState
         InputPayload:
           targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}'
         Script: |-
           def returnToOriginalState(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping':
                   ec2.stop_instances(
                       InstanceIds=[instance]
                       )
               else:
                 pass
       nextStep: getSecondaryInstanceState
   ```

------
#### [ JSON ]

   ```
   {
            "name":"returnPrimaryToOriginalState",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnToOriginalState",
               "InputPayload":{
                  "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"getSecondaryInstanceState"
         },
   ```

------

1. Der Patchvorgang wird für die Instances abgeschlossen, die mit dem Tag verknüpft sind, das im `PrimaryPatchGroupTag`-Parameter angegeben ist. Jetzt dupliziert Emily alle vorherigen Aktionen in ihrem Runbook-Inhalt, um auf die Instances abzuzielen, die dem im `SecondaryPatchGroupTag`-Parameter angegebenen Tag zugeordnet sind.

------
#### [ YAML ]

   ```
   - name: getSecondaryInstanceState
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: getInstanceStates
         InputPayload:
           secondaryTag: '{{SecondaryPatchGroupTag}}'
         Script: |-
           def getInstanceStates(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             tag = events['secondaryTag']
             tagKey, tagValue = list(tag.items())[0]
             instanceQuery = ec2.describe_instances(
             Filters=[
                 {
                     "Name": "tag:" + tagKey,
                     "Values": [tagValue]
                 }]
             )
             if not instanceQuery['Reservations']:
                 noInstancesForTagString = "No instances found for specified tag."
                 return({ 'noInstancesFound' : noInstancesForTagString })
             else:
                 queryResponse = instanceQuery['Reservations']
                 originalInstanceStates = {}
                 for results in queryResponse:
                     instanceSet = results['Instances']
                     for instance in instanceSet:
                         instanceId = instance['InstanceId']
                         originalInstanceStates[instanceId] = instance['State']['Name']
                 return originalInstanceStates
       outputs:
         - Name: originalInstanceStates
           Selector: $.Payload
           Type: StringMap
       nextStep: verifySecondaryInstancesRunning
     - name: verifySecondaryInstancesRunning
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: verifyInstancesRunning
         InputPayload:
           targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}'
         Script: |-
           def verifyInstancesRunning(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped':
                   print("The target instance " + instance + " is stopped. The instance will now be started.")
                   ec2.start_instances(
                       InstanceIds=[instance]
                       )
               elif instanceDict[instance] == 'stopping':
                   print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.")
                   while instanceDict[instance] != 'stopped':
                       poll = ec2.get_waiter('instance_stopped')
                       poll.wait(
                           InstanceIds=[instance]
                       )
                   ec2.start_instances(
                       InstanceIds=[instance]
                   )
               else:
                 pass
       nextStep: waitForSecondaryRunningInstances
     - name: waitForSecondaryRunningInstances
       action: 'aws:executeScript'
       timeoutSeconds: 300
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: waitForRunningInstances
         InputPayload:
           targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}'
         Script: |-
           def waitForRunningInstances(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
                 poll = ec2.get_waiter('instance_running')
                 poll.wait(
                     InstanceIds=[instance]
                 )
       nextStep: returnSecondaryTagKey
     - name: returnSecondaryTagKey
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           secondaryTag: '{{SecondaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['secondaryTag']
             tagKey = list(tag)[0]
             stringKey = "tag:" + tagKey
             return {'tagKey' : stringKey}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: secondaryPatchGroupKey
           Selector: $.Payload.tagKey
           Type: String
       nextStep: returnSecondaryTagValue
     - name: returnSecondaryTagValue
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           secondaryTag: '{{SecondaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['secondaryTag']
             tagKey = list(tag)[0]
             tagValue = tag[tagKey]
             return {'tagValue' : tagValue}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: secondaryPatchGroupValue
           Selector: $.Payload.tagValue
           Type: String
       nextStep: patchSecondaryInstances
     - name: patchSecondaryInstances
       action: 'aws:runCommand'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: AWS-RunPatchBaseline
         Parameters:
           SnapshotId: '{{SnapshotId}}'
           RebootOption: '{{RebootOption}}'
           Operation: '{{Operation}}'
         Targets:
           - Key: '{{returnSecondaryTagKey.secondaryPatchGroupKey}}'
             Values:
             - '{{returnSecondaryTagValue.secondaryPatchGroupValue}}'
         MaxConcurrency: 10%
         MaxErrors: 10%
       nextStep: returnSecondaryToOriginalState
     - name: returnSecondaryToOriginalState
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnToOriginalState
         InputPayload:
           targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}'
         Script: |-
           def returnToOriginalState(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping':
                   ec2.stop_instances(
                       InstanceIds=[instance]
                       )
               else:
                 pass
   ```

------
#### [ JSON ]

   ```
   {
            "name":"getSecondaryInstanceState",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"getInstanceStates",
               "InputPayload":{
                  "secondaryTag":"{{SecondaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"originalInstanceStates",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               }
            ],
            "nextStep":"verifySecondaryInstancesRunning"
         },
         {
            "name":"verifySecondaryInstancesRunning",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"verifyInstancesRunning",
               "InputPayload":{
                  "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"waitForSecondaryRunningInstances"
         },
         {
            "name":"waitForSecondaryRunningInstances",
            "action":"aws:executeScript",
            "timeoutSeconds":300,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"waitForRunningInstances",
               "InputPayload":{
                  "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"returnSecondaryTagKey"
         },
         {
            "name":"returnSecondaryTagKey",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "secondaryTag":"{{SecondaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"secondaryPatchGroupKey",
                  "Selector":"$.Payload.tagKey",
                  "Type":"String"
               }
            ],
            "nextStep":"returnSecondaryTagValue"
         },
         {
            "name":"returnSecondaryTagValue",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "secondaryTag":"{{SecondaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"secondaryPatchGroupValue",
                  "Selector":"$.Payload.tagValue",
                  "Type":"String"
               }
            ],
            "nextStep":"patchSecondaryInstances"
         },
         {
            "name":"patchSecondaryInstances",
            "action":"aws:runCommand",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"AWS-RunPatchBaseline",
               "Parameters":{
                  "SnapshotId":"{{SnapshotId}}",
                  "RebootOption":"{{RebootOption}}",
                  "Operation":"{{Operation}}"
               },
               "Targets":[
                  {
                     "Key":"{{returnSecondaryTagKey.secondaryPatchGroupKey}}",
                     "Values":[
                        "{{returnSecondaryTagValue.secondaryPatchGroupValue}}"
                     ]
                  }
               ],
               "MaxConcurrency":"10%",
               "MaxErrors":"10%"
            },
            "nextStep":"returnSecondaryToOriginalState"
         },
         {
            "name":"returnSecondaryToOriginalState",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnToOriginalState",
               "InputPayload":{
                  "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            }
         }
      ]
   }
   ```

------

1. Emily überprüft den fertigen skriptbasierten Runbook-Inhalt und erstellt das Runbook in derselben AWS-Konto und AWS-Region wie die Ziel-Instances. Jetzt ist sie bereit, ihr Runbook zu testen, um sicherzustellen, dass die Automatisierung wie gewünscht funktioniert, bevor es in ihre Produktionsumgebung implementiert wird. Im Folgenden finden Sie den vollständigen geskripteten Runbook-Inhalt.

------
#### [ YAML ]

   ```
   description: An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.
   schemaVersion: '0.3'
   assumeRole: '{{AutomationAssumeRole}}'
   parameters:
     AutomationAssumeRole:
       type: String
       description: '(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.'
     PrimaryPatchGroupTag:
       type: StringMap
       description: '(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}'
     SecondaryPatchGroupTag:
       type: StringMap
       description: '(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}'
     SnapshotId:
       type: String
       description: '(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.'
       default: ''
     RebootOption:
       type: String
       description: '(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.'
       allowedValues:
         - NoReboot
         - RebootIfNeeded
       default: RebootIfNeeded
     Operation:
       type: String
       description: '(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.'
       allowedValues:
         - Install
         - Scan
       default: Install
   mainSteps:
     - name: getPrimaryInstanceState
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: getInstanceStates
         InputPayload:
           primaryTag: '{{PrimaryPatchGroupTag}}'
         Script: |-
           def getInstanceStates(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             tag = events['primaryTag']
             tagKey, tagValue = list(tag.items())[0]
             instanceQuery = ec2.describe_instances(
             Filters=[
                 {
                     "Name": "tag:" + tagKey,
                     "Values": [tagValue]
                 }]
             )
             if not instanceQuery['Reservations']:
                 noInstancesForTagString = "No instances found for specified tag."
                 return({ 'noInstancesFound' : noInstancesForTagString })
             else:
                 queryResponse = instanceQuery['Reservations']
                 originalInstanceStates = {}
                 for results in queryResponse:
                     instanceSet = results['Instances']
                     for instance in instanceSet:
                         instanceId = instance['InstanceId']
                         originalInstanceStates[instanceId] = instance['State']['Name']
                 return originalInstanceStates
       outputs:
         - Name: originalInstanceStates
           Selector: $.Payload
           Type: StringMap
       nextStep: verifyPrimaryInstancesRunning
     - name: verifyPrimaryInstancesRunning
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: verifyInstancesRunning
         InputPayload:
           targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}'
         Script: |-
           def verifyInstancesRunning(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped':
                   print("The target instance " + instance + " is stopped. The instance will now be started.")
                   ec2.start_instances(
                       InstanceIds=[instance]
                       )
               elif instanceDict[instance] == 'stopping':
                   print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.")
                   while instanceDict[instance] != 'stopped':
                       poll = ec2.get_waiter('instance_stopped')
                       poll.wait(
                           InstanceIds=[instance]
                       )
                   ec2.start_instances(
                       InstanceIds=[instance]
                   )
               else:
                 pass
       nextStep: waitForPrimaryRunningInstances
     - name: waitForPrimaryRunningInstances
       action: 'aws:executeScript'
       timeoutSeconds: 300
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: waitForRunningInstances
         InputPayload:
           targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}'
         Script: |-
           def waitForRunningInstances(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
                 poll = ec2.get_waiter('instance_running')
                 poll.wait(
                     InstanceIds=[instance]
                 )
       nextStep: returnPrimaryTagKey
     - name: returnPrimaryTagKey
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           primaryTag: '{{PrimaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['primaryTag']
             tagKey = list(tag)[0]
             stringKey = "tag:" + tagKey
             return {'tagKey' : stringKey}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: primaryPatchGroupKey
           Selector: $.Payload.tagKey
           Type: String
       nextStep: returnPrimaryTagValue
     - name: returnPrimaryTagValue
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           primaryTag: '{{PrimaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['primaryTag']
             tagKey = list(tag)[0]
             tagValue = tag[tagKey]
             return {'tagValue' : tagValue}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: primaryPatchGroupValue
           Selector: $.Payload.tagValue
           Type: String
       nextStep: patchPrimaryInstances
     - name: patchPrimaryInstances
       action: 'aws:runCommand'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: AWS-RunPatchBaseline
         Parameters:
           SnapshotId: '{{SnapshotId}}'
           RebootOption: '{{RebootOption}}'
           Operation: '{{Operation}}'
         Targets:
           - Key: '{{returnPrimaryTagKey.primaryPatchGroupKey}}'
             Values:
               - '{{returnPrimaryTagValue.primaryPatchGroupValue}}'
         MaxConcurrency: 10%
         MaxErrors: 10%
       nextStep: returnPrimaryToOriginalState
     - name: returnPrimaryToOriginalState
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnToOriginalState
         InputPayload:
           targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}'
         Script: |-
           def returnToOriginalState(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping':
                   ec2.stop_instances(
                       InstanceIds=[instance]
                       )
               else:
                 pass
       nextStep: getSecondaryInstanceState
     - name: getSecondaryInstanceState
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: getInstanceStates
         InputPayload:
           secondaryTag: '{{SecondaryPatchGroupTag}}'
         Script: |-
           def getInstanceStates(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             tag = events['secondaryTag']
             tagKey, tagValue = list(tag.items())[0]
             instanceQuery = ec2.describe_instances(
             Filters=[
                 {
                     "Name": "tag:" + tagKey,
                     "Values": [tagValue]
                 }]
             )
             if not instanceQuery['Reservations']:
                 noInstancesForTagString = "No instances found for specified tag."
                 return({ 'noInstancesFound' : noInstancesForTagString })
             else:
                 queryResponse = instanceQuery['Reservations']
                 originalInstanceStates = {}
                 for results in queryResponse:
                     instanceSet = results['Instances']
                     for instance in instanceSet:
                         instanceId = instance['InstanceId']
                         originalInstanceStates[instanceId] = instance['State']['Name']
                 return originalInstanceStates
       outputs:
         - Name: originalInstanceStates
           Selector: $.Payload
           Type: StringMap
       nextStep: verifySecondaryInstancesRunning
     - name: verifySecondaryInstancesRunning
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: verifyInstancesRunning
         InputPayload:
           targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}'
         Script: |-
           def verifyInstancesRunning(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped':
                   print("The target instance " + instance + " is stopped. The instance will now be started.")
                   ec2.start_instances(
                       InstanceIds=[instance]
                       )
               elif instanceDict[instance] == 'stopping':
                   print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.")
                   while instanceDict[instance] != 'stopped':
                       poll = ec2.get_waiter('instance_stopped')
                       poll.wait(
                           InstanceIds=[instance]
                       )
                   ec2.start_instances(
                       InstanceIds=[instance]
                   )
               else:
                 pass
       nextStep: waitForSecondaryRunningInstances
     - name: waitForSecondaryRunningInstances
       action: 'aws:executeScript'
       timeoutSeconds: 300
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: waitForRunningInstances
         InputPayload:
           targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}'
         Script: |-
           def waitForRunningInstances(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
                 poll = ec2.get_waiter('instance_running')
                 poll.wait(
                     InstanceIds=[instance]
                 )
       nextStep: returnSecondaryTagKey
     - name: returnSecondaryTagKey
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           secondaryTag: '{{SecondaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['secondaryTag']
             tagKey = list(tag)[0]
             stringKey = "tag:" + tagKey
             return {'tagKey' : stringKey}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: secondaryPatchGroupKey
           Selector: $.Payload.tagKey
           Type: String
       nextStep: returnSecondaryTagValue
     - name: returnSecondaryTagValue
       action: 'aws:executeScript'
       timeoutSeconds: 120
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnTagValues
         InputPayload:
           secondaryTag: '{{SecondaryPatchGroupTag}}'
         Script: |-
           def returnTagValues(events,context):
             tag = events['secondaryTag']
             tagKey = list(tag)[0]
             tagValue = tag[tagKey]
             return {'tagValue' : tagValue}
       outputs:
         - Name: Payload
           Selector: $.Payload
           Type: StringMap
         - Name: secondaryPatchGroupValue
           Selector: $.Payload.tagValue
           Type: String
       nextStep: patchSecondaryInstances
     - name: patchSecondaryInstances
       action: 'aws:runCommand'
       onFailure: Abort
       timeoutSeconds: 7200
       inputs:
         DocumentName: AWS-RunPatchBaseline
         Parameters:
           SnapshotId: '{{SnapshotId}}'
           RebootOption: '{{RebootOption}}'
           Operation: '{{Operation}}'
         Targets:
           - Key: '{{returnSecondaryTagKey.secondaryPatchGroupKey}}'
             Values:
             - '{{returnSecondaryTagValue.secondaryPatchGroupValue}}'
         MaxConcurrency: 10%
         MaxErrors: 10%
       nextStep: returnSecondaryToOriginalState
     - name: returnSecondaryToOriginalState
       action: 'aws:executeScript'
       timeoutSeconds: 600
       onFailure: Abort
       inputs:
         Runtime: python3.11
         Handler: returnToOriginalState
         InputPayload:
           targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}'
         Script: |-
           def returnToOriginalState(events,context):
             import boto3
   
             #Initialize client
             ec2 = boto3.client('ec2')
             instanceDict = events['targetInstances']
             for instance in instanceDict:
               if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping':
                   ec2.stop_instances(
                       InstanceIds=[instance]
                       )
               else:
                 pass
   ```

------
#### [ JSON ]

   ```
   {
      "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.",
      "schemaVersion":"0.3",
      "assumeRole":"{{AutomationAssumeRole}}",
      "parameters":{
         "AutomationAssumeRole":{
            "type":"String",
            "description":"(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook."
         },
         "PrimaryPatchGroupTag":{
            "type":"StringMap",
            "description":"(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}"
         },
         "SecondaryPatchGroupTag":{
            "type":"StringMap",
            "description":"(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}"
         },
         "SnapshotId":{
            "type":"String",
            "description":"(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.",
            "default":""
         },
         "RebootOption":{
            "type":"String",
            "description":"(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.",
            "allowedValues":[
               "NoReboot",
               "RebootIfNeeded"
            ],
            "default":"RebootIfNeeded"
         },
         "Operation":{
            "type":"String",
            "description":"(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.",
            "allowedValues":[
               "Install",
               "Scan"
            ],
            "default":"Install"
         }
      },
      "mainSteps":[
         {
            "name":"getPrimaryInstanceState",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"getInstanceStates",
               "InputPayload":{
                  "primaryTag":"{{PrimaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"originalInstanceStates",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               }
            ],
            "nextStep":"verifyPrimaryInstancesRunning"
         },
         {
            "name":"verifyPrimaryInstancesRunning",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"verifyInstancesRunning",
               "InputPayload":{
                  "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"waitForPrimaryRunningInstances"
         },
         {
            "name":"waitForPrimaryRunningInstances",
            "action":"aws:executeScript",
            "timeoutSeconds":300,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"waitForRunningInstances",
               "InputPayload":{
                  "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"returnPrimaryTagKey"
         },
         {
            "name":"returnPrimaryTagKey",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "primaryTag":"{{PrimaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"primaryPatchGroupKey",
                  "Selector":"$.Payload.tagKey",
                  "Type":"String"
               }
            ],
            "nextStep":"returnPrimaryTagValue"
         },
         {
            "name":"returnPrimaryTagValue",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "primaryTag":"{{PrimaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"primaryPatchGroupValue",
                  "Selector":"$.Payload.tagValue",
                  "Type":"String"
               }
            ],
            "nextStep":"patchPrimaryInstances"
         },
         {
            "name":"patchPrimaryInstances",
            "action":"aws:runCommand",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"AWS-RunPatchBaseline",
               "Parameters":{
                  "SnapshotId":"{{SnapshotId}}",
                  "RebootOption":"{{RebootOption}}",
                  "Operation":"{{Operation}}"
               },
               "Targets":[
                  {
                     "Key":"{{returnPrimaryTagKey.primaryPatchGroupKey}}",
                     "Values":[
                        "{{returnPrimaryTagValue.primaryPatchGroupValue}}"
                     ]
                  }
               ],
               "MaxConcurrency":"10%",
               "MaxErrors":"10%"
            },
            "nextStep":"returnPrimaryToOriginalState"
         },
         {
            "name":"returnPrimaryToOriginalState",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnToOriginalState",
               "InputPayload":{
                  "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"getSecondaryInstanceState"
         },
         {
            "name":"getSecondaryInstanceState",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"getInstanceStates",
               "InputPayload":{
                  "secondaryTag":"{{SecondaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"originalInstanceStates",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               }
            ],
            "nextStep":"verifySecondaryInstancesRunning"
         },
         {
            "name":"verifySecondaryInstancesRunning",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"verifyInstancesRunning",
               "InputPayload":{
                  "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"waitForSecondaryRunningInstances"
         },
         {
            "name":"waitForSecondaryRunningInstances",
            "action":"aws:executeScript",
            "timeoutSeconds":300,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"waitForRunningInstances",
               "InputPayload":{
                  "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            },
            "nextStep":"returnSecondaryTagKey"
         },
         {
            "name":"returnSecondaryTagKey",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "secondaryTag":"{{SecondaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"secondaryPatchGroupKey",
                  "Selector":"$.Payload.tagKey",
                  "Type":"String"
               }
            ],
            "nextStep":"returnSecondaryTagValue"
         },
         {
            "name":"returnSecondaryTagValue",
            "action":"aws:executeScript",
            "timeoutSeconds":120,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnTagValues",
               "InputPayload":{
                  "secondaryTag":"{{SecondaryPatchGroupTag}}"
               },
               "Script":"..."
            },
            "outputs":[
               {
                  "Name":"Payload",
                  "Selector":"$.Payload",
                  "Type":"StringMap"
               },
               {
                  "Name":"secondaryPatchGroupValue",
                  "Selector":"$.Payload.tagValue",
                  "Type":"String"
               }
            ],
            "nextStep":"patchSecondaryInstances"
         },
         {
            "name":"patchSecondaryInstances",
            "action":"aws:runCommand",
            "onFailure":"Abort",
            "timeoutSeconds":7200,
            "inputs":{
               "DocumentName":"AWS-RunPatchBaseline",
               "Parameters":{
                  "SnapshotId":"{{SnapshotId}}",
                  "RebootOption":"{{RebootOption}}",
                  "Operation":"{{Operation}}"
               },
               "Targets":[
                  {
                     "Key":"{{returnSecondaryTagKey.secondaryPatchGroupKey}}",
                     "Values":[
                        "{{returnSecondaryTagValue.secondaryPatchGroupValue}}"
                     ]
                  }
               ],
               "MaxConcurrency":"10%",
               "MaxErrors":"10%"
            },
            "nextStep":"returnSecondaryToOriginalState"
         },
         {
            "name":"returnSecondaryToOriginalState",
            "action":"aws:executeScript",
            "timeoutSeconds":600,
            "onFailure":"Abort",
            "inputs":{
               "Runtime":"python3.11",
               "Handler":"returnToOriginalState",
               "InputPayload":{
                  "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}"
               },
               "Script":"..."
            }
         }
      ]
   }
   ```

------

Weitere Informationen zu den hier verwendeten Automation-Aktionen finden Sie unter [Systems Manager Automation Aktionen-Referenz](automation-actions.md).

# Weitere Runbook-Beispiele
<a name="automation-document-examples"></a>

Das folgende Beispiel-Runbook zeigt, wie Sie AWS Systems Manager Automatisierungsaktionen verwenden können, um allgemeine Bereitstellungs-, Problembehandlungs- und Wartungsaufgaben zu automatisieren.

**Anmerkung**  
Die Beispiel-Runbooks in diesem Abschnitt werden bereitgestellt, um zu veranschaulichen, wie Sie benutzerdefinierte Runbooks erstellen können, um Ihre spezifischen Betriebsanforderungen zu erfüllen. Diese Runbooks sind nicht für den Einsatz in Produktionsumgebungen vorgesehen. Sie können sie jedoch für Ihren eigenen Gebrauch anpassen.

**Topics**
+ [Bereitstellung der VPC-Architektur und der Microsoft Active Directory-Domänencontroller](automation-document-architecture-deployment-example.md)
+ [Wiederherstellen eines Root-Volumes aus dem letzten Snapshot](automation-document-instance-recovery-example.md)
+ [Erstellen eines AMI und einer regionenübergreifenden Kopie](automation-document-backup-maintenance-example.md)

# Bereitstellung der VPC-Architektur und der Microsoft Active Directory-Domänencontroller
<a name="automation-document-architecture-deployment-example"></a>

Um die Effizienz zu steigern und allgemeine Aufgaben zu standardisieren, können Sie sich für die Automatisierung von Bereitstellungen entscheiden. Dies ist nützlich, wenn Sie regelmäßig dieselbe Architektur für mehrere Konten bereitstellen und AWS-Regionen. Durch die Automatisierung von Architekturbereitstellungen kann auch das Risiko menschlicher Fehler verringert werden, die bei der manuellen Bereitstellung der Architektur auftreten können. AWS Systems Manager Automatisierungsaktionen können Ihnen dabei helfen, dies zu erreichen. Automation ist ein Tool in AWS Systems Manager.

Das folgende AWS Systems Manager Beispiel-Runbook führt diese Aktionen aus:
+ Ruft das neueste Windows Server 2016 Amazon Machine Image (AMI) mithilfe von Systems Manager Parameter Store ab, das beim Starten der EC2-Instances verwendet wird, die als Domaincontroller konfiguriert werden. Parameter Store ist ein Tool in AWS Systems Manager.
+ Verwendet die `aws:executeAwsApi` Automatisierungsaktion, um mehrere AWS API-Operationen aufzurufen, um die VPC-Architektur zu erstellen. Die Domänencontroller-Instances werden in privaten Subnetzen gestartet und stellen über ein NAT-Gateway eine Verbindung zum Internet her. Dies ermöglicht dem SSM Agent auf den Instances auf die erforderlichen Systems Manager Endpunkte zuzugreifen.
+ Verwendet die `aws:waitForAwsResourceProperty` Automatisierungsaktion, um zu bestätigen, dass die durch die vorherige Aktion gestarteten Instances `Online` für AWS Systems Manager gelten.
+ Verwendet die `aws:runCommand` Automatisierungsaktion zur Konfiguration der als Microsoft Active Directory-Domänencontroller gestarteten Instances.

------
#### [ YAML ]

```
    ---
    description: Custom Automation Deployment Example
    schemaVersion: '0.3'
    parameters:
      AutomationAssumeRole:
        type: String
        default: ''
        description: >-
          (Optional) The ARN of the role that allows Automation to perform the
          actions on your behalf. If no role is specified, Systems Manager
          Automation uses your IAM permissions to run this runbook.
    mainSteps:
      - name: getLatestWindowsAmi
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ssm
          Api: GetParameter
          Name: >-
            /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base
        outputs:
          - Name: amiId
            Selector: $.Parameter.Value
            Type: String
        nextStep: createSSMInstanceRole
      - name: createSSMInstanceRole
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: iam
          Api: CreateRole
          AssumeRolePolicyDocument: >-
            {"Version": "2012-10-17",		 	 	 "Statement":[{"Effect":"Allow","Principal":{"Service":["ec2.amazonaws.com"]},"Action":["sts:AssumeRole"]}]}
          RoleName: sampleSSMInstanceRole
        nextStep: attachManagedSSMPolicy
      - name: attachManagedSSMPolicy
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: iam
          Api: AttachRolePolicy
          PolicyArn: 'arn:aws:iam::aws:policy/service-role/AmazonSSMManagedInstanceCore'
          RoleName: sampleSSMInstanceRole
        nextStep: createSSMInstanceProfile
      - name: createSSMInstanceProfile
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: iam
          Api: CreateInstanceProfile
          InstanceProfileName: sampleSSMInstanceRole
        outputs:
          - Name: instanceProfileArn
            Selector: $.InstanceProfile.Arn
            Type: String
        nextStep: addSSMInstanceRoleToProfile
      - name: addSSMInstanceRoleToProfile
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: iam
          Api: AddRoleToInstanceProfile
          InstanceProfileName: sampleSSMInstanceRole
          RoleName: sampleSSMInstanceRole
        nextStep: createVpc
      - name: createVpc
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateVpc
          CidrBlock: 10.0.100.0/22
        outputs:
          - Name: vpcId
            Selector: $.Vpc.VpcId
            Type: String
        nextStep: getMainRtb
      - name: getMainRtb
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: DescribeRouteTables
          Filters:
            - Name: vpc-id
              Values:
                - '{{ createVpc.vpcId }}'
        outputs:
          - Name: mainRtbId
            Selector: '$.RouteTables[0].RouteTableId'
            Type: String
        nextStep: verifyMainRtb
      - name: verifyMainRtb
        action: aws:assertAwsResourceProperty
        onFailure: Abort
        inputs:
          Service: ec2
          Api: DescribeRouteTables
          RouteTableIds:
            - '{{ getMainRtb.mainRtbId }}'
          PropertySelector: '$.RouteTables[0].Associations[0].Main'
          DesiredValues:
            - 'True'
        nextStep: createPubSubnet
      - name: createPubSubnet
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateSubnet
          CidrBlock: 10.0.103.0/24
          AvailabilityZone: us-west-2c
          VpcId: '{{ createVpc.vpcId }}'
        outputs:
          - Name: pubSubnetId
            Selector: $.Subnet.SubnetId
            Type: String
        nextStep: createPubRtb
      - name: createPubRtb
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateRouteTable
          VpcId: '{{ createVpc.vpcId }}'
        outputs:
          - Name: pubRtbId
            Selector: $.RouteTable.RouteTableId
            Type: String
        nextStep: createIgw
      - name: createIgw
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateInternetGateway
        outputs:
          - Name: igwId
            Selector: $.InternetGateway.InternetGatewayId
            Type: String
        nextStep: attachIgw
      - name: attachIgw
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: AttachInternetGateway
          InternetGatewayId: '{{ createIgw.igwId }}'
          VpcId: '{{ createVpc.vpcId }}'
        nextStep: allocateEip
      - name: allocateEip
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: AllocateAddress
          Domain: vpc
        outputs:
          - Name: eipAllocationId
            Selector: $.AllocationId
            Type: String
        nextStep: createNatGw
      - name: createNatGw
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateNatGateway
          AllocationId: '{{ allocateEip.eipAllocationId }}'
          SubnetId: '{{ createPubSubnet.pubSubnetId }}'
        outputs:
          - Name: natGwId
            Selector: $.NatGateway.NatGatewayId
            Type: String
        nextStep: verifyNatGwAvailable
      - name: verifyNatGwAvailable
        action: aws:waitForAwsResourceProperty
        timeoutSeconds: 150
        inputs:
          Service: ec2
          Api: DescribeNatGateways
          NatGatewayIds:
            - '{{ createNatGw.natGwId }}'
          PropertySelector: '$.NatGateways[0].State'
          DesiredValues:
            - available
        nextStep: createNatRoute
      - name: createNatRoute
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateRoute
          DestinationCidrBlock: 0.0.0.0/0
          NatGatewayId: '{{ createNatGw.natGwId }}'
          RouteTableId: '{{ getMainRtb.mainRtbId }}'
        nextStep: createPubRoute
      - name: createPubRoute
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateRoute
          DestinationCidrBlock: 0.0.0.0/0
          GatewayId: '{{ createIgw.igwId }}'
          RouteTableId: '{{ createPubRtb.pubRtbId }}'
        nextStep: setPubSubAssoc
      - name: setPubSubAssoc
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: AssociateRouteTable
          RouteTableId: '{{ createPubRtb.pubRtbId }}'
          SubnetId: '{{ createPubSubnet.pubSubnetId }}'
      - name: createDhcpOptions
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateDhcpOptions
          DhcpConfigurations:
            - Key: domain-name-servers
              Values:
                - '10.0.100.50,10.0.101.50'
            - Key: domain-name
              Values:
                - sample.com
        outputs:
          - Name: dhcpOptionsId
            Selector: $.DhcpOptions.DhcpOptionsId
            Type: String
        nextStep: createDCSubnet1
      - name: createDCSubnet1
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateSubnet
          CidrBlock: 10.0.100.0/24
          AvailabilityZone: us-west-2a
          VpcId: '{{ createVpc.vpcId }}'
        outputs:
          - Name: firstSubnetId
            Selector: $.Subnet.SubnetId
            Type: String
        nextStep: createDCSubnet2
      - name: createDCSubnet2
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateSubnet
          CidrBlock: 10.0.101.0/24
          AvailabilityZone: us-west-2b
          VpcId: '{{ createVpc.vpcId }}'
        outputs:
          - Name: secondSubnetId
            Selector: $.Subnet.SubnetId
            Type: String
        nextStep: createDCSecGroup
      - name: createDCSecGroup
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: CreateSecurityGroup
          GroupName: SampleDCSecGroup
          Description: Security Group for Sample Domain Controllers
          VpcId: '{{ createVpc.vpcId }}'
        outputs:
          - Name: dcSecGroupId
            Selector: $.GroupId
            Type: String
        nextStep: authIngressDCTraffic
      - name: authIngressDCTraffic
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: AuthorizeSecurityGroupIngress
          GroupId: '{{ createDCSecGroup.dcSecGroupId }}'
          IpPermissions:
            - FromPort: -1
              IpProtocol: '-1'
              IpRanges:
                - CidrIp: 0.0.0.0/0
                  Description: Allow all traffic between Domain Controllers
        nextStep: verifyInstanceProfile
      - name: verifyInstanceProfile
        action: aws:waitForAwsResourceProperty
        maxAttempts: 5
        onFailure: Abort
        inputs:
          Service: iam
          Api: ListInstanceProfilesForRole
          RoleName: sampleSSMInstanceRole
          PropertySelector: '$.InstanceProfiles[0].Arn'
          DesiredValues:
            - '{{ createSSMInstanceProfile.instanceProfileArn }}'
        nextStep: iamEventualConsistency
      - name: iamEventualConsistency
        action: aws:sleep
        inputs:
          Duration: PT2M
        nextStep: launchDC1
      - name: launchDC1
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: RunInstances
          BlockDeviceMappings:
            - DeviceName: /dev/sda1
              Ebs:
                DeleteOnTermination: true
                VolumeSize: 50
                VolumeType: gp2
            - DeviceName: xvdf
              Ebs:
                DeleteOnTermination: true
                VolumeSize: 100
                VolumeType: gp2
          IamInstanceProfile:
            Arn: '{{ createSSMInstanceProfile.instanceProfileArn }}'
          ImageId: '{{ getLatestWindowsAmi.amiId }}'
          InstanceType: t2.micro
          MaxCount: 1
          MinCount: 1
          PrivateIpAddress: 10.0.100.50
          SecurityGroupIds:
            - '{{ createDCSecGroup.dcSecGroupId }}'
          SubnetId: '{{ createDCSubnet1.firstSubnetId }}'
          TagSpecifications:
            - ResourceType: instance
              Tags:
                - Key: Name
                  Value: SampleDC1
        outputs:
          - Name: pdcInstanceId
            Selector: '$.Instances[0].InstanceId'
            Type: String
        nextStep: launchDC2
      - name: launchDC2
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: RunInstances
          BlockDeviceMappings:
            - DeviceName: /dev/sda1
              Ebs:
                DeleteOnTermination: true
                VolumeSize: 50
                VolumeType: gp2
            - DeviceName: xvdf
              Ebs:
                DeleteOnTermination: true
                VolumeSize: 100
                VolumeType: gp2
          IamInstanceProfile:
            Arn: '{{ createSSMInstanceProfile.instanceProfileArn }}'
          ImageId: '{{ getLatestWindowsAmi.amiId }}'
          InstanceType: t2.micro
          MaxCount: 1
          MinCount: 1
          PrivateIpAddress: 10.0.101.50
          SecurityGroupIds:
            - '{{ createDCSecGroup.dcSecGroupId }}'
          SubnetId: '{{ createDCSubnet2.secondSubnetId }}'
          TagSpecifications:
            - ResourceType: instance
              Tags:
                - Key: Name
                  Value: SampleDC2
        outputs:
          - Name: adcInstanceId
            Selector: '$.Instances[0].InstanceId'
            Type: String
        nextStep: verifyDCInstanceState
      - name: verifyDCInstanceState
        action: aws:waitForAwsResourceProperty
        inputs:
          Service: ec2
          Api: DescribeInstanceStatus
          IncludeAllInstances: true
          InstanceIds:
            - '{{ launchDC1.pdcInstanceId }}'
            - '{{ launchDC2.adcInstanceId }}'
          PropertySelector: '$.InstanceStatuses..InstanceState.Name'
          DesiredValues:
            - running
        nextStep: verifyInstancesOnlineSSM
      - name: verifyInstancesOnlineSSM
        action: aws:waitForAwsResourceProperty
        timeoutSeconds: 600
        inputs:
          Service: ssm
          Api: DescribeInstanceInformation
          InstanceInformationFilterList:
            - key: InstanceIds
              valueSet:
                - '{{ launchDC1.pdcInstanceId }}'
                - '{{ launchDC2.adcInstanceId }}'
          PropertySelector: '$.InstanceInformationList..PingStatus'
          DesiredValues:
            - Online
        nextStep: installADRoles
      - name: installADRoles
        action: aws:runCommand
        inputs:
          DocumentName: AWS-RunPowerShellScript
          InstanceIds:
            - '{{ launchDC1.pdcInstanceId }}'
            - '{{ launchDC2.adcInstanceId }}'
          Parameters:
            commands: |-
              try {
                  Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools
              }
              catch {
                  Write-Error "Failed to install ADDS Role."
              }
        nextStep: setAdminPassword
      - name: setAdminPassword
        action: aws:runCommand
        inputs:
          DocumentName: AWS-RunPowerShellScript
          InstanceIds:
            - '{{ launchDC1.pdcInstanceId }}'
          Parameters:
            commands:
              - net user Administrator "sampleAdminPass123!"
        nextStep: createForest
      - name: createForest
        action: aws:runCommand
        inputs:
          DocumentName: AWS-RunPowerShellScript
          InstanceIds:
            - '{{ launchDC1.pdcInstanceId }}'
          Parameters:
            commands: |-
              $dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force
              try {
                  Install-ADDSForest -DomainName "sample.com" -DomainMode 6 -ForestMode 6 -InstallDNS -DatabasePath "D:\NTDS" -SysvolPath "D:\SYSVOL" -SafeModeAdministratorPassword $dsrmPass -Force
              }
              catch {
                  Write-Error $_
              }
              try {
                  Add-DnsServerForwarder -IPAddress "10.0.100.2"
              }
              catch {
                  Write-Error $_
              }
        nextStep: associateDhcpOptions
      - name: associateDhcpOptions
        action: aws:executeAwsApi
        onFailure: Abort
        inputs:
          Service: ec2
          Api: AssociateDhcpOptions
          DhcpOptionsId: '{{ createDhcpOptions.dhcpOptionsId }}'
          VpcId: '{{ createVpc.vpcId }}'
        nextStep: waitForADServices
      - name: waitForADServices
        action: aws:sleep
        inputs:
          Duration: PT1M
        nextStep: promoteADC
      - name: promoteADC
        action: aws:runCommand
        inputs:
          DocumentName: AWS-RunPowerShellScript
          InstanceIds:
            - '{{ launchDC2.adcInstanceId }}'
          Parameters:
            commands: |-
              ipconfig /renew
              $dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force
              $domAdminUser = "sample\Administrator"
              $domAdminPass = "sampleAdminPass123!" | ConvertTo-SecureString -asPlainText -Force
              $domAdminCred = New-Object System.Management.Automation.PSCredential($domAdminUser,$domAdminPass)
    
              try {
                  Install-ADDSDomainController -DomainName "sample.com" -InstallDNS -DatabasePath "D:\NTDS" -SysvolPath "D:\SYSVOL" -SafeModeAdministratorPassword $dsrmPass -Credential $domAdminCred -Force
              }
              catch {
                  Write-Error $_
              }
```

------
#### [ JSON ]

```
{
      "description": "Custom Automation Deployment Example",
      "schemaVersion": "0.3",
      "assumeRole": "{{ AutomationAssumeRole }}",
      "parameters": {
        "AutomationAssumeRole": {
          "type": "String",
          "description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to run this runbook.",
          "default": ""
        }
      },
      "mainSteps": [
        {
          "name": "getLatestWindowsAmi",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ssm",
            "Api": "GetParameter",
            "Name": "/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base"
          },
          "outputs": [
            {
              "Name": "amiId",
              "Selector": "$.Parameter.Value",
              "Type": "String"
            }
          ],
          "nextStep": "createSSMInstanceRole"
        },
        {
          "name": "createSSMInstanceRole",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "iam",
            "Api": "CreateRole",
            "AssumeRolePolicyDocument": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}",
            "RoleName": "sampleSSMInstanceRole"
          },
          "nextStep": "attachManagedSSMPolicy"
        },
        {
          "name": "attachManagedSSMPolicy",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "iam",
            "Api": "AttachRolePolicy",
            "PolicyArn": "arn:aws:iam::aws:policy/service-role/AmazonSSMManagedInstanceCore",
            "RoleName": "sampleSSMInstanceRole"
          },
          "nextStep": "createSSMInstanceProfile"
        },
        {
          "name": "createSSMInstanceProfile",
          "action":"aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "iam",
            "Api": "CreateInstanceProfile",
            "InstanceProfileName": "sampleSSMInstanceRole"
          },
          "outputs": [
            {
              "Name": "instanceProfileArn",
              "Selector": "$.InstanceProfile.Arn",
              "Type": "String"
            }
          ],
          "nextStep": "addSSMInstanceRoleToProfile"
        },
        {
          "name": "addSSMInstanceRoleToProfile",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "iam",
            "Api": "AddRoleToInstanceProfile",
            "InstanceProfileName": "sampleSSMInstanceRole",
            "RoleName": "sampleSSMInstanceRole"
          },
          "nextStep": "createVpc"
        },
        {
          "name": "createVpc",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateVpc",
            "CidrBlock": "10.0.100.0/22"
          },
          "outputs": [
            {
              "Name": "vpcId",
              "Selector": "$.Vpc.VpcId",
              "Type": "String"
            }
          ],
          "nextStep": "getMainRtb"
        },
        {
          "name": "getMainRtb",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "DescribeRouteTables",
            "Filters": [
              {
                "Name": "vpc-id",
                "Values": ["{{ createVpc.vpcId }}"]
              }
            ]
          },
          "outputs": [
            {
              "Name": "mainRtbId",
              "Selector": "$.RouteTables[0].RouteTableId",
              "Type": "String"
            }
          ],
          "nextStep": "verifyMainRtb"
        },
        {
          "name": "verifyMainRtb",
          "action": "aws:assertAwsResourceProperty",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "DescribeRouteTables",
            "RouteTableIds": ["{{ getMainRtb.mainRtbId }}"],
            "PropertySelector": "$.RouteTables[0].Associations[0].Main",
            "DesiredValues": ["True"]
          },
          "nextStep": "createPubSubnet"
        },
        {
          "name": "createPubSubnet",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateSubnet",
            "CidrBlock": "10.0.103.0/24",
            "AvailabilityZone": "us-west-2c",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "outputs":[
            {
              "Name": "pubSubnetId",
              "Selector": "$.Subnet.SubnetId",
              "Type": "String"
            }
          ],
          "nextStep": "createPubRtb"
        },
        {
          "name": "createPubRtb",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateRouteTable",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "outputs": [
            {
              "Name": "pubRtbId",
              "Selector": "$.RouteTable.RouteTableId",
              "Type": "String"
            }
          ],
          "nextStep": "createIgw"
        },
        {
          "name": "createIgw",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateInternetGateway"
          },
          "outputs": [
            {
              "Name": "igwId",
              "Selector": "$.InternetGateway.InternetGatewayId",
              "Type": "String"
            }
          ],
          "nextStep": "attachIgw"
        },
        {
          "name": "attachIgw",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "AttachInternetGateway",
            "InternetGatewayId": "{{ createIgw.igwId }}",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "nextStep": "allocateEip"
        },
        {
          "name": "allocateEip",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "AllocateAddress",
            "Domain": "vpc"
          },
          "outputs": [
            {
              "Name": "eipAllocationId",
              "Selector": "$.AllocationId",
              "Type": "String"
            }
          ],
          "nextStep": "createNatGw"
        },
        {
          "name": "createNatGw",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateNatGateway",
            "AllocationId": "{{ allocateEip.eipAllocationId }}",
            "SubnetId": "{{ createPubSubnet.pubSubnetId }}"
          },
          "outputs":[
            {
              "Name": "natGwId",
              "Selector": "$.NatGateway.NatGatewayId",
              "Type": "String"
            }
          ],
          "nextStep": "verifyNatGwAvailable"
        },
        {
          "name": "verifyNatGwAvailable",
          "action": "aws:waitForAwsResourceProperty",
          "timeoutSeconds": 150,
          "inputs": {
            "Service": "ec2",
            "Api": "DescribeNatGateways",
            "NatGatewayIds": [
              "{{ createNatGw.natGwId }}"
            ],
            "PropertySelector": "$.NatGateways[0].State",
            "DesiredValues": [
              "available"
            ]
          },
          "nextStep": "createNatRoute"
        },
        {
          "name": "createNatRoute",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateRoute",
            "DestinationCidrBlock": "0.0.0.0/0",
            "NatGatewayId": "{{ createNatGw.natGwId }}",
            "RouteTableId": "{{ getMainRtb.mainRtbId }}"
          },
          "nextStep": "createPubRoute"
        },
        {
          "name": "createPubRoute",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateRoute",
            "DestinationCidrBlock": "0.0.0.0/0",
            "GatewayId": "{{ createIgw.igwId }}",
            "RouteTableId": "{{ createPubRtb.pubRtbId }}"
          },
          "nextStep": "setPubSubAssoc"
        },
        {
          "name": "setPubSubAssoc",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "AssociateRouteTable",
            "RouteTableId": "{{ createPubRtb.pubRtbId }}",
            "SubnetId": "{{ createPubSubnet.pubSubnetId }}"
          }
        },
        {
          "name": "createDhcpOptions",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateDhcpOptions",
            "DhcpConfigurations": [
              {
                "Key": "domain-name-servers",
                "Values": ["10.0.100.50,10.0.101.50"]
              },
              {
                "Key": "domain-name",
                "Values": ["sample.com"]
              }
            ]
          },
          "outputs": [
            {
              "Name": "dhcpOptionsId",
              "Selector": "$.DhcpOptions.DhcpOptionsId",
              "Type": "String"
            }
          ],
          "nextStep": "createDCSubnet1"
        },
        {
          "name": "createDCSubnet1",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateSubnet",
            "CidrBlock": "10.0.100.0/24",
            "AvailabilityZone": "us-west-2a",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "outputs": [
            {
              "Name": "firstSubnetId",
              "Selector": "$.Subnet.SubnetId",
              "Type": "String"
            }
          ],
          "nextStep": "createDCSubnet2"
        },
        {
          "name": "createDCSubnet2",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateSubnet",
            "CidrBlock": "10.0.101.0/24",
            "AvailabilityZone": "us-west-2b",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "outputs": [
            {
              "Name": "secondSubnetId",
              "Selector": "$.Subnet.SubnetId",
              "Type": "String"
            }
          ],
          "nextStep": "createDCSecGroup"
        },
        {
          "name": "createDCSecGroup",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "CreateSecurityGroup",
            "GroupName": "SampleDCSecGroup",
            "Description": "Security Group for Example Domain Controllers",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "outputs": [
            {
              "Name": "dcSecGroupId",
              "Selector": "$.GroupId",
              "Type": "String"
            }
          ],
          "nextStep": "authIngressDCTraffic"
        },
        {
          "name": "authIngressDCTraffic",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "AuthorizeSecurityGroupIngress",
            "GroupId": "{{ createDCSecGroup.dcSecGroupId }}",
            "IpPermissions": [
              {
                "FromPort": -1,
                "IpProtocol": "-1",
                "IpRanges": [
                  {
                    "CidrIp": "0.0.0.0/0",
                    "Description": "Allow all traffic between Domain Controllers"
                  }
                ]
              }
            ]
          },
          "nextStep": "verifyInstanceProfile"
        },
        {
          "name": "verifyInstanceProfile",
          "action": "aws:waitForAwsResourceProperty",
          "maxAttempts": 5,
          "onFailure": "Abort",
          "inputs": {
            "Service": "iam",
            "Api": "ListInstanceProfilesForRole",
            "RoleName": "sampleSSMInstanceRole",
            "PropertySelector": "$.InstanceProfiles[0].Arn",
            "DesiredValues": [
              "{{ createSSMInstanceProfile.instanceProfileArn }}"
            ]
          },
          "nextStep": "iamEventualConsistency"
        },
        {
          "name": "iamEventualConsistency",
          "action": "aws:sleep",
          "inputs": {
            "Duration": "PT2M"
          },
          "nextStep": "launchDC1"
        },
        {
          "name": "launchDC1",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "RunInstances",
            "BlockDeviceMappings": [
              {
                "DeviceName": "/dev/sda1",
                "Ebs": {
                  "DeleteOnTermination": true,
                  "VolumeSize": 50,
                  "VolumeType": "gp2"
                }
              },
              {
                "DeviceName": "xvdf",
                "Ebs": {
                  "DeleteOnTermination": true,
                  "VolumeSize": 100,
                  "VolumeType": "gp2"
                }
              }
            ],
            "IamInstanceProfile": {
              "Arn": "{{ createSSMInstanceProfile.instanceProfileArn }}"
            },
            "ImageId": "{{ getLatestWindowsAmi.amiId }}",
            "InstanceType": "t2.micro",
            "MaxCount": 1,
            "MinCount": 1,
            "PrivateIpAddress": "10.0.100.50",
            "SecurityGroupIds": [
              "{{ createDCSecGroup.dcSecGroupId }}"
            ],
            "SubnetId": "{{ createDCSubnet1.firstSubnetId }}",
            "TagSpecifications": [
              {
                "ResourceType": "instance",
                "Tags": [
                  {
                    "Key": "Name",
                    "Value": "SampleDC1"
                  }
                ]
              }
            ]
          },
          "outputs": [
            {
              "Name": "pdcInstanceId",
              "Selector": "$.Instances[0].InstanceId",
              "Type": "String"
            }
          ],
          "nextStep": "launchDC2"
        },
        {
          "name": "launchDC2",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "RunInstances",
            "BlockDeviceMappings": [
              {
                "DeviceName": "/dev/sda1",
                "Ebs": {
                  "DeleteOnTermination": true,
                  "VolumeSize": 50,
                  "VolumeType": "gp2"
                }
              },
              {
                "DeviceName": "xvdf",
                "Ebs": {
                  "DeleteOnTermination": true,
                  "VolumeSize": 100,
                  "VolumeType": "gp2"
                }
              }
            ],
            "IamInstanceProfile": {
              "Arn": "{{ createSSMInstanceProfile.instanceProfileArn }}"
            },
            "ImageId": "{{ getLatestWindowsAmi.amiId }}",
            "InstanceType": "t2.micro",
            "MaxCount": 1,
            "MinCount": 1,
            "PrivateIpAddress": "10.0.101.50",
            "SecurityGroupIds": [
              "{{ createDCSecGroup.dcSecGroupId }}"
            ],
            "SubnetId": "{{ createDCSubnet2.secondSubnetId }}",
            "TagSpecifications": [
              {
                "ResourceType": "instance",
                "Tags": [
                  {
                    "Key": "Name",
                    "Value": "SampleDC2"
                  }
                ]
              }
            ]
          },
          "outputs": [
            {
              "Name": "adcInstanceId",
              "Selector": "$.Instances[0].InstanceId",
              "Type": "String"
            }
          ],
          "nextStep": "verifyDCInstanceState"
        },
        {
          "name": "verifyDCInstanceState",
          "action": "aws:waitForAwsResourceProperty",
          "inputs": {
            "Service": "ec2",
            "Api": "DescribeInstanceStatus",
            "IncludeAllInstances": true,
            "InstanceIds": [
              "{{ launchDC1.pdcInstanceId }}",
              "{{ launchDC2.adcInstanceId }}"
            ],
            "PropertySelector": "$.InstanceStatuses[0].InstanceState.Name",
            "DesiredValues": [
              "running"
            ]
          },
          "nextStep": "verifyInstancesOnlineSSM"
        },
        {
          "name": "verifyInstancesOnlineSSM",
          "action": "aws:waitForAwsResourceProperty",
          "timeoutSeconds": 600,
          "inputs": {
            "Service": "ssm",
            "Api": "DescribeInstanceInformation",
            "InstanceInformationFilterList": [
              {
                "key": "InstanceIds",
                "valueSet": [
                  "{{ launchDC1.pdcInstanceId }}",
                  "{{ launchDC2.adcInstanceId }}"
                ]
              }
            ],
            "PropertySelector": "$.InstanceInformationList[0].PingStatus",
            "DesiredValues": [
              "Online"
            ]
          },
          "nextStep": "installADRoles"
        },
        {
          "name": "installADRoles",
          "action": "aws:runCommand",
          "inputs": {
            "DocumentName": "AWS-RunPowerShellScript",
            "InstanceIds": [
              "{{ launchDC1.pdcInstanceId }}",
              "{{ launchDC2.adcInstanceId }}"
            ],
            "Parameters": {
              "commands": [
                "try {",
                "  Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools",
                "}",
                "catch {",
                "  Write-Error \"Failed to install ADDS Role.\"",
                "}"
              ]
            }
          },
          "nextStep": "setAdminPassword"
        },
        {
          "name": "setAdminPassword",
          "action": "aws:runCommand",
          "inputs": {
            "DocumentName": "AWS-RunPowerShellScript",
            "InstanceIds": [
              "{{ launchDC1.pdcInstanceId }}"
            ],
            "Parameters": {
              "commands": [
                "net user Administrator \"sampleAdminPass123!\""
              ]
            }
          },
          "nextStep": "createForest"
        },
        {
          "name": "createForest",
          "action": "aws:runCommand",
          "inputs": {
            "DocumentName": "AWS-RunPowerShellScript",
            "InstanceIds": [
              "{{ launchDC1.pdcInstanceId }}"
            ],
            "Parameters": {
              "commands": [
                "$dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force",
                "try {",
                "   Install-ADDSForest -DomainName \"sample.com\" -DomainMode 6 -ForestMode 6 -InstallDNS -DatabasePath \"D:\\NTDS\" -SysvolPath \"D:\\SYSVOL\" -SafeModeAdministratorPassword $dsrmPass -Force",
                "}",
                "catch {",
                "   Write-Error $_",
                "}",
                "try {",
                "   Add-DnsServerForwarder -IPAddress \"10.0.100.2\"",
                "}",
                "catch {",
                "   Write-Error $_",
                "}"
              ]
            }
          },
          "nextStep": "associateDhcpOptions"
        },
        {
          "name": "associateDhcpOptions",
          "action": "aws:executeAwsApi",
          "onFailure": "Abort",
          "inputs": {
            "Service": "ec2",
            "Api": "AssociateDhcpOptions",
            "DhcpOptionsId": "{{ createDhcpOptions.dhcpOptionsId }}",
            "VpcId": "{{ createVpc.vpcId }}"
          },
          "nextStep": "waitForADServices"
        },
        {
          "name": "waitForADServices",
          "action": "aws:sleep",
          "inputs": {
            "Duration": "PT1M"
          },
          "nextStep": "promoteADC"
        },
        {
          "name": "promoteADC",
          "action": "aws:runCommand",
          "inputs": {
            "DocumentName": "AWS-RunPowerShellScript",
            "InstanceIds": [
              "{{ launchDC2.adcInstanceId }}"
            ],
            "Parameters": {
              "commands": [
                "ipconfig /renew",
                "$dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force",
                "$domAdminUser = \"sample\\Administrator\"",
                "$domAdminPass = \"sampleAdminPass123!\" | ConvertTo-SecureString -asPlainText -Force",
                "$domAdminCred = New-Object System.Management.Automation.PSCredential($domAdminUser,$domAdminPass)",
                "try {",
                "   Install-ADDSDomainController -DomainName \"sample.com\" -InstallDNS -DatabasePath \"D:\\NTDS\" -SysvolPath \"D:\\SYSVOL\" -SafeModeAdministratorPassword $dsrmPass -Credential $domAdminCred -Force",
                "}",
                "catch {",
                "   Write-Error $_",
                "}"
              ]
            }
          }
        }
      ]
    }
```

------

# Wiederherstellen eines Root-Volumes aus dem letzten Snapshot
<a name="automation-document-instance-recovery-example"></a>

Das Betriebssystem auf einem Root-Volume kann aus verschiedenen Gründen beschädigt werden. Beispielsweise können Instances nach einem Patchvorgang aufgrund eines beschädigten Kernels oder einer beschädigten Registrierung nicht mehr erfolgreich gestartet werden. Durch die Automatisierung gängiger Problembehandlungsaufgaben, wie z. B. das Wiederherstellen eines Root-Volumes aus dem letzten Snapshot, der vor dem Patch-Vorgang erstellt wurde, können Ausfallzeiten reduziert und Ihre Problembehebungsmaßnahmen beschleunigt werden. AWS Systems Manager Automatisierungsmaßnahmen können Ihnen dabei helfen, dies zu erreichen. Automation ist ein Tool in AWS Systems Manager.

Das folgende AWS Systems Manager Beispiel-Runbook führt diese Aktionen aus: 
+ Verwendet die `aws:executeAwsApi` Automatisierungsaktion zum Abrufen von Details aus dem Root-Volumen der Instance.
+ Verwendet die `aws:executeScript` Automatisierungsaktion zum Abrufen des neuesten Snapshots für das Root-Volume.
+ Verwendet die `aws:branch` Automatisierungsaktion, um die Automatisierung fortzusetzen, wenn ein Snapshot für das Root-Volume gefunden wird.

------
#### [ YAML ]

```
    ---
    description: Custom Automation Troubleshooting Example
    schemaVersion: '0.3'
    assumeRole: "{{ AutomationAssumeRole }}"
    parameters:
      AutomationAssumeRole:
        type: String
        description: "(Required) The ARN of the role that allows Automation to perform
          the actions on your behalf. If no role is specified, Systems Manager Automation
          uses your IAM permissions to use this runbook."
        default: ''
      InstanceId:
          type: String
          description: "(Required) The Instance Id whose root EBS volume you want to restore the latest Snapshot."
          default: ''
    mainSteps:
    - name: getInstanceDetails
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: DescribeInstances
        InstanceIds:
        - "{{ InstanceId }}"
      outputs:
        - Name: availabilityZone
          Selector: "$.Reservations[0].Instances[0].Placement.AvailabilityZone"
          Type: String
        - Name: rootDeviceName
          Selector: "$.Reservations[0].Instances[0].RootDeviceName"
          Type: String
      nextStep: getRootVolumeId
    - name: getRootVolumeId
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: DescribeVolumes
        Filters:
        -  Name: attachment.device
           Values: ["{{ getInstanceDetails.rootDeviceName }}"]
        -  Name: attachment.instance-id
           Values: ["{{ InstanceId }}"]
      outputs:
        - Name: rootVolumeId
          Selector: "$.Volumes[0].VolumeId"
          Type: String
      nextStep: getSnapshotsByStartTime
    - name: getSnapshotsByStartTime
      action: aws:executeScript
      timeoutSeconds: 45
      onFailure: Abort
      inputs:
        Runtime: python3.11
        Handler: getSnapshotsByStartTime
        InputPayload:
          rootVolumeId : "{{ getRootVolumeId.rootVolumeId }}"
        Script: |-
          def getSnapshotsByStartTime(events,context):
            import boto3
    
            #Initialize client
            ec2 = boto3.client('ec2')
            rootVolumeId = events['rootVolumeId']
            snapshotsQuery = ec2.describe_snapshots(
              Filters=[
                {
                  "Name": "volume-id",
                  "Values": [rootVolumeId]
                }
              ]
            )
            if not snapshotsQuery['Snapshots']:
              noSnapshotFoundString = "NoSnapshotFound"
              return { 'noSnapshotFound' : noSnapshotFoundString }
            else:
              jsonSnapshots = snapshotsQuery['Snapshots']
              sortedSnapshots = sorted(jsonSnapshots, key=lambda k: k['StartTime'], reverse=True)
              latestSortedSnapshotId = sortedSnapshots[0]['SnapshotId']
              return { 'latestSnapshotId' : latestSortedSnapshotId }
      outputs:
      - Name: Payload
        Selector: $.Payload
        Type: StringMap
      - Name: latestSnapshotId
        Selector: $.Payload.latestSnapshotId
        Type: String
      - Name: noSnapshotFound
        Selector: $.Payload.noSnapshotFound
        Type: String 
      nextStep: branchFromResults
    - name: branchFromResults
      action: aws:branch
      onFailure: Abort
      inputs:
        Choices:
        - NextStep: createNewRootVolumeFromSnapshot
          Not:
            Variable: "{{ getSnapshotsByStartTime.noSnapshotFound }}"
            StringEquals: "NoSnapshotFound"
      isEnd: true
    - name: createNewRootVolumeFromSnapshot
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: CreateVolume
        AvailabilityZone: "{{ getInstanceDetails.availabilityZone }}"
        SnapshotId: "{{ getSnapshotsByStartTime.latestSnapshotId }}"
      outputs:
        - Name: newRootVolumeId
          Selector: "$.VolumeId"
          Type: String
      nextStep: stopInstance
    - name: stopInstance
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: StopInstances
        InstanceIds:
        - "{{ InstanceId }}"
      nextStep: verifyVolumeAvailability
    - name: verifyVolumeAvailability
      action: aws:waitForAwsResourceProperty
      timeoutSeconds: 120
      inputs:
        Service: ec2
        Api: DescribeVolumes
        VolumeIds:
        - "{{ createNewRootVolumeFromSnapshot.newRootVolumeId }}"
        PropertySelector: "$.Volumes[0].State"
        DesiredValues:
        - "available"
      nextStep: verifyInstanceStopped
    - name: verifyInstanceStopped
      action: aws:waitForAwsResourceProperty
      timeoutSeconds: 120
      inputs:
        Service: ec2
        Api: DescribeInstances
        InstanceIds:
        - "{{ InstanceId }}"
        PropertySelector: "$.Reservations[0].Instances[0].State.Name"
        DesiredValues:
        - "stopped"
      nextStep: detachRootVolume
    - name: detachRootVolume
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: DetachVolume
        VolumeId: "{{ getRootVolumeId.rootVolumeId }}"
      nextStep: verifyRootVolumeDetached
    - name: verifyRootVolumeDetached
      action: aws:waitForAwsResourceProperty
      timeoutSeconds: 30
      inputs:
        Service: ec2
        Api: DescribeVolumes
        VolumeIds:
        - "{{ getRootVolumeId.rootVolumeId }}"
        PropertySelector: "$.Volumes[0].State"
        DesiredValues:
        - "available"
      nextStep: attachNewRootVolume
    - name: attachNewRootVolume
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: AttachVolume
        Device: "{{ getInstanceDetails.rootDeviceName }}"
        InstanceId: "{{ InstanceId }}"
        VolumeId: "{{ createNewRootVolumeFromSnapshot.newRootVolumeId }}"
      nextStep: verifyNewRootVolumeAttached
    - name: verifyNewRootVolumeAttached
      action: aws:waitForAwsResourceProperty
      timeoutSeconds: 30
      inputs:
        Service: ec2
        Api: DescribeVolumes
        VolumeIds:
        - "{{ createNewRootVolumeFromSnapshot.newRootVolumeId }}"
        PropertySelector: "$.Volumes[0].Attachments[0].State"
        DesiredValues:
        - "attached"
      nextStep: startInstance
    - name: startInstance
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: StartInstances
        InstanceIds:
        - "{{ InstanceId }}"
```

------
#### [ JSON ]

```
    {
       "description": "Custom Automation Troubleshooting Example",
       "schemaVersion": "0.3",
       "assumeRole": "{{ AutomationAssumeRole }}",
       "parameters": {
          "AutomationAssumeRole": {
             "type": "String",
             "description": "(Required) The ARN of the role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to run this runbook.",
             "default": ""
          },
          "InstanceId": {
             "type": "String",
             "description": "(Required) The Instance Id whose root EBS volume you want to restore the latest Snapshot.",
             "default": ""
          }
       },
       "mainSteps": [
          {
             "name": "getInstanceDetails",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeInstances",
                "InstanceIds": [
                   "{{ InstanceId }}"
                ]
             },
             "outputs": [
                {
                   "Name": "availabilityZone",
                   "Selector": "$.Reservations[0].Instances[0].Placement.AvailabilityZone",
                   "Type": "String"
                },
                {
                   "Name": "rootDeviceName",
                   "Selector": "$.Reservations[0].Instances[0].RootDeviceName",
                   "Type": "String"
                }
             ],
             "nextStep": "getRootVolumeId"
          },
          {
             "name": "getRootVolumeId",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeVolumes",
                "Filters": [
                   {
                      "Name": "attachment.device",
                      "Values": [
                         "{{ getInstanceDetails.rootDeviceName }}"
                      ]
                   },
                   {
                      "Name": "attachment.instance-id",
                      "Values": [
                         "{{ InstanceId }}"
                      ]
                   }
                ]
             },
             "outputs": [
                {
                   "Name": "rootVolumeId",
                   "Selector": "$.Volumes[0].VolumeId",
                   "Type": "String"
                }
             ],
             "nextStep": "getSnapshotsByStartTime"
          },
          {
             "name": "getSnapshotsByStartTime",
             "action": "aws:executeScript",
             "timeoutSeconds": 45,
             "onFailure": "Continue",
             "inputs": {
                "Runtime": "python3.11",
                "Handler": "getSnapshotsByStartTime",
                "InputPayload": {
                   "rootVolumeId": "{{ getRootVolumeId.rootVolumeId }}"
                },
                "Attachment": "getSnapshotsByStartTime.py"
             },
             "outputs": [
                {
                   "Name": "Payload",
                   "Selector": "$.Payload",
                   "Type": "StringMap"
                },
                {
                   "Name": "latestSnapshotId",
                   "Selector": "$.Payload.latestSnapshotId",
                   "Type": "String"
                },
                {
                   "Name": "noSnapshotFound",
                   "Selector": "$.Payload.noSnapshotFound",
                   "Type": "String"
                }
             ],
             "nextStep": "branchFromResults"
          },
          {
             "name": "branchFromResults",
             "action": "aws:branch",
             "onFailure": "Abort",
             "inputs": {
                "Choices": [
                   {
                      "NextStep": "createNewRootVolumeFromSnapshot",
                      "Not": {
                         "Variable": "{{ getSnapshotsByStartTime.noSnapshotFound }}",
                         "StringEquals": "NoSnapshotFound"
                      }
                   }
                ]
             },
             "isEnd": true
          },
          {
             "name": "createNewRootVolumeFromSnapshot",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "CreateVolume",
                "AvailabilityZone": "{{ getInstanceDetails.availabilityZone }}",
                "SnapshotId": "{{ getSnapshotsByStartTime.latestSnapshotId }}"
             },
             "outputs": [
                {
                   "Name": "newRootVolumeId",
                   "Selector": "$.VolumeId",
                   "Type": "String"
                }
             ],
             "nextStep": "stopInstance"
          },
          {
             "name": "stopInstance",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "StopInstances",
                "InstanceIds": [
                   "{{ InstanceId }}"
                ]
             },
             "nextStep": "verifyVolumeAvailability"
          },
          {
             "name": "verifyVolumeAvailability",
             "action": "aws:waitForAwsResourceProperty",
             "timeoutSeconds": 120,
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeVolumes",
                "VolumeIds": [
                   "{{ createNewRootVolumeFromSnapshot.newRootVolumeId }}"
                ],
                "PropertySelector": "$.Volumes[0].State",
                "DesiredValues": [
                   "available"
                ]
             },
             "nextStep": "verifyInstanceStopped"
          },
          {
             "name": "verifyInstanceStopped",
             "action": "aws:waitForAwsResourceProperty",
             "timeoutSeconds": 120,
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeInstances",
                "InstanceIds": [
                   "{{ InstanceId }}"
                ],
                "PropertySelector": "$.Reservations[0].Instances[0].State.Name",
                "DesiredValues": [
                   "stopped"
                ]
             },
             "nextStep": "detachRootVolume"
          },
          {
             "name": "detachRootVolume",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "DetachVolume",
                "VolumeId": "{{ getRootVolumeId.rootVolumeId }}"
             },
             "nextStep": "verifyRootVolumeDetached"
          },
          {
             "name": "verifyRootVolumeDetached",
             "action": "aws:waitForAwsResourceProperty",
             "timeoutSeconds": 30,
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeVolumes",
                "VolumeIds": [
                   "{{ getRootVolumeId.rootVolumeId }}"
                ],
                "PropertySelector": "$.Volumes[0].State",
                "DesiredValues": [
                   "available"
                ]
             },
             "nextStep": "attachNewRootVolume"
          },
          {
             "name": "attachNewRootVolume",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "AttachVolume",
                "Device": "{{ getInstanceDetails.rootDeviceName }}",
                "InstanceId": "{{ InstanceId }}",
                "VolumeId": "{{ createNewRootVolumeFromSnapshot.newRootVolumeId }}"
             },
             "nextStep": "verifyNewRootVolumeAttached"
          },
          {
             "name": "verifyNewRootVolumeAttached",
             "action": "aws:waitForAwsResourceProperty",
             "timeoutSeconds": 30,
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeVolumes",
                "VolumeIds": [
                   "{{ createNewRootVolumeFromSnapshot.newRootVolumeId }}"
                ],
                "PropertySelector": "$.Volumes[0].Attachments[0].State",
                "DesiredValues": [
                   "attached"
                ]
             },
             "nextStep": "startInstance"
          },
          {
             "name": "startInstance",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "StartInstances",
                "InstanceIds": [
                   "{{ InstanceId }}"
                ]
             }
          }
       ],
       "files": {
            "getSnapshotsByStartTime.py": {
                "checksums": {
                    "sha256": "sampleETagValue"
                }
            }
        }
    }
```

------

# Erstellen eines AMI und einer regionenübergreifenden Kopie
<a name="automation-document-backup-maintenance-example"></a>

Das Erstellen eines Amazon Machine Image (AMI) einer Instance ist ein üblicher Prozess, der bei Backup und Wiedherherstellung verwendet wird. Sie können sich auch dafür entscheiden, ein AMI als Teil einer Notfallwiederherstellungsarchitektur in eine andere AWS-Region zu kopieren. Durch die Automatisierung gängiger Wartungsaufgaben kann die Ausfallzeit reduziert werden, wenn ein Problem ein Failover erfordert. AWS Systems Manager Automatisierungsaktionen können Ihnen dabei helfen. Automation ist ein Tool in AWS Systems Manager.

Das folgende AWS Systems Manager Beispiel-Runbook führt diese Aktionen aus:
+ Verwendet die `aws:executeAwsApi` Automatisierungsaktion zur Erstellung eines AMI.
+ Verwendet die `aws:waitForAwsResourceProperty` Automatisierungsaktion zur Bestätigung der Verfügbarkeit des AMI.
+ Verwendet die `aws:executeScript` Automatisierungsaktion zum Kopieren des AMI in die Zielregion.

------
#### [ YAML ]

```
    ---
    description: Custom Automation Backup and Recovery Example
    schemaVersion: '0.3'
    assumeRole: "{{ AutomationAssumeRole }}"
    parameters:
      AutomationAssumeRole:
        type: String
        description: "(Required) The ARN of the role that allows Automation to perform
          the actions on your behalf. If no role is specified, Systems Manager Automation
          uses your IAM permissions to use this runbook."
        default: ''
      InstanceId:
        type: String
        description: "(Required) The ID of the EC2 instance."
        default: ''
    mainSteps:
    - name: createImage
      action: aws:executeAwsApi
      onFailure: Abort
      inputs:
        Service: ec2
        Api: CreateImage
        InstanceId: "{{ InstanceId }}"
        Name: "Automation Image for {{ InstanceId }}"
        NoReboot: false
      outputs:
        - Name: newImageId
          Selector: "$.ImageId"
          Type: String
      nextStep: verifyImageAvailability
    - name: verifyImageAvailability
      action: aws:waitForAwsResourceProperty
      timeoutSeconds: 600
      inputs:
        Service: ec2
        Api: DescribeImages
        ImageIds:
        - "{{ createImage.newImageId }}"
        PropertySelector: "$.Images[0].State"
        DesiredValues:
        - available
      nextStep: copyImage
    - name: copyImage
      action: aws:executeScript
      timeoutSeconds: 45
      onFailure: Abort
      inputs:
        Runtime: python3.11
        Handler: crossRegionImageCopy
        InputPayload:
          newImageId : "{{ createImage.newImageId }}"
        Script: |-
          def crossRegionImageCopy(events,context):
            import boto3
    
            #Initialize client
            ec2 = boto3.client('ec2', region_name='us-east-1')
            newImageId = events['newImageId']
    
            ec2.copy_image(
              Name='DR Copy for ' + newImageId,
              SourceImageId=newImageId,
              SourceRegion='us-west-2'
            )
```

------
#### [ JSON ]

```
    {
       "description": "Custom Automation Backup and Recovery Example",
       "schemaVersion": "0.3",
       "assumeRole": "{{ AutomationAssumeRole }}",
       "parameters": {
          "AutomationAssumeRole": {
             "type": "String",
             "description": "(Required) The ARN of the role that allows Automation to perform\nthe actions on your behalf. If no role is specified, Systems Manager Automation\nuses your IAM permissions to run this runbook.",
             "default": ""
          },
          "InstanceId": {
             "type": "String",
             "description": "(Required) The ID of the EC2 instance.",
             "default": ""
          }
       },
       "mainSteps": [
          {
             "name": "createImage",
             "action": "aws:executeAwsApi",
             "onFailure": "Abort",
             "inputs": {
                "Service": "ec2",
                "Api": "CreateImage",
                "InstanceId": "{{ InstanceId }}",
                "Name": "Automation Image for {{ InstanceId }}",
                "NoReboot": false
             },
             "outputs": [
                {
                   "Name": "newImageId",
                   "Selector": "$.ImageId",
                   "Type": "String"
                }
             ],
             "nextStep": "verifyImageAvailability"
          },
          {
             "name": "verifyImageAvailability",
             "action": "aws:waitForAwsResourceProperty",
             "timeoutSeconds": 600,
             "inputs": {
                "Service": "ec2",
                "Api": "DescribeImages",
                "ImageIds": [
                   "{{ createImage.newImageId }}"
                ],
                "PropertySelector": "$.Images[0].State",
                "DesiredValues": [
                   "available"
                ]
             },
             "nextStep": "copyImage"
          },
          {
             "name": "copyImage",
             "action": "aws:executeScript",
             "timeoutSeconds": 45,
             "onFailure": "Abort",
             "inputs": {
                "Runtime": "python3.11",
                "Handler": "crossRegionImageCopy",
                "InputPayload": {
                   "newImageId": "{{ createImage.newImageId }}"
                },
                "Attachment": "crossRegionImageCopy.py"
             }
          }
       ],
       "files": {
            "crossRegionImageCopy.py": {
                "checksums": {
                    "sha256": "sampleETagValue"
                }
            }
        }
    }
```

------