Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,9 @@ function Test-GetAzureStorageAccountGeoReplicationStats
Assert-AreEqual $kind $sto.Kind;
Assert-NotNull $sto.GeoReplicationStats.Status
Assert-NotNull $sto.GeoReplicationStats.LastSyncTime
Assert-AreEqual "false" $sto.GeoReplicationStats.CanPlannedFailover
Assert-AreEqual "Standard_LRS" $sto.GeoReplicationStats.PostFailoverRedundancy
Assert-AreEqual "Standard_RAGRS" $sto.GeoReplicationStats.PostPlannedFailoverRedundancy

Retry-IfException { Remove-AzStorageAccount -Force -ResourceGroupName $rgname -Name $stoname; }
}
Expand Down

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Storage/Storage.Management/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
## Upcoming Release

## Version 9.2.0
* Supported Storage account planned failover: `Invoke-AzStorageAccountFailover`, `Get-AzStorageAccount`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the changelog to ## Upcoming Release

* Supported Zone and ZonePlacementPolicy on Storage accounts: `New-AzStorageAccount`, `Set-AzStorageAccount`
* Supported listing Storage SKU: `Get-AzStorageSku`
* Supported enabling SMB Oauth on Storage accounts: `New-AzStorageAccount`, `Set-AzStorageAccount`
Expand Down
17 changes: 12 additions & 5 deletions src/Storage/Storage.Management/Models/PSGeoReplicationStats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,24 @@ public static PSGeoReplicationStats ParsePSGeoReplicationStats(GeoReplicationSta
return null;
}

PSGeoReplicationStats pSGeoReplicationStats = new PSGeoReplicationStats();

pSGeoReplicationStats.Status = geoReplicationStats.Status;
pSGeoReplicationStats.LastSyncTime = geoReplicationStats.LastSyncTime;
pSGeoReplicationStats.CanFailover = geoReplicationStats.CanFailover;
PSGeoReplicationStats pSGeoReplicationStats = new PSGeoReplicationStats
{
Status = geoReplicationStats.Status,
LastSyncTime = geoReplicationStats.LastSyncTime,
CanFailover = geoReplicationStats.CanFailover,
CanPlannedFailover = geoReplicationStats.CanPlannedFailover,
PostFailoverRedundancy = geoReplicationStats.PostFailoverRedundancy,
PostPlannedFailoverRedundancy = geoReplicationStats.PostPlannedFailoverRedundancy
};

return pSGeoReplicationStats;
}

public string Status { get; set; }
public DateTime? LastSyncTime { get; set; }
public bool? CanFailover { get; set; }
public bool? CanPlannedFailover { get; set; }
public string PostFailoverRedundancy { get; set; }
public string PostPlannedFailoverRedundancy { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ public class InvokeAzureStorageAccountFailoverCommand : StorageAccountBaseCmdlet
[ValidateNotNullOrEmpty]
public string Name { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "Specify the failover type. Possible values are: Unplanned, Planned. If not specified, the default failover type is Unplanned.")]
[PSArgumentCompleter(AccountFailoverType.Planned,
AccountFailoverType.Unplanned)]
public string FailoverType { get; set; }

