Util/Util.psm1
using module '../Common/Result' Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Common | Join-Path -ChildPath Error | Join-Path -ChildPath Error) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Common | Join-Path -ChildPath Wrappers | Join-Path -ChildPath Wrappers) function Test-UserLoggedIn { param() [RMReturn] $RMReturn = [RMReturn]::new() if (-not (Get-Variable -Name "RMContext-UserLogin" -ErrorAction SilentlyContinue)) { $UserMessage = "Please login using the cmdlet 'Invoke-RMLogin' and try again." Write-RMError -Message $UserMessage [RMError] $RMError = [RMError]::new("login_required", $UserMessage) $RMReturn.AddRMError($RMError) $RMReturn.SetReturnCode([RMReturn]::ERROR) return $RMReturn } $RMReturn.SetReturnCode([RMReturn]::SUCCESS) return $RMReturn } # TODO: This wrapper is not doing much, can be removed. function Invoke-RMRestMethod { param( [hashtable] $Params ) return Invoke-RestMethod @Params } function Invoke-RMMigrationProfilePost { param ( [hashtable] $MigrationProfile ) # Giving max depth otherwise the cmdlet 'ConvertTo-Json' will truncate the JSON $MigrationProfileJson = $MigrationProfile |ConvertTo-Json -Depth 100 $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.token } $Params = @{ Method = "Post" Uri = $Uri + "/migrationprofiles" Body = $MigrationProfileJson ContentType = "application/json" Headers = $Headers } Invoke-RMRestMethod -Params $Params } function Invoke-RMMigrationPost { param( [System.Object] $MigrationProfileResponse ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Post" Uri = $Uri.Value + "/migrationprofiles/" + $MigrationProfileResponse.id + "/migrations" Headers = $Headers ContentType = "application/json" } return Invoke-RMRestMethod -Params $Params } function Invoke-RMDifferentialProfilePost { param ( [System.Object] $DifferentialProfile ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.token } $Params = @{ Method = "Post" Uri = $Uri + "/differentialprofiles" Body = $DifferentialProfile ContentType = "application/json" Headers = $Headers } return Invoke-RMRestMethod -Params $Params } function Invoke-RMDifferentialMigrationPost { param ( [System.Object] $DifferentialProfileResponse ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Post" Uri = $Uri.Value + "/differentialprofiles/" + $DifferentialProfileResponse.id + "/migrations" Headers = $Headers ContentType = "application/json" } return Invoke-RMRestMethod -Params $Params } function Get-RMStringAsHashtable { param( [string] $InputString ) $Result = @{} if (!("" -ne $InputString -and $InputString.Contains("="))) { return $Result } foreach ($item in $InputString.Split(",").Trim()) { $item = $item.Split("=") $Result.add($item[0].Trim(), $item[1].Trim()) } return $Result } function Get-RMStringArrayAsHashtable { param( [string[]] $InputItems, [string] $ParameterName ) $Result = @{} if ($null -eq $InputItems -or 0 -eq $InputItems.Count) { return $Result } foreach ($item in $InputItems) { if (!$item.Contains("=")) { throw "$ParameterName is invalid, each item in '$ParameterName' must be of the format 'key=value'" } $item = $item.Split("=") $Result.add($item[0].Trim(), $item[1].Trim()) } return $Result } function Get-RMVolumeType { param( [string] $VolumeType, [bool] $SupportVolumeType ) if ("GP2" -ieq $VolumeType) { return "ssd2" } if ("GP3" -ieq $VolumeType) { return "ssd3" } if ("magnetic" -ieq $VolumeType) { return "magnetic" } if ("IO1" -ieq $VolumeType -and $SupportVolumeType) { return "iops_ssd" } if ("IO2" -ieq $VolumeType -and $SupportVolumeType) { return "iops2_ssd" } throw "Unsupported volume type '$VolumeType'" } function Get-RMExcludedMountPoint { param( [System.Object[]] $MountPoints, [string] $OSType, [bool] $IsDifferentialMigration ) while ($true) { $ReadValue = Read-RMString -UserMessage "Enter the mount points to be excluded, separated by commas" ` -DefaultValue "None" -IsRequired $false -ParameterName "Mount points to be excluded" if ("" -eq $ReadValue) { return $ReadValue } $MountsToExclude = $ReadValue.Split(",").Trim() if ("windows" -ieq $OSType) { if (!$IsDifferentialMigration -and $MountsToExclude -contains "c") { Write-RMError -Message "Cannot exclude 'C' drive, please try again." continue } } elseif ($IsDifferentialMigration) { $MountsNotExcludeList = @("/", "/bin", "/boot" , "/dev", "/etc", "/home", "/lib" , "/mnt", "/opt", "/proc", "/root", "/run", "/sbin", "/srv", "/tmp", "/usr", "/var") $Results = Compare-Object -ReferenceObject $MountsNotExcludeList -DifferenceObject $MountsToExclude -IncludeEqual if ($Results.SideIndicator -contains "==") { $ExcludedMountPointList = @() foreach ($Result in $Results) { if ($Result.SideIndicator -eq "==") { $ExcludedMountPointList += $Result.InputObject } } $ExcludedMountPointListAsString = $ExcludedMountPointList -join ", " Write-RMError -Message "Cannot exclude mount points '$ExcludedMountPointListAsString', please try again." continue } }elseif ($MountsToExclude -contains "/" -or $MountsToExclude -contains "/boot" -or $MountsToExclude -contains "/usr") { Write-RMError -Message "Cannot exclude mount points '/', '/boot' or '/usr', please try again." continue } $Result = Test-RMNonExistentMountPoints -SourceMountPoints $MountPoints -UserInputMountPoints $MountsToExclude if (0 -ne $Result.Count) { $ResultAsString = $Result -join ", " Write-RMError -Message "Mount points '$ResultAsString' does not exist on source and hence cannot be excluded, please try again." continue } return $ReadValue } } function Get-RMSelectedMount { param( [System.Object[]] $MountPoints, [System.Object[]] $DifferenceList, [bool] $IncludeEqual ) $SelectedMountPoints = @() foreach($MountPoint in $MountPoints) { $Result = Compare-Object -ReferenceObject $MountPoint.values -DifferenceObject $DifferenceList -IncludeEqual if ($IncludeEqual) { if ($Result.SideIndicator -contains "==") { $SelectedMountPoints += $MountPoint } } elseif (!($Result.SideIndicator -contains "==")) { $SelectedMountPoints += $MountPoint } } return $SelectedMountPoints } function Compare-RMMountPoint { param( [System.Object] $Source, [System.Object[]] $SourceMountPoints, [System.Object[]] $UserInputMountPoints, [string] $ParameterName ) $Errors = @() if("windows" -ieq $Source.os_type) { if ($UserInputMountPoints -inotcontains "c") { $Errors += "Mount point 'C' was not included in parameter '$ParameterName', mount point 'C' is required." } return $Errors } if ($SourceMountPoints -contains "/" -and $UserInputMountPoints -notcontains "/") { $Errors += "Mount point '/' was not included in parameter '$ParameterName', mount point '/' is required." } if ($SourceMountPoints -contains "/boot" -and $UserInputMountPoints -notcontains "/boot") { $Errors += "Mount point '/boot' was not included in parameter '$ParameterName', mount point '/boot' is required." } if ($SourceMountPoints -contains "/usr" -and $UserInputMountPoints -notcontains "/usr") { $Errors += "Mount point '/usr' was not included in parameter '$ParameterName', mount point '/usr' is required." } return $Errors } function Test-RMNonExistentMountPoints { param( [System.Object[]] $SourceMountPoints, [System.Object[]] $UserInputMountPoints ) $NonExistentMountPoints = @() $Results = Compare-Object -ReferenceObject $SourceMountPoints -DifferenceObject $UserInputMountPoints -IncludeEqual if ($Results.SideIndicator -contains "=>") { foreach ($Result in $Results) { if ($Result.SideIndicator -eq "=>") { $NonExistentMountPoints += $Result.InputObject } } } return $NonExistentMountPoints } function Watch-RMPreflightStatus { param( [string] $PreflightId, [string] $TimeOutMessage ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Get" Uri = $Uri.Value + "/preflights/" + $PreflightId Headers = $Headers } $Timeout30MinsInSeconds = 30 * 60 $StartTime = [DateTimeOffset]::Now.ToUnixTimeSeconds() # The below sleep is needed to allow the cassandra and solr to # get in-sync; otherwise, we may get "resource not found error". Start-Sleep -Milliseconds 300 $Response = Invoke-RMRestMethod -Params $Params while ($Response.state -ne "success" -and $Response.state -ne "error") { $TimeNow = [DateTimeOffset]::Now.ToUnixTimeSeconds() if (($TimeNow - $StartTime) -gt $Timeout30MinsInSeconds) { throw $TimeOutMessage } Start-Sleep -Seconds 5 $Response = Invoke-RMRestMethod -Params $Params } return $Response } function Watch-RMTargetInventoryStatus { param( [string] $TargetInventoryId ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Get" Uri = $Uri.Value + "/targetinventories/" + $TargetInventoryId Headers = $Headers } $Timeout30MinsInSeconds = 30 * 60 $StartTime = [DateTimeOffset]::Now.ToUnixTimeSeconds() Write-Output "Waiting for target inventory to complete..." | Out-Host $Response = Invoke-RMRestMethod -Params $Params while ($Response.state -ne "success" -and $Response.state -ne "error") { $TimeNow = [DateTimeOffset]::Now.ToUnixTimeSeconds() if (($TimeNow - $StartTime) -gt $Timeout30MinsInSeconds) { throw "Timed out while waiting for target inventory to complete" } Start-Sleep -Seconds 5 $Response = Invoke-RMRestMethod -Params $Params } return $Response } function Get-RMMigrationExtension { param ( [guid] $OrganizationId ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Get" Uri = $Uri.Value + "/organizations/" + $OrganizationId + "/binaryassets?size=500&status=upload_available" Headers = $Headers } return Invoke-RMRestMethod -Params $Params } function Get-RMWindowsOSMMapping { param() # ME OSM name to user label return @{ "Windows 10 Pro" = "Windows 10 Pro" "Windows 10 Enterprise" = "Windows 10 Enterprise" "Windows 11 Pro" = "Windows 11 Pro" "Windows 11 Enterprise" = "Windows 11 Enterprise" "Windows Server 2008 R2 SERVERSTANDARD" = "Windows Server 2008 R2 Standard" "Windows Server 2008 R2 SERVERDATACENTER" = "Windows Server 2008 R2 Datacenter" "Windows Server 2012 SERVERSTANDARD" = "Windows Server 2012 Standard" "Windows Server 2012 SERVERDATACENTER" = "Windows Server 2012 Datacenter" "Windows Server 2012 R2 SERVERSTANDARD" = "Windows Server 2012 R2 Standard" "Windows Server 2012 R2 SERVERDATACENTER" = "Windows Server 2012 R2 Datacenter" "Windows Server 2016 SERVERSTANDARD" = "Windows Server 2016 Standard" "Windows Server 2016 SERVERSTANDARDCORE" = "Windows Server 2016 Standard Core" "Windows Server 2016 SERVERDATACENTER" = "Windows Server 2016 Datacenter" "Windows Server 2016 SERVERDATACENTERCORE" = "Windows Server 2016 Datacenter Core" "Windows Server 2019 SERVERSTANDARD" = "Windows Server 2019 Standard" "Windows Server 2019 SERVERSTANDARDCORE" = "Windows Server 2019 Standard Core" "Windows Server 2019 SERVERDATACENTER" = "Windows Server 2019 Datacenter" "Windows Server 2019 SERVERDATACENTERCORE" = "Windows Server 2019 Datacenter Core" "Windows Server 2022 SERVERSTANDARD" = "Windows Server 2022 Standard" "Windows Server 2022 SERVERSTANDARDCORE" = "Windows Server 2022 Standard Core" "Windows Server 2022 SERVERDATACENTER" = "Windows Server 2022 Datacenter" "Windows Server 2022 SERVERDATACENTERCORE" = "Windows Server 2022 Datacenter Core" } } function Get-RMLinuxOSMMapping { param() # ME OSM name to user label return @{ "RHEL7" = "Red Hat Enterprise Linux Server 7.9" "RHEL8" = "Red Hat Enterprise Linux Server 8" "RHEL9" = "Red Hat Enterprise Linux Server 9" "RHEL610" = "Red Hat Enterprise Linux Server 6.1" "CENTOS7" = "CentOS 7.9" "CENTOS610" = "CentOS 6.1" "SLES15SP1" = "SUSE Linux Enterprise Server 15 SP1" "UBUNTU1604LTS" = "Ubuntu 16.04 LTS" "ROCKY8" = "Rocky Linux 8" "ROCKY9" = "Rocky Linux 9" "ALMA8" = "Alma Linux 8" "ALMA9" = "Alma Linux 9" } } function Get-RMOSMMappingBySource { param( [System.Object] $Source ) $ResultOSMMapping = @{} $OSMMapping = @{} if ($null -eq $Source -or $null -eq $Source.attributes ` -or $null -eq $Source.attributes.os ` -or $null -eq $Source.attributes.os.source_migration_state) { return $ResultOSMMapping } if ($Source.os_type -eq "windows") { $OSMMapping = Get-RMWindowsOSMMapping } else { $OSMMapping = Get-RMLinuxOSMMapping } $SourceMigrationState = $Source.attributes.os.source_migration_state | ConvertFrom-Json foreach ($UpgradeOption in $SourceMigrationState.upgrade_options) { # Mapping of label to ME OSM name - this will be helpful as the user will be # providing labels and we need to send ME OSM name to ME. if ($OSMMapping.ContainsKey($UpgradeOption)) { $ResultOSMMapping.Add($OSMMapping[$UpgradeOption], $UpgradeOption) } else { Write-Warning "Newer version of cmdlet is needed, couldn't find upgrade option '$UpgradeOption'" | Out-Host } } return $ResultOSMMapping } function Get-RMSQLMMappingBySource { param ( [System.Object] $Source ) $ResultSQLMMapping = @() $InstalledProgram = $Source.attributes.os.installed_programs | Where-Object {$_.product_family -ieq "mssql"} foreach($Program in $InstalledProgram) { if ("" -ne $Program.upgrade_options) { if (![string]::IsNullOrWhiteSpace($Program.additional_info.display_short_name)) { $DisplayName = $Program.additional_info.display_short_name + " - Instance: " + $Program.additional_info.instance_name } else { $DisplayName = $Program.display_name -replace " Database Engine Services" , "" + " - Instance: " + $Program.additional_info.instance_name } $UpgradeOptions = Get-RMSQLServerUpgradeOptionDisplayValueAndGUID -UpgradeOption $Program.upgrade_options $ResultSQLMMapping += Get-RMSQLMapping -DisplayName $DisplayName -InstanceName $Program.additional_info.instance_name ` -UpgradeOptions $UpgradeOptions -GUID $Program.guid } } return $ResultSQLMMapping } function Get-RMSQLServerUpgradeOptionDisplayValueAndGUID { param ( [string[]] $UpgradeOption ) $OptionArray = @() foreach ($Option in $UpgradeOption) { switch ($Option) { "MSSQL2016" { $OptionArray += "2016"; Break } "MSSQL2019" { $OptionArray += "2019"; Break } "MSSQL2022" { $OptionArray += "2022"; } } } return $OptionArray } function Get-RMSQLMapping { param( [string] $DisplayName, [string] $InstanceName, [string[]] $UpgradeOptions, [guid] $GUID ) $SQLObject = @{ "display_name" = $DisplayName "instance_name" = $InstanceName "upgrade_options" = $UpgradeOptions "guid" = $GUID } return $SQLObject } function Add-RMResizeMount { param( [string[]] $SelectedMounts, [hashtable] $ResizeMounts, [object] $Source ) $MountsResizeErrors = @() $ResizeMountList = @() $ResizeMounts.keys | ForEach-Object { $ResizeMountList += $_ } $Result = Compare-Object -ReferenceObject $SelectedMounts -DifferenceObject $ResizeMountList -IncludeEqual if ($Result.SideIndicator -contains "=>") { $MountsResizeErrors += "Resize mount points contains a mount point that has not been selected for migration, please check and try again" return $null, $MountsResizeErrors } $IsValidData = $true $MountsResize = @{} $SourceMountPointObjects = Get-RMMountPointObject -Source $Source foreach ($Mount in $ResizeMounts.keys) { foreach ($MountPoint in $SourceMountPointObjects) { $MountPath = $MountPoint.path if ($MountPath -ne $Mount) { continue } $TotalSpace = [math]::round($MountPoint.size_kb/(1024 * 1024), 2) $UsedSpace = [math]::round($MountPoint.used_kb/(1024 * 1024), 2) $ResizeValue = $ResizeMounts[$Mount] if (-not($ResizeValue -match "^[\d]+$")) { $MountsResizeErrors += "Mount point '$MountPath' contains non-integer resize value '$ResizeValue', please enter an integer value only" $IsValidData = $false continue } $ResizeValue = $ResizeValue -as [int] if (-not($ResizeValue -gt $UsedSpace -and $ResizeValue -lt $TotalSpace)) { $MountsResizeErrors += "Resize value for mount point '$MountPath' is not valid, resize value should not be greater than the current total size or less than the used size" $IsValidData = $false continue } $MountResizeInKiB = $ResizeValue * 1024 * 1024 $MountsResize.Add($MountPath, $MountResizeInKiB) break } } if (!$IsValidData) { return $null, $MountsResizeErrors } return $MountsResize, $MountsResizeErrors } function Get-RMMountPointObject { param( [System.Object] $Source ) $MountPoints = @() if ("windows" -ieq $Source.os_type) { foreach ($Mount in $Source.attributes.storage.mounts.psobject.properties.value) { $MountPoints += $Mount } } else { foreach ($Mount in $Source.attributes.storage.mounts.psobject.properties.value) { if ("disk" -ieq $Mount.nature -or "subvolume" -ieq $Mount.nature -and "squashfs" -ine $Mount.fs_type) { $MountPoints += $Mount } } } return $MountPoints } function Get-RMPartition { param ( [System.Object[]] $SelectedMounts ) $Partitions = @() foreach($MountPoint in $SelectedMounts) { $Partitions += $MountPoint.mount_point } return $Partitions } function Get-RMResizeMountsPoint { param ( [string[]] $ResizeMountPoints, [array] $SelectedMountPoints, [System.Object] $Source ) $Errors = @() try { $ResizeMounts = Get-RMStringArrayAsHashtable -InputItems $ResizeMountPoints -ParameterName "ResizeMountPoints" } catch { $Errors += $PSItem.Exception.Message } $MountsResize = $null $MountsResizeErrors = $null if ($null -ne $ResizeMounts) { $MountsResize, $MountsResizeErrors = Add-RMResizeMount -SelectedMounts $SelectedMountPoints.values -ResizeMounts $ResizeMounts -Source $Source } if ($Errors -gt 0) { $MountsResizeErrors += $Errors } return $MountsResize, $MountsResizeErrors } function Get-RMInteractiveMountsResize { param ( [array] $SelectedMountPoints, [System.Object] $Source ) $MountPointList = @() $SelectedMountPoints | ForEach-Object { $MountPointList += $_.values } $MountsResize = @{} $SourceMountPointObjects = Get-RMMountPointObject -Source $Source foreach ($Mount in $MountPointList) { foreach ($MountPoint in $SourceMountPointObjects) { if ($MountPoint.path -ne $Mount) { continue } $TotalSpace = [math]::round($MountPoint.size_kb/(1024 * 1024), 2) if ([int]$TotalSpace -le 1) { # Cannot resize the disk that is <= 1GiB break } $UsedSpace = [math]::round($MountPoint.used_kb/(1024 * 1024), 2) $RoundedTotalSpace = [math]::Floor($TotalSpace) while ($true) { $ReadValue = Read-Host "Enter new size in GiB for mount point $Mount, current used space is $UsedSpace GiB of total space $TotalSpace GiB [$RoundedTotalSpace GiB]" if ("" -eq $ReadValue) { $ReadValue = $RoundedTotalSpace } if (-not($ReadValue -match "^[\d]+$")) { Write-RMError -Message "Please enter an integer value only" continue } $ReadValue = $ReadValue -as [int] if (-not($ReadValue -gt $UsedSpace -and $ReadValue -le $RoundedTotalSpace)) { Write-RMError -Message "Resize value for mount point '$Mount' is not valid, resize value should not be greater than the current total size or less than the used size" continue } $MountResizeInKiB = $ReadValue * 1024 * 1024 $MountsResize.Add($Mount, $MountResizeInKiB) break } break } } return $MountsResize } function Get-RMMoveGroupList { param ( [string] $OrganizationId, [int] $PageNumber ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.token } $Params = @{ Method = "Get" Uri = $Uri + "/organizations/" + $OrganizationId + "/movegroups?size=25&page=" + $PageNumber +"&sort=name,desc" Headers = $Headers } $Response = Invoke-RMRestMethod -Params $Params return $Response } function Get-MoveGroupByName { param ( [string] $MoveGroupName, [string] $OrganizationId ) $MoveGroupList = @() $Response = Get-RMMoveGroupList -OrganizationId $OrganizationId -PageNumber 0 $MoveGroupList += $Response $MoveGroup = Get-MoveGroup -MoveGroupName $MoveGroupName -MoveGroupList $MoveGroupList.content if ($null -eq $MoveGroup) { for ($index = 1; $index -lt $Response.page.totalPages; $index++) { $MoveGroupList = Get-RMMoveGroupList -OrganizationId $OrganizationId -PageNumber $index $MoveGroup = Get-MoveGroup -MoveGroupName $MoveGroupName -MoveGroupList $MoveGroupList.content if ($null -ne $MoveGroup) { Set-Variable -Name "RMContext-MoveGroup" -Value $MoveGroup -Scope Global return $MoveGroup } } } else { Set-Variable -Name "RMContext-MoveGroup" -Value $MoveGroup -Scope Global return $MoveGroup } return $null } function Get-MoveGroup { param( [string] $MoveGroupName, [array] $MoveGroupList ) foreach($MoveGroup in $MoveGroupList) { if ($MoveGroupName -eq $MoveGroup.name) { return $MoveGroup } } return $null } function Get-RMEntitlement { param() $CurrentProjectId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.token } $Params = @{ Method = "Get" Uri = $Uri + "/organizations/" + $CurrentProjectId + "/entitlements" Headers = $Headers } $Entitlements = Invoke-RMRestMethod -Params $Params foreach ($Entitlement in $Entitlements.content) { $Remaining = $Entitlement.total - $Entitlement.used if ($Remaining -ge 1) { return $Entitlement } } throw "Not enough entitlements available to start the migration" } function Get-RMTransferMethodInternal { param ( [System.Object] $Source, [string[]] $SelectedMountPoints ) $Result = @{} $Result.Add("Transfer_Method", "file-based") $Result.Add("Is_Block_Based_Supported_By_Source", $false) $Result.Add("Block_Based_Unsupported_Mounts", @()) if ($Source.os_type -eq "windows") { $Result["Transfer_Method"] = "block-based" return $Result } if($Source.attributes.discovered_features.features_list -notcontains "linux_block_based") { return $Result } $Result["Is_Block_Based_Supported_By_Source"] = $true $fs = @("ext2", "ext3", "ext4", "xfs") $IsBlockBasedSupportedByAllSelectedMounts = $true foreach($Mount in $Source.attributes.storage.mounts.psobject.properties.value){ if ($SelectedMountPoints -inotcontains $Mount.path) { continue } if ($Mount.nature -eq "disk") { if ($fs -notcontains $Mount.fs_type) { $Result["Block_Based_Unsupported_Mounts"] += $Mount.path $IsBlockBasedSupportedByAllSelectedMounts = $false; } } } if ($IsBlockBasedSupportedByAllSelectedMounts) { $Result["Transfer_Method"] = "block-based" } return $Result } function Get-RMTransferMethod { param( [System.Object] $Source, [System.Object[]] $SelectedMountPoints, [bool] $IsInteractive, [string] $TransferMethod ) $MountPoints = @() foreach ($SelectedMount in $SelectedMountPoints) { if ($SelectedMount -is [hashtable]) { $MountPoints += $SelectedMount.values } else { $MountPoints += $SelectedMount } } $Result = Get-RMTransferMethodInternal -Source $Source -SelectedMountPoints $MountPoints if ($IsInteractive) { if ("block-based" -ieq $Result["Transfer_Method"]) { $ReadValue = Read-RMString -UserMessage "Enter transfer method" -Options "file-based", "block-based" ` -DefaultValue "block-based" -ParameterName "Transfer method" -IsRequired $false return $ReadValue, "" } else { if ($Result["Is_Block_Based_Supported_By_Source"] -and $Result["Block_Based_Unsupported_Mounts"].Count -gt 0) { $BlockBasedUnsupportedMountsAsString = $Result["Block_Based_Unsupported_Mounts"] -join ", " Write-Output "Block-based transfer method is not supported by the mount points '$BlockBasedUnsupportedMountsAsString', file-based transfer method will be used." | Out-Host } else { Write-Output "Block-based transfer method is not supported for the given source, file-based transfer method will be used." | Out-Host } } return $Result["Transfer_Method"], "" } if ([string]::IsNullOrEmpty($TransferMethod)) { return $Result["Transfer_Method"], "" } if ($TransferMethod -eq "file-based") { return $TransferMethod, "" } $ErrorString = "" if ($TransferMethod -eq "block-based" -and $Result["Transfer_Method"] -eq "file-based") { if ($Result["Is_Block_Based_Supported_By_Source"] -and $Result["Block_Based_Unsupported_Mounts"].Count -gt 0) { $BlockBasedUnsupportedMountsAsString = $Result["Block_Based_Unsupported_Mounts"] -join ", " $ErrorString = "Block-based transfer method is not supported by the mount points '$BlockBasedUnsupportedMountsAsString'" } else { $ErrorString = "Block-based transfer method is not supported for the given source." } } return $Result["Transfer_Method"], $ErrorString } function Confirm-RMIPAddress { param ( [string] $IPAddress ) $IPPattern = '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' if ($IPAddress -notmatch $IPPattern) { return $false } return $true } function Edit-RMMountPoints { param( [System.Object] $TargetProperties, [System.Object] $MountPoints ) $SelectedMounts = $TargetProperties | where { $null -ne $_.selected_mounts} $SelectedMounts.selected_mounts = $MountPoints return $SelectedMounts } function Get-RMDestinationNICConfigWithGatewayAndDNS { param( [RMVSphereDestinationNetworkConfiguration[]] $DestinationNICConfig ) foreach ($NICConfig in $DestinationNICConfig) { if ($NICConfig.IPType -ieq "dhcp") { continue } if (!([string]::IsNullOrWhiteSpace($NICConfig.DefaultGateway) ` -and [string]::IsNullOrWhiteSpace($NICConfig.PrimaryDNS))) { return $NICConfig } } # If all are DHCP, then return the first NIC return $DestinationNICConfig[0] } function Get-RMInputObjectBySideIndicator { param( [System.Object[]] $CompareResult, [string] $SideIndicator ) $InputObjects = @() foreach ($Result in $CompareResult) { if ($Result.SideIndicator -eq $SideIndicator) { $InputObjects += $Result.InputObject } } return $InputObjects } function Get-RMVMBasedSourceDiskLabel { param( [System.Object] $Source ) $DiskLabels = @() foreach ($Disk in $Source.attributes.storage.vm_disks) { $DiskLabels += $Disk.label } return $DiskLabels } |