Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/Migrate/Migrate.Autorest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ input-file:
- $(repo)/specification/recoveryservicessiterecovery/resource-manager/Microsoft.RecoveryServices/stable/2024-01-01/service.json
- $(repo)/specification/recoveryservicesdatareplication/resource-manager/Microsoft.DataReplication/stable/2024-09-01/recoveryservicesdatareplication.json

module-version: 3.0.12
module-version: 3.0.13
title: Migrate
subject-prefix: 'Migrate'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,15 @@ function Get-AzMigrateLocalServerReplication {
)

process {
Import-Module $PSScriptRoot\Helper\AzLocalCommonSettings.ps1
$helperPath = Join-Path $PSScriptRoot 'Helper' 'AzLocalCommonSettings.ps1'
Import-Module $helperPath
$helperPath = Join-Path $PSScriptRoot 'Helper' 'AzLocalCommonHelper.ps1'
Import-Module $helperPath

$hasTargetObjectId = $PSBoundParameters.ContainsKey('TargetObjectID')
$hasDiscoveredMachineId = $PSBoundParameters.ContainsKey('DiscoveredMachineId')
$hasResourceGroupId = $PSBoundParameters.ContainsKey('ResourceGroupID')
$hasProjectId = $PSBoundParameters.ContainsKey('ProjectID')

$parameterSet = $PSCmdlet.ParameterSetName
$null = $PSBoundParameters.Remove('TargetObjectID')
Expand All @@ -143,16 +151,32 @@ function Get-AzMigrateLocalServerReplication {
$null = $PSBoundParameters.Remove('ResourceGroupID')
$null = $PSBoundParameters.Remove('ProjectID')
$null = $PSBoundParameters.Remove('MachineName')

# Validate ARM ID format from inputs
if ($hasTargetObjectId -and !(Test-AzureResourceIdFormat -Data $TargetObjectID -Format $IdFormats.ProtectedItemArmIdTemplate)) {
throw "Invalid -TargetObjectID '$TargetObjectID'. A valid protected item ARM ID should follow the format '$($IdFormats.ProtectedItemArmIdTemplate)'."
}

if ($hasDiscoveredMachineId -and !(Test-AzureResourceIdFormat -Data $DiscoveredMachineId -Format $IdFormats.MachineArmIdTemplate)) {
throw "Invalid -DiscoveredMachineId '$DiscoveredMachineId'. A valid machine ARM ID should follow the format '$($IdFormats.MachineArmIdTemplate)'."
}

if ($hasResourceGroupId -and !(Test-AzureResourceIdFormat -Data $ResourceGroupID -Format $IdFormats.ResourceGroupArmIdTemplate)) {
throw "Invalid -ResourceGroupID '$ResourceGroupID'. A valid resource group ARM ID should follow the format '$($IdFormats.ResourceGroupArmIdTemplate)'."
}

if ($hasProjectId -and !(Test-AzureResourceIdFormat -Data $ProjectID -Format $IdFormats.MigrateProjectArmIdTemplate)) {
throw "Invalid -ProjectID '$ProjectID'. A valid migrate project ARM ID should follow the format '$($IdFormats.MigrateProjectArmIdTemplate)'."
}

if ($parameterSet -eq 'GetBySDSID') {
# $DiscoveredMachineId is in the format of
# "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.OffAzure/{2}/{3}/machines/{4}"
$machineIdArray = $DiscoveredMachineId.Split("/")
if ($machineIdArray.Length -lt 11) {
throw "Invalid machine ARM ID '$DiscoveredMachineId'"
}
$siteType = $machineIdArray[7]
$siteName = $machineIdArray[8]
$ResourceGroupName = $machineIdArray[4]
$ProtectedItemName = $machineIdArray[10]
$ResourceGroupName = $machineIdArray[4] # {1}
$siteType = $machineIdArray[7] # {2}
$siteName = $machineIdArray[8] # {3}
$ProtectedItemName = $machineIdArray[10] # {4}

$null = $PSBoundParameters.Add('ResourceGroupName', $ResourceGroupName)
$null = $PSBoundParameters.Add('SiteName', $siteName)
Expand Down Expand Up @@ -207,19 +231,14 @@ function Get-AzMigrateLocalServerReplication {
if (($parameterSet -match 'List') -or ($parameterSet -eq 'GetByMachineName')) {
# Retrieve ResourceGroupName, ProjectName if ListByID
if ($parameterSet -eq 'ListByID') {
# $ResourceGroupID is in the format of "/subscriptions/{0}/resourceGroups/{1}"
$resourceGroupIdArray = $ResourceGroupID.Split('/')
if ($resourceGroupIdArray.Length -lt 5) {
throw "Invalid resource group Id '$ResourceGroupID'."
}

$ResourceGroupName = $resourceGroupIdArray[4]
$ResourceGroupName = $resourceGroupIdArray[4] # {1}

# ProjecyID is in the format of
# "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Migrate/MigrateProjects/{2}"
$projectIdArray = $ProjectID.Split('/')
if ($projectIdArray.Length -lt 9) {
throw "Invalid migrate project Id '$ProjectID'."
}

$ProjectName = $projectIdArray[8]
$ProjectName = $projectIdArray[8] # {2}
}

$amhSolutionName = "Servers-Migration-ServerMigration_DataReplication"
Expand Down Expand Up @@ -254,14 +273,13 @@ function Get-AzMigrateLocalServerReplication {
if ($parameterSet -eq 'GetByInputObject') {
$TargetObjectID = $InputObject.Id
}
$objectIdArray = $TargetObjectID.Split("/")
if ($objectIdArray.Length -lt 11) {
throw "Invalid target object ID '$TargetObjectID'."
}

$ResourceGroupName = $objectIdArray[4]
$VaultName = $objectIdArray[8]
$ProtectedItemName = $objectIdArray[10]
# $TargetObjectID is in the format of
# "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DataReplication/replicationVaults/{2}/protectedItems/{3}"
$objectIdArray = $TargetObjectID.Split("/")
$ResourceGroupName = $objectIdArray[4] # {1}
$VaultName = $objectIdArray[8] # {2}
$ProtectedItemName = $objectIdArray[10] # {3}
$null = $PSBoundParameters.Add("ResourceGroupName", $ResourceGroupName)
$null = $PSBoundParameters.Add("VaultName", $VaultName)
$null = $PSBoundParameters.Add("Name", $ProtectedItemName)
Expand Down
77 changes: 77 additions & 0 deletions src/Migrate/Migrate.Autorest/custom/Helper/AzLocalCommonHelper.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,81 @@ function ValidateReplication {
{
Write-Warning $VmReplicationValidationMessages.OsTypeNotSupported
}
}

function Test-AzureResourceIdFormat {
[Microsoft.Azure.PowerShell.Cmdlets.Migrate.DoNotExportAttribute()]
param(
[Parameter(Mandatory = $true)]
[string] $Data,

[Parameter(Mandatory = $true)]
[string] $Format
)

try {
if ([string]::IsNullOrWhiteSpace($Data)) {
return $false
}

# Find where format string starts (after first /)
$firstTokenEnd = $Format.IndexOf("/", 1)
if ($firstTokenEnd -eq -1) {
return $false
}

$formatPrefix = $Format.Substring(0, $firstTokenEnd)
$matchIndex = $Data.ToLower().IndexOf($formatPrefix.ToLower())

if ($matchIndex -eq -1) {
return $false
}

$processData = $Data.Substring($matchIndex)
$processFormat = $Format
$tokens = @()

$counter = 0
while ($true) {
$markerPattern = "{$counter}"
$markerStartIndex = $processFormat.IndexOf($markerPattern)

if ($markerStartIndex -eq -1) {
break
}

$markerEndIndex = $processData.IndexOf("/", $markerStartIndex)

if ($markerEndIndex -eq -1) {
$token = $processData.Substring($markerStartIndex)
if ([string]::IsNullOrWhiteSpace($token)) {
return $false
}
$tokens += $token
}
else {
$token = $processData.Substring($markerStartIndex, $markerEndIndex - $markerStartIndex)
if ([string]::IsNullOrWhiteSpace($token)) {
return $false
}
$tokens += $token
$processData = $processData.Substring($markerEndIndex)
$processFormat = $processFormat.Substring($markerStartIndex + $markerPattern.Length)
}

$counter++
}

# Verify format matches with the extracted tokens
$formatWithTokens = $Format
for ($i = 0; $i -lt $tokens.Count; $i++) {
$formatWithTokens = $formatWithTokens -replace "\{$i\}", $tokens[$i]
}

return $Data.ToLower() -like $formatWithTokens.ToLower()
}
catch
{
return $false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,25 @@ $VmReplicationValidationMessages = @{
$ArcResourceBridgeValidationMessages = @{
NotRunning = "Arc Resource Bridge is offline. To continue, bring the Arc Resource Bridge online. Wait a few minutes for the status to update and retry.";
NoClusters = "There are no Azure Local clusters found in the selected resource group."
}

$IdFormats = @{
ResourceGroupArmIdTemplate = "/subscriptions/{0}/resourceGroups/{1}"
MachineArmIdTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.OffAzure/{2}/{3}/machines/{4}"
StoragePathArmIdTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.AzureStackHCI/storageContainers/{2}"
LogicalNetworkArmIdTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.AzureStackHCI/logicalnetworks/{2}"
MigrateProjectArmIdTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Migrate/MigrateProjects/{2}"
ProtectedItemArmIdTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DataReplication/replicationVaults/{2}/protectedItems/{3}"
}

$TargetVMCPUCores = @{
Min = 1
Max = 64
}

$TargetVMRamInMB = @{
Gen1Min = 512
Gen1Max = 1048576 # 1 TB
Gen2Min = 32
Gen2Max = 12582912 # 12 TB
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,10 @@ function Initialize-AzMigrateLocalReplicationInfrastructure {
)

process {
Import-Module $PSScriptRoot\Helper\AzLocalCommonSettings.ps1
Import-Module $PSScriptRoot\Helper\AZLocalCommonHelper.ps1
$helperPath = Join-Path $PSScriptRoot 'Helper' 'AzLocalCommonSettings.ps1'
Import-Module $helperPath
$helperPath = Join-Path $PSScriptRoot 'Helper' 'AzLocalCommonHelper.ps1'
Import-Module $helperPath

CheckResourcesModuleDependency
CheckStorageModuleDependency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ function Initialize-AzMigrateReplicationInfrastructure {
Import-Module Az.Resources
Import-Module Az.Storage
Import-Module Az.RecoveryServices
Import-Module $PSScriptRoot\Helper\AzLocalCommonSettings.ps1
$helperPath = Join-Path $PSScriptRoot 'Helper' 'AzLocalCommonSettings.ps1'
Import-Module $helperPath

# Validate user specified target region
$TargetRegion = $TargetRegion.ToLower()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ function New-AzMigrateLocalDiskMappingObject {
process {
$isDynamicDisk = [System.Convert]::ToBoolean($IsDynamic)
$osDisk = [System.Convert]::ToBoolean($IsOSDisk)
$hasPhysicalSectorSize = $PSBoundParameters.ContainsKey('PhysicalSectorSize')

if ($Format -eq "VHD" -and $PhysicalSectorSize -ne 512) {
throw "PhysicalSectorSize must be 512 for VHD format."
if ($Format -eq "VHD" -and $hasPhysicalSectorSize -and $PhysicalSectorSize -ne 512) {
throw "PhysicalSectorSize must be 512 for VHD format but $PhysicalSectorSize is given."
}

$DiskObject = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20240901.AzLocalDiskInput]::new(
Expand Down
Loading
Loading