[Parameter(Mandatory = true,
HelpMessage = "Storage account object",
ValueFromPipeline = true,
Expand All @@ -83,30 +90,53 @@ public override void ExecuteCmdlet()

if (ShouldProcess(this.Name, "Invoke Failover of Storage Account"))
{
StringBuilder shouldContinuePrompt = new StringBuilder();
shouldContinuePrompt.AppendLine("Failover the storage account, the secondary cluster will become primary after failover. Please understand the following impact to your storage account before you initiate the failover:");
shouldContinuePrompt.AppendLine(" 1. Please check the Last Sync Time using Get-"+ ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "StorageAccount cmdlet with -IncludeGeoReplicationStats parameter, and check GeoReplicationStats property of your account. This is the data you may lose if you initiate the failover.");
shouldContinuePrompt.AppendLine(" 2. After the failover, your storage account type will be converted to locally redundant storage (LRS). You can convert your account to use geo-redundant storage (GRS).");
shouldContinuePrompt.AppendLine(" 3. Once you re-enable GRS for your storage account, Microsoft will replicate data to your new secondary region. Replication time is dependent on the amount of data to replicate. Please note that there are bandwidth charges for the bootstrap. Please refer to doc: https://azure.microsoft.com/en-us/pricing/details/bandwidth/");


if (this.force || ShouldContinue(shouldContinuePrompt.ToString(), ""))
if (ParameterSetName == AccountObjectParameterSet)
{
if (ParameterSetName == AccountObjectParameterSet)
this.ResourceGroupName = InputObject.ResourceGroupName;
this.Name = InputObject.StorageAccountName;
}

StorageModels.FailoverType? type = null;
if (!String.IsNullOrEmpty(this.FailoverType)) {
if (this.FailoverType.ToLower() == AccountFailoverType.Planned.ToLower())
{
this.ResourceGroupName = InputObject.ResourceGroupName;
this.Name = InputObject.StorageAccountName;
type = StorageModels.FailoverType.Planned;
}
else if (this.FailoverType.ToLower() != AccountFailoverType.Unplanned.ToLower())
{
throw new ArgumentException(string.Format("The Failover Type {0} is invalid.", this.FailoverType), "FailoverType");
}
}

this.StorageClient.StorageAccounts.Failover(
this.ResourceGroupName,
this.Name);

var storageAccount = this.StorageClient.StorageAccounts.GetProperties(this.ResourceGroupName, this.Name);
if (type == null) {
StringBuilder shouldContinuePrompt = new StringBuilder();
shouldContinuePrompt.AppendLine("Failover the storage account, the secondary cluster will become primary after failover. Please understand the following impact to your storage account before you initiate the failover:");
shouldContinuePrompt.AppendLine(" 1. Please check the Last Sync Time using Get-" + ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "StorageAccount cmdlet with -IncludeGeoReplicationStats parameter, and check GeoReplicationStats property of your account. This is the data you may lose if you initiate the failover.");
shouldContinuePrompt.AppendLine(" 2. After the failover, your storage account type will be converted to locally redundant storage (LRS). You can convert your account to use geo-redundant storage (GRS).");
shouldContinuePrompt.AppendLine(" 3. Once you re-enable GRS for your storage account, Microsoft will replicate data to your new secondary region. Replication time is dependent on the amount of data to replicate. Please note that there are bandwidth charges for the bootstrap. Please refer to doc: https://azure.microsoft.com/en-us/pricing/details/bandwidth/");

if (this.force || ShouldContinue(shouldContinuePrompt.ToString(), ""))
{
ExecuteFailover(type);
}

WriteStorageAccount(storageAccount, DefaultContext);
} else
{
ExecuteFailover(type);
}
}
}

private void ExecuteFailover(StorageModels.FailoverType? type = null)
{
this.StorageClient.StorageAccounts.Failover(
this.ResourceGroupName,
this.Name,
type);

var storageAccount = this.StorageClient.StorageAccounts.GetProperties(this.ResourceGroupName, this.Name);

WriteStorageAccount(storageAccount, DefaultContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ protected struct DefaultSharePermissionType
internal const string StorageFileDataSmbShareOwner = "StorageFileDataSmbShareOwner";
}

protected struct AccountFailoverType
{
internal const string Planned = "Planned";
internal const string Unplanned = "Unplanned";
}

public IStorageManagementClient StorageClient
{
get
Expand Down
21 changes: 19 additions & 2 deletions src/Storage/Storage.Management/help/Get-AzStorageAccount.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Get-AzStorageAccount

This command gets all of the Storage accounts in the subscription.

### Example 4: Get a Storage accounts with its blob restore status
### Example 4: Get a Storage account with its blob restore status
```powershell
$account = Get-AzStorageAccount -ResourceGroupName "myresourcegoup" -Name "mystorageaccount" -IncludeBlobRestoreStatus

Expand All @@ -70,7 +70,24 @@ Status RestoreId FailureReason Parameters.TimeToR
InProgress a70cd4a1-f223-4c86-959f-cc13eb4795a8 2020-02-10T13:45:04.7155962Z [container1/blob1 -> container2/blob2]
```

This command gets a Storage accounts with its blob restore status, and show the blob restore status.
This command gets a Storage account with its blob restore status, and show the blob restore status.

### Example 5: Get a Storage account with its geo-replication stats
```powershell
$account = Get-AzStorageAccount -ResourceGroupName myresourcegroup -Name myaccount -IncludeGeoReplicationStats
$account.GeoReplicationStats
```

```output
Status : Live
LastSyncTime : 10/21/2025 3:42:38 AM
CanFailover : True
CanPlannedFailover : True
PostFailoverRedundancy : Standard_LRS
PostPlannedFailoverRedundancy : Standard_GRS
```

This command gets a Storage account with its geo-replication stats, and shows the geo-replication stats.

## PARAMETERS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ Invokes failover of a Storage account.

### AccountName (Default)
```
Invoke-AzStorageAccountFailover [-ResourceGroupName] <String> [-Name] <String> [-Force] [-AsJob]
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm]
Invoke-AzStorageAccountFailover [-ResourceGroupName] <String> [-Name] <String> [-FailoverType <String>]
[-Force] [-AsJob] [-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
[<CommonParameters>]
```

### AccountObject
```
Invoke-AzStorageAccountFailover -InputObject <PSStorageAccount> [-Force] [-AsJob]
Invoke-AzStorageAccountFailover [-FailoverType <String>] -InputObject <PSStorageAccount> [-Force] [-AsJob]
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm]
[<CommonParameters>]
```
Expand All @@ -36,24 +36,64 @@ Please understand the following impact to your storage account before you initia

## EXAMPLES

### Example 1: Invoke failover of a Storage account
### Example 1: Invoke an unplanned failover of a Storage account
<!-- Skip: Output cannot be splitted from code -->


```
$account = Get-AzStorageAccount -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount" -IncludeGeoReplicationStats
$account.GeoReplicationStats

Status LastSyncTime
------ ------------
Live 11/13/2018 2:44:22 AM
Status : Live
LastSyncTime : 10/21/2025 3:42:38 AM
CanFailover : True
CanPlannedFailover : True
PostFailoverRedundancy : Standard_LRS
PostPlannedFailoverRedundancy : Standard_GRS

$job = Invoke-AzStorageAccountFailover -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount" -Force -AsJob
$job | Wait-Job
```

This command check the last sync time of a Storage account then invokes failover of it, the secondary cluster will become primary after failover. Since failover takes a long time, suggest to run it in the backend with -Asjob parameter, and then wait for the job complete.

### Example 2: Invoke a planned failover of a Storage account
<!-- Skip: Output cannot be splitted from code -->
```
PS C:\>$account = Get-AzStorageAccount -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount" -IncludeGeoReplicationStats
PS C:\>$account.GeoReplicationStats

Status : Live
LastSyncTime : 10/21/2025 3:42:38 AM
CanFailover : True
CanPlannedFailover : True
PostFailoverRedundancy : Standard_LRS
PostPlannedFailoverRedundancy : Standard_GRS

PS C:\>$job = Invoke-AzStorageAccountFailover -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount" -FailoverType Planned -Force -AsJob
PS C:\>$job | Wait-Job
```
This command checks the last sync time and canFailover status of a Storage account and then invokes a planned failover of it.

### Example 3: Invoke an unplanned failover of a Storage account with FailoverType set to Unplanned
<!-- Skip: Output cannot be splitted from code -->
```
PS C:\>$account = Get-AzStorageAccount -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount" -IncludeGeoReplicationStats
PS C:\>$account.GeoReplicationStats

Status : Live
LastSyncTime : 10/21/2025 3:42:38 AM
CanFailover : True
CanPlannedFailover : True
PostFailoverRedundancy : Standard_LRS
PostPlannedFailoverRedundancy : Standard_GRS

PS C:\>$job = Invoke-AzStorageAccountFailover -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount" -FailoverType Unplanned -Force -AsJob
PS C:\>$job | Wait-Job
```
This command checks the last sync time and canFailover status of a Storage account and then invokes an unplanned failover of it.


## PARAMETERS

### -AsJob
Expand Down Expand Up @@ -86,6 +126,21 @@ Accept pipeline input: False
Accept wildcard characters: False
```

### -FailoverType
Specify the failover type. Possible values are: Unplanned, Planned. If not specified, the default failover type is Unplanned.

```yaml
Type: System.String
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -Force
Force to Failover the Account

Expand Down Expand Up @@ -182,7 +237,7 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable

## INPUTS

### System.String
### Microsoft.Azure.Commands.Management.Storage.Models.PSStorageAccount

## OUTPUTS

Expand Down