Util/Util.psm1
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() if (-not (Get-Variable -Name "RMContext-UserLogin" -ErrorAction SilentlyContinue)) { Write-RMError -Message "Please login using the cmdlet 'Invoke-RMLogin' and try again." return $false } return $true } function Invoke-RMRestMethod { param( [hashtable] $Params ) try { return Invoke-RestMethod @Params } catch [System.Exception] { Show-RMError -ErrorObj $PSItem throw } } 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 (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 ) if ("GP2" -ieq $VolumeType) { return "ssd2" } if ("GP3" -ieq $VolumeType) { return "ssd3" } if ("magnetic" -ieq $VolumeType) { return "magnetic" } if ("IO1" -ieq $VolumeType) { return "iops_ssd" } if ("IO2" -ieq $VolumeType) { return "iops2_ssd" } throw "Unsupported volume type '$VolumeType'" } function Get-RMExcludedMountPoint { param( [System.Object] $Source, [System.Object[]] $MountPoints ) 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 $Source.os_type) { if ($MountsToExclude -contains "c") { Write-RMError -Message "Cannot exclude 'C' drive, 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.Values -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() $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-RMWindowsOSMMapping { param() # ME OSM name to user label return @{ "Windows 10 Pro" = "Windows 10 Professional" "Windows 10 Enterprise" = "Windows 10 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" "CENTOS7" = "CentOS 7.9" "UBUNTU1604LTS" = "Ubuntu 16.04 LTS" "SLES15SP1" = "SUSE Linux Enterprise Server 15 SP1" } } function Get-RMOSMMappingBySource { param( [System.Object] $Source ) $ResultOSMMapping = @{} $OSMMapping = @{} 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. $ResultOSMMapping.Add($OSMMapping[$UpgradeOption], $UpgradeOption) } return $ResultOSMMapping } function Add-RMResizeMount { param( [string[]] $SelectedMounts, [hashtable] $ResizeMounts, [object] $Source ) $ResizeMountList = @() $ResizeMounts.keys | ForEach-Object { $ResizeMountList += $_ } $Result = Compare-Object -ReferenceObject $SelectedMounts -DifferenceObject $ResizeMountList -IncludeEqual if ($Result.SideIndicator -contains "=>") { Write-RMError -Message "Resize mount points contains a mount point that has not been selected for migration, please check and try again" return $null } $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]+$")) { Write-RMError -Message "Mount point '$MountPath' contains non-integer value $ResizeValue, please enter an integer value only" $IsValidData = $false continue } $ResizeValue = $ResizeValue -as [int] if (-not($ResizeValue -gt $UsedSpace -and $ResizeValue -lt $TotalSpace)) { Write-RMError -Message "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 } return $MountsResize } 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-RMMigrationInstruction { param ( [hashtable] $MigrationInstructions ) $MigrationInstructionList = @() if ($null -ne $MigrationInstructions) { $MigrationInstructionList = $MigrationInstructions.Keys | foreach-object { "$_/$($MigrationInstructions[$_])"} } return $MigrationInstructionList } 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 ) $MountPointList = @() $ResizeMounts = Get-RMStringArrayAsHashtable -InputItems $ResizeMountPoints -ParameterName "ResizeMountPoints" foreach($SelectedMountPoint in $SelectedMountPoints) { $MountPointList += $SelectedMountPoint.values } return Add-RMResizeMount -SelectedMounts $MountPointList -ResizeMounts $ResizeMounts -Source $Source } 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]::round($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 Out-MigrationIdFromResponse { param( [System.Object] $Response ) $MigrationId = "" if ($Response.links[1].rel -ine "migration") { return $MigrationId } $SplitData = $Response.links[1].href.split("/") if ($SplitData.Count -lt 7) { return $MigrationId } if ($SplitData[6].Contains("{")) { $MigrationId = $SplitData[6].SubString(0, $SplitData[6].IndexOf("{")) } else { $MigrationId = $SplitData[6].SubString(0, $SplitData[6].Length) } Write-Output "Migration started successfully, migration ID: $MigrationId" | Out-Host } function Get-RMTransferMethod { param ( [System.Object] $Source ) $TransferType = "file-based" if ($Source.os_type -eq "windows") { $TransferType = "block-based" } else { if($Source.attributes.discovered_features.features_list -contains "linux_block_based") { $fs = @("ext2", "ext3", "ext4", "xfs") $check = $true foreach($Mount in $Source.attributes.storage.mounts.psobject.properties.value){ if ($Mount.nature -eq "disk") { if ($fs -notcontains $Mount.fs_type) { $check = $false; break } } } if ($check) { $TransferType = "block-based" } } } return $TransferType } function Confirm-RMDateFormat { param( [string] $InputDate, [string] $DateFormat ) if([string]::IsNullOrEmpty($InputDate)) { return $true } try { [datetime]::ParseExact($InputDate, $DateFormat, $null) |Out-Null } catch { return $false } return $true } 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 } |