A simple powershell script to restore from a snapshot for a Windows EC2 instance (single volume)

For those of us who are accustomed to the “revert to snapshot” function in a VMware environment, it is quite a challenge to do the same on AWS.  The problem comes from the fact that you can’t manipulate the volume itself most of the time, and restoring basically means replacing the currently mounted volume of the instance.  Here’s a script I wrote for a group discussion we had here at TCG (Technology Consulting Group) to  simplify the restore process.
The script assumes that you have already setup the AWS powershell environment and can successfully connect to and manage your EC2 instances.  For help with setting it up you can visit the official page here:

http://docs.aws.amazon.com/powershell/latest/userguide/pstools-getting-set-up.html

The restore script works in a fairly straight forward way:

  1. Determine the instance ID
  2. Get the volume ID and the available snapshots
  3. Get the ID of the snapshot for the restore
  4. Create a new volume from the snapshot and get the new volume ID
  5. Shut down the instance
  6. Unmount the existing volume
  7. Mount the new volume created from the snapshot
  8. Boot the server

There are a few different options regarding the steps that you might want to change to adapt to your environment.  I did the script this way to suit our needs.  For example:  

  • You can just plug in the instance ID if you already have it on hand.  Producing a list of instances if you have a lot of them is not very effective.  
  • Since it’s for a Windows root volume, I set the mount device as /dev/sda1 which works for me.  you might want to make sure it’s the same for you.  You can see the mount dev from the first command of my script.
  • I’m using quite a few while loops to check the status of the instance, which you might not need, etc…

You might have noticed the “single volume” description on the title and this script is really just for restoring a single volume.  There are a few more steps to do for restoring multiple volumes, although basically you’re doing the same thing for all the volumes.  The only difference will be the mounting device.  And don’t forget to update your snapshot creation script to reflect the new volume ID.  

It is not obvious but you can use the same script to expand your volume if needed.  Again, unlike VMware where you can manipulate and expand a volume directly, you can’t do the same on AWS.

The complete script can be found below:

 

# sample code...please test first and use at your own risk!

write-host "here's the list of instances"

(Get-Ec2Instance).Instances | select InstanceId, PublicDnsName, PrivateIpAddress, RootDeviceName, RootDeviceType, ImageId, @{Name="AWS Servername";Expression={$_.tags | where key -eq "Name" | select Value -expand Value}} |ft -AutoSize

$SrvInstanceId = Read-Host -Prompt "what's the instance-id of the target server?"

$SrvName = (Get-EC2Tag | where {$_.ResourceId -eq $SrvInstanceId -and $_.Key -eq "Name"}).value

$OrigInstanceAZ = (Get-EC2Volume | ? { $_.Attachments.InstanceId -eq $SrvInstanceId}).AvailabilityZone




# Get a collection of all volumes attached to the instance

$OldVolId = (Get-EC2Volume | ? { $_.Attachments.InstanceId -eq $SrvInstanceId}).VolumeId

$OldVolSize = (Get-EC2Volume | ? { $_.Attachments.InstanceId -eq $SrvInstanceId}).Size




write-host "here's a list of available snapshots for volume $OldVolId of the Instance $SrvName"




Get-EC2Snapshot | where {$_.VolumeId -eq $OldVolId} |select StartTime, SnapshotId, VolumeSize, Description |ft -AutoSize




$SnapId = Read-Host -Prompt "what's the SnapshotId of target snapshot for restore?"




Write-host "Hit Ctrl-C to abort right now..... or "

PAUSE




# change volume size as needed below !!!

$NewVolSize = Read-Host -Prompt "Give me the new size you want.  Here is the original size $OldVolSize GB"

#$NewInstanceAZ = Read-Host -Prompt "What AZ should this Volume exist in.  Original AZ = $OldInstanceAZ" 

$NewVolId = (New-EC2Volume -SnapshotId $SnapId -Size $NewVolSize -AvailabilityZone $OrigInstanceAZ -VolumeType gp2 |select VolumeId |ft -HideTableHeaders | Out-String -Stream | Select-String -Pattern "vol-")




# shutdown instance

write-host "Shutting down the instance $SrvName now..."

Stop-EC2instance $SrvInstanceId | Out-Null

# $instancestate = (Get-EC2Instance $SrvInstanceId).Instances.State.Name

while (((Get-EC2Instance $SrvInstanceId).Instances.State.Name) -ne "stopped") {write-host "waiting..."; start-sleep -seconds 5}

Write-Host "`nStopped"




# detach volume

Write-host "`nDetaching the old volume..."

Dismount-EC2Volume -InstanceId $SrvInstanceId -VolumeId $OldVolId

Start-Sleep -s 5




# attach volume




Write-host "`nAttaching the new volume..."

Add-EC2Volume -InstanceId $SrvInstanceId -VolumeId $NewVolId -Device /dev/sda1

Start-Sleep -s 5




# start instance

Write-host "`nDone. Starting the instance $SrvName now..."

Start-EC2Instance $SrvInstanceId | Out-Null

while (((Get-EC2Instance $SrvInstanceId).Instances.State.Name) -ne "running") {write-host "waiting..."; start-sleep -seconds 5}

Write-Host "`nInstance is running `n"

Write-Host "here's the public DNS name and IP address: `n"

(Get-EC2Instance $SrvInstanceId).Instances.PublicDnsName 

(Get-EC2Instance $SrvInstanceId).Instances.PublicIpAddress 

 

 

Questions? Write me at davidmfong@stanford.edu