RiverMeadow.Source/RiverMeadow.Source.psm1
Import-Module -Name $PSScriptRoot\..\Util\Util Import-Module -Name $PSScriptRoot\..\Common\Common function Add-RMSource { param( [Alias("sip")] [string] $SourceIP, [Alias("shpa")] [bool] $SourceHasPreinstalledAgent, [Alias("scoa")] [bool] $StoreCredsOnAppliance, [Alias("un")] [string] $Username, [Alias("pw")] [string] $Password, [Alias("cpw")] [string] $ConfirmPassword, [Alias('usshpk')] [bool] $UseSSHPrivateKey, [Alias("pk")] [string] $PrivateKey, [Alias("pp")] [string] $Passphrase, [Alias("cpp")] [string] $ConfirmPassphrase, [Alias("dm")] [string] $Domain, [Alias("rmt")] [string[]] $RiverMeadowTags, [Alias("ai")] [string[]] $AdvancedInstructions, [Alias("cmg")] [bool] $CreateMoveGroup, [Alias("mgn")] [string] $MoveGroupName, [Alias("tmd")] [string] $TargetMigrationDate, [Alias("are")] [string] $AssignedResourceEmail ) $UserLoginStatus = Test-UserLoggedIn if (!$UserLoginStatus) { return } if (0 -eq $PSBoundParameters.Count) { Add-RMSourceInteractive } else { Add-RMSourceNonInteractive @PSBoundParameters } } function Add-RMSourceInteractive { $CurrentProjectId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly $ReadValue = Read-Host "Enter the source IP address" if ("" -eq $ReadValue) { throw "Source IP address is required" } $SourceIP = $ReadValue $SourceHasPreinstalledAgent = $false $ReadValue = Read-Host "Does source has preinstalled agent (true/false)[false]" if ("" -ne $ReadValue) { $SourceHasPreinstalledAgent = [System.Convert]::ToBoolean($ReadValue) } if(!$SourceHasPreinstalledAgent){ $StoreCredsOnAppliance = $false $ReadValue = Read-Host "Store the source credentials on migration appliance (true/false)[false]" if ("" -ne $ReadValue) { $StoreCredsOnAppliance = [System.Convert]::ToBoolean($ReadValue) } } if (!$SourceHasPreinstalledAgent -and !$StoreCredsOnAppliance) { $ReadValue = Read-Host "Enter the username" if ("" -eq $ReadValue) { throw "Username is required." } $Username = $ReadValue $UseSSHPrivateKey = $false $ReadValue = Read-Host "Use SSH private key (true/false)[false]" if ("" -ne $ReadValue) { $UseSSHPrivateKey = [System.Convert]::ToBoolean($ReadValue) } if ($UseSSHPrivateKey) { $ReadValue = Read-Host "Enter the private key" if ("" -eq $ReadValue) { throw "Private key is required." } $PrivateKey = $ReadValue $Password = Compare-RMSecureString -Message "Enter the passphrase" -ConfirmMessage "Confirm the passphrase" ` -ConfirmErrorMessage "Confirm passphrase is reqiured." -CompareErrorMessage "Passphrase and confirm passphrase must match." -SSHPrivateKey $true } else { $Password = Compare-RMSecureString -Message "Enter the password" -ConfirmMessage "Confirm the password" ` -ErrorMessage "Password is required." -ConfirmErrorMessage "Confirm password is reqiured." -CompareErrorMessage "Password and confirm password must match." } $ReadValue = Read-Host "Enter the domain" if ("" -ne $ReadValue) { $Domain = $ReadValue } } $ReadValue = Read-Host "Enter one or more RiverMeadow tags, separated by commas [None]" if ("" -ne $ReadValue) { $RiverMeadowTags = $ReadValue.Split(",").Trim() } else { $RiverMeadowTags = @() } $ReadValue = Read-Host "Enter one or more advanced instructions in the format 'key=value' and separated by commas [None]" $AdvancedInstructions = Get-RMStringAsHashtable -InputString $ReadValue $CreateMoveGroup = $false $ReadValue = Read-Host "Create new move group (true/false)[false]" if ("" -ne $ReadValue) { $CreateMoveGroup = [System.Convert]::ToBoolean($ReadValue) if ($CreateMoveGroup) { $ReadValue = Read-Host "Enter new move group name" if ("" -eq $ReadValue) { throw "New move group name is required." } $MoveGroupName = $ReadValue $ReadValue = Read-Host "Enter target migration date in the format 'mm/dd/yyyy' [None]" if("" -ne $ReadValue) { try { [datetime]::ParseExact($ReadValue, "MM/dd/yyyy", $null) $TargetMigrationDate = $ReadValue } catch { throw "Please enter a valid target migration date in the format 'mm/dd/yyyy'." } } $AssignedResourceEmail = Read-Host "Enter assigned resource email [None]" } } if (!$CreateMoveGroup) { $MoveGroupList = @() $Response = Get-RMMoveGroupList -Organization $CurrentProjectId -PageNumber 0 $MoveGroupList += $Response for ($index = 1; $index -lt $Response.page.totalPages; $index++) { $MoveGroupList += Get-RMMoveGroupList -OrganizationId $CurrentProjectId -PageNumber $index } $MoveGroups = $MoveGroupList.content.name -join ", " $ReadValue = Read-Host "Enter the move group name to which the source should be added ($MoveGroups)" if ("" -ne $ReadValue) { $MoveGroupName = $ReadValue } } $UserInput = @{ SourceIP = $SourceIP CurrentProjectId = $CurrentProjectId SourceHasPreinstalledAgent = $SourceHasPreinstalledAgent StoreCredsOnAppliance = $StoreCredsOnAppliance Username = $Username Password = $Password PrivateKey = $PrivateKey Domain = $Domain RiverMeadowTags = $RiverMeadowTags AdvancedInstructions = $AdvancedInstructions CreateMoveGroup = $CreateMoveGroup MoveGroupName = $MoveGroupName TargetMigrationDate = $TargetMigrationDate AssignedResourceEmail = $AssignedResourceEmail } New-RMSource @UserInput } function Compare-RMSecureString { param ( [string] $Message, [string] $ConfirmMessage, [string] $ErrorMessage, [string] $ConfirmErrorMessage, [string] $CompareErrorMessage, [bool] $SSHPrivateKey ) $SecurePassword = Read-Host "$Message" -AsSecureString $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) if (!$SSHPrivateKey -and "" -eq $Password) { throw "$ErrorMessage" } $ConfirmSecurePassword = Read-Host "$ConfirmMessage" -AsSecureString $ConfirmBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ConfirmSecurePassword) $ConfirmPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($ConfirmBSTR) if ($SSHPrivateKey ) { if ("" -ne $Password) { if ("" -eq $ConfirmPassword) { throw $ConfirmErrorMessage } if ($Password -ne $ConfirmPassword) { throw "$CompareErrorMessage" } } } else { if ("" -eq $ConfirmPassword ) { throw "$ConfirmErrorMessage" } if ($Password -ne $ConfirmPassword) { throw "$CompareErrorMessage" } } return $Password } function Add-RMSourceNonInteractive { param ( [string] $SourceIP, [bool] $SourceHasPreinstalledAgent, [bool] $StoreCredsOnAppliance, [string] $Username, [string] $Password, [string] $ConfirmPassword, [bool] $UseSSHPrivateKey, [string] $PrivateKey, [string] $Passphrase, [string] $ConfirmPassphrase, [string] $Domain, [string[]] $RiverMeadowTags, [string[]] $AdvancedInstructions, [bool] $CreateMoveGroup, [string] $MoveGroupName, [string] $TargetMigrationDate, [string] $AssignedResourceEmail ) $Errors = Confirm-RMAddSourceParameter -UserParameter $PSBoundParameters $IsValidDate = Confirm-RMDateFormat -InputDate $TargetMigrationDate -DateFormat "MM/dd/yyyy" if ($Errors.Count -gt 0) { if (!$IsValidDate) { Write-RMError -Message "TargetMigrationDate is invalid, the TargetMigrationDate should be in the format 'mm/dd/yyyy'." } Out-RMUserParameterResult -ErrorMessage $Errors return } if (!$IsValidDate) { Write-RMError -Message "TargetMigrationDate is invalid, the TargetMigrationDate should be in the format 'mm/dd/yyyy'." return } $UserInput = @{} $CurrentProjectId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly $UserInput.Add("CurrentProjectId", $CurrentProjectId) $UserInput.Add("SourceIP", $SourceIP) if ($SourceHasPreinstalledAgent) { $UserInput.Add("SourceHasPreinstalledAgent", $SourceHasPreinstalledAgent) } else { if ($StoreCredsOnAppliance) { $UserInput.Add("StoreCredsOnAppliance", $StoreCredsOnAppliance) } } if (!$SourceHasPreinstalledAgent -and !$StoreCredsOnAppliance) { $UserInput.Add("Username", $Username) if ($UseSSHPrivateKey) { $UserInput.Add("PrivateKey", $PrivateKey) $UserInput.Add("Password", $Passphrase) } else { $UserInput.Add("Password", $Password) } $UserInput.Add("Domain", $Domain) } if ($null -eq $RiverMeadowTags) { $RiverMeadowTags = @() } $UserInput.Add("RiverMeadowTags", $RiverMeadowTags) $AdvancedInstructionsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $AdvancedInstructions $UserInput.Add("AdvancedInstructions", $AdvancedInstructionsAsHashTable) if ($CreateMoveGroup) { $UserInput.Add("CreateMoveGroup", $CreateMoveGroup) $UserInput.Add("MoveGroupName", $MoveGroupName) $UserInput.Add("TargetMigrationDate", $TargetMigrationDate) $UserInput.Add("AssignedResourceEmail", $AssignedResourceEmail) } else { $UserInput.Add("MoveGroupName", $MoveGroupName) } New-RMSource @UserInput } function New-RMSource { param( [string] $SourceIP, [string] $CurrentProjectId, [bool] $SourceHasPreinstalledAgent, [bool] $StoreCredsOnAppliance, [string] $Username, [string] $Password, [string] $PrivateKey, [string] $Domain, [string[]] $RiverMeadowTags, [hashtable] $AdvancedInstructions, [bool] $CreateMoveGroup, [string] $MoveGroupName, [string] $TargetMigrationDate, [string] $AssignedResourceEmail ) $CredsStorage = "local" if ($StoreCredsOnAppliance) { $CredsStorage = "ca" } $MoveGroupID = $null if ($CreateMoveGroup) { $MoveGroupID = "00000000-0000-0000-0000-000000000000" } else { if ("" -ne $MoveGroupName) { $MoveGroup = Get-MoveGroupByName -MoveGroupName $MoveGroupName -OrganizationId $CurrentProjectId if ($null -eq $MoveGroup) { throw "Invalid move group." } $MoveGroupID = $MoveGroup.id } } $ControlConnectionType = $null if ($SourceHasPreinstalledAgent) { $ControlConnectionType = "agent" } $SourceRequest = @{ "name"= $SourceIP "host"= $SourceIP #e.g string format:"Azure:Standard_D5_v2" #TODO We will add cloud size features in the future "cloud_sizing"= "" "instructions"= $AdvancedInstructions "credentials"= @{ "storage" = $CredsStorage "username" = $Username "password" = $Password "domain" = $Domain "private_key" = $PrivateKey } "move_group_id" = $MoveGroupID "move_group_name" = $MoveGroupName "target_migration_date" = $TargetMigrationDate "assigned_resource_email" = $AssignedResourceEmail "tags"= $RiverMeadowTags "organization_id" = $CurrentProjectId "control_connection_type" = $ControlConnectionType } $SourceRequestJson = $SourceRequest |ConvertTo-Json -Depth 100 $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.token } $Params = @{ Method = "Post" Uri = $Uri + "/sources" Body = $SourceRequestJson ContentType = "application/json" Headers = $Headers } try { Invoke-RMRestMethod -Params $Params | Out-Null } catch { # Invoke-RMRestMethod has already shown the error, so just return return } Write-Output "Source has been added successfully" } function Confirm-RMAddSourceParameter { param( [hashtable] $UserParameter ) $Errors = @() if (!$UserParameter.ContainsKey("SourceIP") -or [string]::IsNullOrEmpty("SourceIP")) { $Errors += "SourceIP is required" } if (!(($UserParameter.ContainsKey("SourceHasPreinstalledAgent") -and $UserParameter["SourceHasPreinstalledAgent"]) ` -or ($UserParameter.ContainsKey("StoreCredsOnAppliance") -and $UserParameter["StoreCredsOnAppliance"]))) { if (!$UserParameter.ContainsKey("Username") -or [string]::IsNullOrEmpty($UserParameter["Username"])) { $Errors += "Username is required" } if ($UserParameter.ContainsKey("UseSSHPrivateKey") -and $UserParameter["UseSSHPrivateKey"] -eq $true) { if (!$UserParameter.ContainsKey("PrivateKey") -or [string]::IsNullOrEmpty($UserParameter["PrivateKey"])) { $Errors += "PrivateKey is required, when 'UseSSHPrivateKey' is true" } if ($UserParameter["Passphrase"] -ne $UserParameter["ConfirmPassphrase"]) { $Errors += "Passphrase and ConfirmPassphrase must match" } } else { if(!$UserParameter.ContainsKey("Password") -or [string]::IsNullOrEmpty($UserParameter["Password"])) { $Errors += "Password is required" } if (!$UserParameter.ContainsKey("ConfirmPassword") -or [string]::IsNullOrEmpty($UserParameter["ConfirmPassword"])) { $Errors += "ConfirmPassword is required" } if ($UserParameter["Password"] -ne $UserParameter["ConfirmPassword"]) { $Errors += "Password and ConfirmPassword must match" } } } if ($UserParameter.ContainsKey("CreateMoveGroup") -and $UserParameter["CreateMoveGroup"] -eq $true) { if (!$UserParameter.ContainsKey("MoveGroupName") -or [string]::IsNullOrEmpty($UserParameter["MoveGroupName"])) { $Errors += "MoveGroupName is required, when 'CreateMoveGroup' is true" } } return $Errors } Export-ModuleMember -Function Add-RMSource |