Last active
October 1, 2021 10:36
-
-
Save deric4/e60a2b8f2236476b416986321978f567 to your computer and use it in GitHub Desktop.
Script reference in CreatVSSSnapshot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# [AWS Docs](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/application-consistent-snapshots-creating-commands.html#application-cosistent-snapshots-cli) | |
#https://docs.aws.amazon.com/systems-manager/latest/userguide/samples/CreateVssSnapshotAdvancedScript.zip | |
function Freeze-Instance { | |
param( | |
[string]$InstanceId, | |
[string[]]$Devices, | |
[string[]]$Volumes | |
) | |
$DevicesString = $Devices -join ',' | |
$VolumesString = $Volumes -join ',' | |
Write-Host "Starting Freeze for devices" $DevicesString $(Get-Date) | |
#Call freeze SSM command and wait until complete | |
$cmd = Send-SSMCommand -InstanceId $InstanceId -DocumentName AWSEC2-ManageVssIO -Parameter @{"Action" = "Freeze"; "Devices" = $DevicesString; "Volumes" = $VolumesString} | |
$commandId = $cmd.CommandId | |
Sleep -Seconds 2 | |
while ((Get-SSMCommandInvocation -CommandId $commandId).Status.Value -eq "InProgress" ) { | |
Sleep -MilliSeconds 501 | |
} | |
$CommandInvocation = Get-SSMCommandInvocation -CommandId $commandId -Details $true | |
if ($CommandInvocation.CommandPlugins[0].Status.Value -eq "Failed") { | |
throw "Freeze command failed, command id: $($commandId), output: $($CommandInvocation.CommandPlugins[0].Output)" | |
} | |
Write-Host "Freeze complete, command id=$commandId $(Get-Date)" | |
} | |
# | |
# Thaws EBS volumes attached to an Ec2 instance | |
# | |
function Thaw-Instance { | |
param([string]$InstanceId) | |
Write-Host "Starting Thaw $(Get-Date)" | |
#Call thaw SSM command and wait until complete | |
$cmd = Send-SSMCommand -InstanceId $InstanceId -DocumentName AWSEC2-ManageVssIO -Parameter @{"Action" = "Thaw"} | |
$commandId = $cmd.CommandId | |
Sleep -Seconds 1 | |
while ((Get-SSMCommandInvocation -CommandId $commandId).Status.Value -eq "InProgress" ) { | |
Sleep -Seconds 1 | |
} | |
Write-Host "Thaw complete, command id=$commandId $(Get-Date)" | |
$CommandInvocation = Get-SSMCommandInvocation -CommandId $commandId -Details $true | |
if ($CommandInvocation.CommandPlugins[0].Status.Value -eq "Failed") { | |
throw "Thaw command failed $($commandId), output $CommandInvocation.CommandPlugins[0].Status" | |
} | |
$output = $CommandInvocation.CommandPlugins[0].Output | |
$Status = $CommandInvocation.CommandPlugins[0].Status | |
write-host $output | |
} | |
# | |
# Tag Snapshots | |
# | |
function Tag-Snapshots { | |
param( | |
[System.Object[]]$SnapshotsData, | |
[boolean]$AppConsistent, | |
[Parameter(Mandatory = $false)][amazon.EC2.Model.Tag[]]$Tags | |
) | |
if ($Tags -eq $null) { | |
$Tags = @() | |
} | |
$Tag = new-object amazon.EC2.Model.Tag | |
$Tag.Key = "AppConsistent" | |
$Tag.Value = "$AppConsistent" | |
$Tags += $Tag | |
foreach ($SnapshotData in $SnapshotsData) { | |
$Tag = new-object amazon.EC2.Model.Tag | |
$Tag.Key = "Device" | |
$Tag.Value = $SnapshotData.Device | |
$AllTags = $Tags + $Tag | |
New-EC2Tag -Resources $SnapshotData.SnapshotId -Tags $AllTags | |
} | |
} | |
# | |
# Create consistent snapshots of volumes attached to an EC2 instance except root volume | |
# | |
function Vss-Snapshot { | |
param( | |
[string]$InstanceId, | |
[Parameter(Mandatory = $false)][string]$Description, | |
[Parameter(Mandatory = $false)][amazon.EC2.Model.Tag[]]$Tags | |
) | |
#Get attached voluems/devices | |
$BlockDeviceMappings = (Get-EC2Instance -Instance $InstanceId).Instances.BlockDeviceMappings | |
$SnapshotData = @() | |
foreach ($BlockDeviceMapping in $BlockDeviceMappings) { | |
#Exclude the boot volume, boot volumes are not supported using this script | |
if ($BlockDeviceMapping.DeviceName -ne "/dev/sda1") { | |
$SnapshotData += | |
New-Object PSObject -Property @{ | |
EbsVolumeId = $BlockDeviceMapping.Ebs.VolumeId | |
Device = $BlockDeviceMapping.DeviceName | |
SnapshotId = $null | |
} | |
} | |
} | |
if ($SnapshotData.Count -eq 0) { | |
Write-Error "Instance has no volumes to snapshot" | |
exit 1 | |
} | |
#Freeze IO on instance | |
Freeze-Instance $InstanceId $SnapshotData.Device $SnapshotData.EbsVolumeId | |
#Take Snapshots | |
foreach ($Data in $SnapshotData) { | |
$Snaphsot = New-EC2Snapshot -Description $Description -VolumeId $Data.EbsVolumeId | |
$Data.SnapshotId = $Snaphsot.SnapshotId | |
} | |
#Thaw IO on instance | |
Try { | |
Thaw-Instance $InstanceId | |
Tag-Snapshots $SnapshotData $true $Tags | |
} Catch { | |
#If Thaw fails (snapshots took to long), tag snapshots as AppConsistent=false | |
Tag-Snapshots $SnapshotData $false $Tags | |
} | |
} | |
#Example usage | |
$Tags = @() | |
$Tag = new-object amazon.EC2.Model.Tag | |
$Tag.Key = "TagKey" | |
$Tag.Value = "TagValue" | |
$Tags += $Tag | |
Vss-Snapshot $instance "Created by adv script" $Tags |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://docs.aws.amazon.com/systems-manager/latest/userguide/samples/RestoreVssSnapshotSampleScript.zip | |
# Restore volume to an EC2 instance | |
# WARNING: This will stop the instance and dismount existing volumes | |
# | |
function Vss-Restore { | |
param( | |
[String]$InstanceId, | |
[String[]]$Snapshots | |
) | |
#get snapshot information | |
$SnapshotData = @() | |
foreach ($Snapshot in $Snapshots) { | |
#Get device from snapshot 'Device' tag | |
$filter = New-Object Amazon.EC2.Model.Filter | |
$filter.Name = "key" | |
$filter.Values = "Device" | |
$filters = @($filter) | |
$keys = new-object string[] 1 | |
$keys[0] = $Snapshot | |
$filter = new-object Amazon.EC2.Model.Filter | |
$filter.Name = 'resource-id' | |
$filter.Values = $keys | |
$filters += @($filter) | |
$DeviceTag = Get-EC2Tag -Filter $filters | |
if ($DeviceTag -eq $null) { | |
throw "Restore failed, snapshot $Snapshot missing 'Device' tag" | |
} | |
$SnapshotData += | |
New-Object PSObject -Property @{ | |
EbsVolumeId = $null | |
Device = $DeviceTag.Value | |
SnapshotId = $Snapshot | |
} | |
} | |
Write-Host "Shutting down instance" $InstanceId | |
Stop-EC2Instance -Instance $InstanceId > $null | |
do { | |
Sleep -Seconds 2 | |
$Instance = (Get-EC2Instance -Instance $InstanceId).Instances | |
} | |
until($Instance.State.Name -eq "stopped") | |
#Dismount existing volumes from instance, ;eaving root volume if not replacing it | |
foreach ($BlockDevice in $Instance.BlockDeviceMappings) { | |
if ($SnapshotData.Device.Contains($BlockDevice.DeviceName) -or $BlockDevice.DeviceName -ne "/dev/sda1") { | |
Write-Host "Dimounting volume" $BlockDevice.Ebs.VolumeId "for device" $BlockDevice.DeviceName "from instance" $InstanceId | |
Dismount-EC2Volume -InstanceId $InstanceId -VolumeId $BlockDevice.Ebs.VolumeId > $null | |
} | |
} | |
#create volumes from snapshot and attach them to instance | |
$AvailabilityZone = $Instance.Placement.AvailabilityZone | |
foreach ($Data in $SnapshotData) { | |
#TODO: Modify to set iops, encryption, etc | |
$Volume = New-EC2Volume -SnapshotId $Data.SnapshotId -AvailabilityZone $AvailabilityZone | |
do { | |
Sleep -Seconds 5 | |
$VolumeState = (Get-EC2Volume -VolumeId $Volume.VolumeId).State | |
} | |
until($VolumeState = "available") | |
$Data.EbsVolumeId = $Volume.VolumeId | |
Write-Host "Attaching volume" $Data.EbsVolumeId "from snapshot" $Data.SnapshotId "for device" $Data.Device "to instance" $InstanceId | |
Add-EC2Volume -InstanceId $InstanceId -VolumeId $Volume.VolumeId -Device $DeviceTag.Value > $null | |
} | |
#Start instance | |
Write-Host "Starting instance" $InstanceId | |
Start-EC2Instance -InstanceId $InstanceId > $null | |
} | |
Vss-Restore $InstanceId @($SnapshotId) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment