PowerShell script to undelete an accidentally deleted File share
This script helps you to undelete a file share, if you deleted it accidentally. The soft delete security feature for file shares provides you the option of undeleting a file share within the 14 days retention period, allowing recovery of all your file share contents, snapshots, and recovery points. To learn more about soft delete, visit this link.
Sample script
#Import-Module Az.Storage -MinimumVersion 1.7.0 -Scope Local
Param(
[Parameter(Mandatory=$True)][System.String] $ResourceGroupName,
[Parameter(Mandatory=$True)][System.String] $StorageAccountName,
[Parameter(Mandatory=$True)][System.String] $FileShareName,
[Parameter(Mandatory=$True)][System.String] $SubscriptionId,
[Parameter(Mandatory=$False)][System.Boolean] $ListOption,
[Parameter(Mandatory=$False)][System.String] $DeletedShareVersion
)
Function Restore-DeletedFileShare
{
Param(
[Parameter(Mandatory=$True)][Microsoft.WindowsAzure.Commands.Common.Storage.LazyAzureStorageContext] $Context,
[Parameter(Mandatory=$True)][System.String] $FileShareName,
[Parameter(Mandatory=$False)][System.String] $DeletedShareVersion
)
if ([string]::IsNullOrWhiteSpace($FileShareName))
{
Write-Error "Please specify the required input parameter: FileShareName" -ErrorAction Stop
}
$FileShareName = $FileShareName.ToLowerInvariant()
Write-Verbose "Restoring a file share with the name: $FileShareName" -Verbose
Write-Information -MessageData "Started: Creating SASToken to List File Shares" -InformationAction Continue
$listToken = New-AzStorageAccountSASToken -Context $Context -Service File -ResourceType Service -Permission "l" -Protocol HttpsOrHttp -StartTime (Get-Date).AddHours(-1) -ExpiryTime (Get-Date).AddHours(1)
Write-Information -MessageData "Completed: Creating SASToken to List File Shares" -InformationAction Continue
Write-Information -MessageData "Started: Listing File Shares to find the deleted file share" -InformationAction Continue
$listSharesUrl = [string]::Concat($Context.FileEndPoint, "?include=metadata,deleted&comp=list&api-version=2019-10-10&", $listToken.Substring(1))
$listSharesResponse = Invoke-WebRequest $listSharesUrl -Method "GET" -Verbose
if ($listSharesResponse.StatusCode -ne 200)
{
Write-Error "Request to list file shares failed." -ErrorAction Stop
}
Write-Verbose $listSharesResponse.RawContent -Verbose
$listSharesResponseContent = $listSharesResponse.Content.Substring(3)
Write-Information -MessageData "Completed: Listing File Shares to find the deleted file share" -InformationAction Continue
Write-Information -MessageData "Started: Search for a deleted file share with the specified name" -InformationAction Continue
$deletedFileShares = Select-Xml -Content $listSharesResponseContent -XPath "/EnumerationResults/Shares/Share[Deleted=""true"" and Name=""$FileShareName""]"
$matchedCount = 0
$deletedShareVersions = New-Object System.Collections.Generic.List[string]
foreach($share in $deletedFileShares)
{
if($matchedCount -eq 0)
{
Write-Verbose $share.Node.InnerXml -Verbose
Write-Information -MessageData "Completed: Search for a deleted file share with the specified name And Found versions" -InformationAction Continue
}
$shareVer = $share.Node.Item("Version").InnerText
$shareDelTime = $share.Node.Item("Properties").Item("DeletedTime").InnerText
$retDays = $share.Node.Item("Properties").Item("RemainingRetentionDays").InnerText
$deletedShareVersions.Add($share.Node.Item("Version").InnerText)
Write-Information -MessageData "DeletedVersion: $shareVer, DeletedTime: $shareDelTime, RemainingRetentionDays: $retDays" -InformationAction Continue
$matchedCount++
}
if($ListOption -eq $True)
{
return;
}
if ($matchedCount -eq 0)
{
Write-Error "Deleted file share with the specified name was not found." -ErrorAction Stop
}
elseif($matchedCount -eq 1 -and ([string]::IsNullOrWhiteSpace($DeletedShareVersion) -or $deletedShareVersions.Contains($DeletedShareVersion)))
{
$DeletedShareVersion = $deletedShareVersions
}
elseif ($matchedCount -gt 1)
{
if ([string]::IsNullOrWhiteSpace($DeletedShareVersion) -or !$deletedShareVersions.Contains($DeletedShareVersion))
{
Write-Error "More than one share with the specified name was found. Please specify a valid DeletedShareVersion parameter from above possible values." -ErrorAction Stop
}
}
Write-Information -MessageData "Completed: Search for a deleted file share with the specified name And Found version: $DeletedShareVersion" -InformationAction Continue
Write-Information -MessageData "Started: Creating SASToken to Restore File Share" -InformationAction Continue
$restoreToken = New-AzStorageAccountSASToken -Context $Context -Service File -ResourceType Container -Permission "w" -Protocol HttpsOrHttp -StartTime (Get-Date).AddHours(-1) -ExpiryTime (Get-Date).AddHours(1)
Write-Information -MessageData "Completed: Creating SASToken to Restore File Share" -InformationAction Continue
Write-Information -MessageData "Started: Restore File Share" -InformationAction Continue
$restoreShareUrl = [string]::Concat($Context.FileEndPoint, $FileShareName, "?restype=share&comp=undelete&api-version=2019-10-10&", $restoreToken.Substring(1))
$restoreHeaders = @{"x-ms-deleted-share-name" = $FileShareName; "x-ms-deleted-share-version" = $DeletedShareVersion}
$restoreResponse = Invoke-WebRequest $restoreShareUrl -Headers $restoreHeaders -Method "PUT" -Verbose
if ($restoreResponse.StatusCode -ne 201)
{
Write-Error "Request to restore a file share failed." -ErrorAction Stop
}
Write-Verbose $restoreResponse.RawContent -Verbose
Write-Information -MessageData "Completed: Restore File Share" -InformationAction Continue
}
Connect-AzAccount -Environment AzureChinaCloud
Select-AzSubscription -Subscription $SubscriptionId
$sa = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName
Restore-DeletedFileShare $sa.Context $FileShareName $DeletedShareVersion
How to use the script in different scenarios
Prerequisites
Install the latest Azure PowerShell Az modules from this link before running the script.
Keep the following details handy as you'll need to pass them as values for different parameters of the script:
- -SubscriptionId - ID of the subscription where the file share is present.
- -ResourceGroupName - Resource Group of the Storage Account hosting the file share.
- -StorageAccountName - Name of the storage account hosting the file share.
- -FileShareName - Name of the file share to be undeleted
Execution steps
- Save the script above on your machine with a name of your choice. In this example, we saved it as Undelete.ps1
- Run the script according to the scenario that fits your requirements.
Scenario 1
There are no multiple deleted versions with the same name as the file share you're trying to undelete.
The following example undeletes the file share share1 present in storage account afsshare.
.\UnDelete.ps1 -ResourceGroupName afsshare -StorageAccountName afsshare -SubscriptionId aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e -FileShareName share1
The output should show the message Completed:Restore File Share
Scenario 2
There are multiple deleted versions with the same name as the fileshare you're trying to undelete.
The following example undeletes a version of the file share share1
Step 1
Execute the script as follows by providing the file share name.
.\UnDelete.ps1 -ResourceGroupName afsshare -StorageAccountName afsshare -SubscriptionId aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e -FileShareName share1
Completed: Search for a deleted file share with the specified name and Found versions
DeletedVersion: 01D5D7F77ACC7864, DeletedTime: Fri, 31 Jan 2020 05:30:33 GMT, RemainingRetentionDays: 14
DeletedVersion: 01D5D7F7A76CAF42, DeletedTime: Fri, 31 Jan 2020 05:31:25 GMT, RemainingRetentionDays: 14
Restore-DeletedFileShare : More than one share with the specified name was found. Please specify a valid DeletedShareVersion parameter from above possible values.
Step 2
Choose the version from the output of step 1 that you want to undelete and pass it as a value for the -DeletedShareVersion parameter.
The following example undeletes the 01D5D7F77ACC7864 version of the share1 file share.
.\UnDelete.ps1 -ResourceGroupName afsshare-StorageAccountName afsshare -SubscriptionId aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e -FileShareName share1 -DeletedShareVersion 01D5D7F77ACC7864