RiverMeadow.Source/RiverMeadow.Source.psm1

Import-Module -Name $PSScriptRoot\..\Util\Util
function Add-RMSourceToCurrentProject {
    param(
        [Alias("sip")]
        [string] $SourceIP,

        [Alias("shpa")]
        [bool] $SourceHasPreinstalledAgent,

        [Alias("scoa")]
        [bool] $StoreCredsOnAppliance,

        [Alias("un")]
        [string] $Username,

        [Alias("p")]
        [string] $Password,

        [Alias("d")]
        [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,

        [Alias("css")]
        [string] $CloudSizeSetting
    )

    $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

        $SecurePassword = Read-Host "Enter the password" -AsSecureString
        $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
        $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
        if ("" -eq $Password) {
            throw "Password is required."
        }

        $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
        Domain = $Domain
        RiverMeadowTags = $RiverMeadowTags
        AdvancedInstructions = $AdvancedInstructions
        CreateMoveGroup = $CreateMoveGroup
        MoveGroupName = $MoveGroupName
        TargetMigrationDate = $TargetMigrationDate
        AssignedResourceEmail = $AssignedResourceEmail
    }

    New-RMSource @UserInput
}

function Add-RMSourceNonInteractive {
    param (
        [string] $SourceIP,
        [bool] $SourceHasPreinstalledAgent,
        [bool] $StoreCredsOnAppliance,
        [string] $Username,
        [string] $Password,
        [string] $Domain,
        [string[]] $RiverMeadowTags,
        [string[]] $AdvancedInstructions,
        [bool] $CreateMoveGroup,
        [string] $MoveGroupName,
        [string] $TargetMigrationDate,
        [string] $AssignedResourceEmail,
        [string] $CloudSizeSetting
    )

    $UserInput = @{}

    $CurrentProjectId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly
    $UserInput.Add("CurrentProjectId", $CurrentProjectId)

    if ("" -eq $SourceIP) {
        throw "Source IP address is required."
    }
    $UserInput.Add("SourceIP", $SourceIP)

    if ($SourceHasPreinstalledAgent) {
        $UserInput.Add("SourceHasPreinstalledAgent", $SourceHasPreinstalledAgent)
    } else {
        if ($StoreCredsOnAppliance) {
            $UserInput.Add("StoreCredsOnAppliance", $StoreCredsOnAppliance)
        }
    }

    if (!$SourceHasPreinstalledAgent -and !$StoreCredsOnAppliance) {
        if ("" -eq $Username) {
            throw "Username is required."
        }
        $UserInput.Add("Username", $Username)

        if ("" -eq $Password) {
            throw "Password is required."
        }
        $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)

        if ("" -eq $MoveGroupName) {
            throw  "New move group name is required."
        }
        $UserInput.Add("MoveGroupName", $MoveGroupName)


        if("" -ne $TargetMigrationDate) {
            try {
                [datetime]::ParseExact($TargetMigrationDate, "MM/dd/yyyy", $null) |Out-Null
            }
            catch {
                throw "Please enter a valid target migration date in the format 'mm/dd/yyyy'."
            }
        }
        $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] $Domain,
        [string[]] $RiverMeadowTags,
        [hashtable] $AdvancedInstructions,
        [bool] $CreateMoveGroup,
        [string] $MoveGroupName,
        [string] $TargetMigrationDate,
        [string] $AssignedResourceEmail,
        [string] $CloudSizeSetting
    )

    $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
        }
        "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
    }

    $Response = Invoke-RMRestMethod -Params $Params
    return  $Response.id
}

Export-ModuleMember -Function Add-RMSourceToCurrentProject