lib/Authentication.ps1


## Define a ZertoSessions Variable to store connection details in
New-Variable -Scope global -Name 'ZertoSessions' -Value @{ } -Force


function New-ZertoSession {
    <#
    .SYNOPSIS
    Creates a connection to a Zerto VM instance

    .DESCRIPTION
    This function creates a connection to the specified Zerto instance using
    the provided credentials. This session can be used when calling other functions within
    the Zerto module

    .PARAMETER SessionName
    The name that will be used when referring to the created ZertoSession

    .PARAMETER Server
    The URI of the Zerto instance to connect to

    .PARAMETER Credential
    The credentials to be used twhen connecting to Zerto

    .PARAMETER AllowInsecureSSL
    Boolean indicating whether or not an insecure SSL connection is allowed

    .PARAMETER ProfileName
    The name of the stored ZertoProfile which contains the connection settings

    .EXAMPLE
    $Session = @{
        SessionName = 'TMDDEV'
        Server = 'tmddev.Zerto.net'
        Credential = (Get-StoredCredential -Name 'ME')
    }
    New-ZertoSession @Session

    .EXAMPLE
    Get-ZertoProfile -Name 'Zerto.example.com' | New-ZertoSession

    .EXAMPLE
    New-ZertoSession -ProfileName 'Zerto.example.com'

    .OUTPUTS
    None
    #>


    [CmdletBinding()]
    [Alias('Connect-ZertoServer')]
    param(
        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true)]
        [Alias('Name')]
        [String]$SessionName = 'Default',

        [Parameter(Mandatory = $true,
            ParameterSetName = 'ByProperty',
            ValueFromPipelineByPropertyName = $true)]
        [String]$Server,

        [Parameter(Mandatory = $true,
            ParameterSetName = 'ByProperty',
            ValueFromPipelineByPropertyName = $true)]
        [Int]$Port = 9669,

        [Parameter(Mandatory = $true,
            ParameterSetName = 'ByProperty',
            ValueFromPipelineByPropertyName = $true)]
        [PSCredential]$Credential,

        [Parameter(Mandatory = $false,
            ParameterSetName = 'ByProperty',
            ValueFromPipelineByPropertyName = $true)]
        [Bool]$AllowInsecureSSL = $false,

        [Parameter(Mandatory = $false)]
        [Switch]$Passthru,

        # [Parameter(Mandatory = $true,
        # ParameterSetName = 'ByProfileObject')]
        # [ZertoProfile]$ZertoProfile,

        [Parameter(Mandatory = $true,
            Position = 0,
            ParameterSetName = 'ByProfile')]
        [ArgumentCompleter( { Get-ZertoProfile -List })]
        [Alias('Profile')]
        [String]$ProfileName
    )

    begin {
        ## Create the TMServers Array that will be reachable at $global:ZertoSessions
        if (-not $global:ZertoSessions) {
            New-Variable -Name ZertoSessions -Scope Global -Value @{}
        }
    }

    process {

        if ($ProfileName) {
            $ZertoProfile = Get-ZertoProfile -Name $ProfileName
            if (!$ZertoProfile) {
                Write-Error "Could not load a Zerto profile named '$ProfileName'"
                return
            }
        }

        if ($ZertoProfile) {
            $SessionName = (($global:ZertoSessions.Keys -contains 'Default') -and ($SessionName -eq 'Default')) ? $ZertoProfile.Name : 'Default'
            $Server = $ZertoProfile.Server
            $Credential = $ZertoProfile.Credential
            $AllowInsecureSSL = $ZertoProfile.AllowInsecureSSL
        }
        else {
            if ($SessionName -eq 'Default') {
                $SessionName = (($global:ZertoSessions.Keys -contains 'Default') -and ($SessionName -eq 'Default')) ? $Server : 'Default'
            }
        }

        ## Check for Existing Session to this server
        if ($global:ZertoSessions.Keys -contains $SessionName) {
            $NewZertoSession = $global:ZertoSessions[$SessionName]
        }
        else {

            ## Create a session object for this new connection
            $NewZertoSession = [ZertoSession]::new($SessionName, $Server, $AllowInsecureSSL)
        }

        ## Honor SSL Settings from the user
        $CertSettings = @{ SkipCertificateCheck = $AllowInsecureSSL }

        ## Trim the server name
        $Instance = $Server.Replace('https://', '').Replace('http://', '')

        ## Save the Instance and Port used
        $NewZertoSession.ZertoServer = $Instance
        $NewZertoSession.ZertoPort = $Port

        ## Prepare Request Headers for use in the Session Header Cache
        $ContentType = 'application/json;charset=UTF-8'

        # Format the uri
        $uri = "https://$($Instance):$($Port)/v1/session/add"

        # Authenticating with Zerto APIs - Basic AUTH over SSL
        if ($Credential.GetNetworkCredential().domain) {
            $authInfo = ("{0}\{1}:{2}" -f $Credential.GetNetworkCredential().domain , $Credential.GetNetworkCredential().UserName, $Credential.GetNetworkCredential().Password )
        }
        else {
            $authInfo = ("{0}:{1}" -f $Credential.GetNetworkCredential().UserName, $Credential.GetNetworkCredential().Password )
        }
        $authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo)
        $authInfo = [System.Convert]::ToBase64String($authInfo)
        $RequestHeaders = @{
            "Authorization"  = ("Basic {0}" -f $authInfo)
            "Accept-Version" = "1.0";
            "Content-Type"   = $ContentType;
            "Accept"         = "application/json";
            "Cache-Control"  = "no-cache";
        }

        $WebRequestSplat = @{
            Method                          = 'POST'
            Uri                             = $uri
            Headers                         = $RequestHeaders
            SessionVariable                 = 'ZertoWebSession'
            PreserveAuthorizationOnRedirect = $true
            ContentType                     = $ContentType
        }

        ## Attempt Login
        if ($VerbosePreference -eq 'Continue') {
            Write-Host "Logging into Zerto instance [ " -NoNewline
            Write-Host $Instance -ForegroundColor Cyan -NoNewline
            Write-Host " ]"
        }

        # Make the request
        try {
            Write-Verbose "Web Request Parameters:"
            Write-Verbose ($WebRequestSplat | ConvertTo-Json -Depth 10)
            Write-Verbose "Invoking web request"
            $Response = Invoke-WebRequest @WebRequestSplat @CertSettings
            Write-Verbose "Response status code: $($Response.StatusCode)"
            Write-Verbose "Response Content: $($Response.Content)"
        }
        catch {
            throw $_
        }

        ## Check the Response code for 200
        if ($Response.StatusCode -eq 200) {
            $ZertoSessionToken = $Response.headers.get_item("x-zerto-session") | Select-Object -First 1
            $ZertoWebSession.Headers["x-zerto-session"] = $ZertoSessionToken
            $ZertoWebSession.Headers.Remove('Authorization')
        }
        else {
            Write-Error "Login Failure! Unable to Log into $Server. Check the URL and Credentials and try again"
            return
        }

        $NewZertoSession.ZertoWebSession = $ZertoWebSession

        ## Add this Session to the ZertoSessions list
        $global:ZertoSessions[$SessionName] = $NewZertoSession

        ## Return the session if requested
        if ($Passthru) {
            $NewZertoSession
        }
    }
}


# #.ExternalHelp ZertoModule.psm1-help.xml
# Function Get-ZertoAuthToken {
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server or ENV:\ZertoServer')] [string] $ZertoServer = ( Get-EnvZertoServer ) ,
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server URL Port')] [string] $ZertoPort = ( Get-EnvZertoPort ),
# [Parameter( HelpMessage = 'User to connect to Zerto')] [string] $ZertoUser,
# [Parameter( HelpMessage = 'Credential to connect to Zerto')] [PSCredential] $Credential
# )

# Set-SSLCertByPass

# if ([String]::IsNullOrEmpty($ZertoServer) ) {
# throw "Missing Zerto Server"
# }

# $baseURL = "https://" + $ZertoSessionConfig.ZertoServer + ":" + $ZertoSessionConfig.ZertoPort + "/v1/"
# $FullURL = $baseURL + "session/add"
# $TypeJSON = "application/json"
# Write-Verbose $FullURL

# if (-Not $Credential) {

# if ([String]::IsNullOrEmpty($ZertoUser)) {
# $Credential = Get-Credential -Message "Enter your Zerto credentials for '$ZertoServer'"
# }
# else {
# $Credential = Get-Credential -Message "Enter your Zerto credentials for '$ZertoServer'" -UserName $ZertoUser
# }
# }

# If ($null -NE $Credential) {
# #Remove our Zerto Version
# Remove-Item ENV:ZertoToken -Force -ErrorAction Ignore
# Remove-Item ENV:ZertoVersion -Force -ErrorAction Ignore

# # Authenticating with Zerto APIs - Basic AUTH over SSL
# if ($Credential.GetNetworkCredential().domain) {
# $authInfo = ("{0}\{1}:{2}" -f $Credential.GetNetworkCredential().domain , $Credential.GetNetworkCredential().UserName, $Credential.GetNetworkCredential().Password )
# }
# else {
# $authInfo = ("{0}:{1}" -f $Credential.GetNetworkCredential().UserName, $Credential.GetNetworkCredential().Password )
# }
# $authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo)
# $authInfo = [System.Convert]::ToBase64String($authInfo)
# $headers = @{Authorization = ("Basic {0}" -f $authInfo) }
# # $sessionBody = '{"authenticationMethod": 1}'
# # $sessionBody = @{
# # AuthenticationMethod = 0
# # login = $Credential.Username
# # password = $Credential.GetNetworkCredential().Password
# # } | ConvertTo-Json -Compress

# #Need to check our Response.
# try {
# $RequestSplat = @{
# Uri = $FullURL
# Headers = $headers
# Method = 'POST'
# # Body = $sessionBody
# ContentType = $TypeJSON
# }

# ## TODO: Add handling for this
# $AllowInsecureSSL = $true
# if ($AllowInsecureSSL) {
# $RequestSplat.SkipCertificateCheck = $True
# }
# $xZertoSessionResponse = Invoke-WebRequest @RequestSplat
# }
# catch {
# $xZertoSessionResponse = $_.Exception.Response
# }

# if ($null -eq $xZertoSessionResponse ) {
# Throw "Zerto Server ${ZertoServer}:${ZertoPort} not responding."
# }
# elseif ($xZertoSessionResponse.StatusCode -eq "200") {
# $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")
# $ZertoSessionHeader = @{"x-zerto-session" = $xZertoSession }
# return $ZertoSessionHeader
# }
# else {
# if ($xZertoSessionResponse.StatusCode.value__ -eq "401") {
# Throw "User $ZertoUser not authorized or invalid password."
# }
# return $null
# }
# }
# else {
# return $null
# }
# }

# #.ExternalHelp ZertoModule.psm1-help.xml
# Function Set-ZertoAuthToken {
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server or ENV:\ZertoServer')] [string] $ZertoServer = ( Get-EnvZertoServer ) ,
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server URL Port')] [string] $ZertoPort = ( Get-EnvZertoPort ),
# [Parameter( HelpMessage = 'User to connect to Zerto')] [string] $ZertoUser
# )

# Set-Item ENV:ZertoToken ( (Get-ZertoAuthToken -ZertoServer $ZertoServer -ZertoPort $ZertoPort -ZertoUser $ZertoUser) | ConvertTo-Json -Compress)
# #Set our Zerto Version
# Set-Item ENV:ZertoVersion (Get-ZertoLocalSite).version
# }

# # .ExternalHelp ZertoModule.psm1-help.xml
# Function Remove-ZertoAuthToken {
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server or ENV:\ZertoServer')] [string] $ZertoServer = ( Get-EnvZertoServer ) ,
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server URL Port')] [string] $ZertoPort = ( Get-EnvZertoPort ),
# [Parameter(Mandatory = $false, ValueFromPipeline = $true, HelpMessage = 'Zerto authentication token from Get-ZertoAuthToken or ENV:\ZertoToken')] [Hashtable] $ZertoToken = ( Get-EnvZertoToken )
# )

# $baseURL = "https://" + $ZertoSessionConfig.ZertoServer + ":" + $ZertoSessionConfig.ZertoPort + "/v1/"
# $TypeJSON = "application/json"

# if ( $ZertoToken -eq $null) {
# throw "Missing Zerto Authentication Token"
# }

# $FullURL = $baseURL + "Session"
# Write-Verbose $FullURL

# try {
        # $RestMethodSplat = @{
        # Uri = $FullURL
        # TimeoutSec = 100
        # ContentType = $TypeJSON
        # Method = 'GET'
        # WebSession = $ZertoSessionConfig.ZertoWebSession
        # }
        # $Result = Invoke-RestMethod @RestMethodSplat @ZertoCertSettings -Method Delete
# }
# catch {
# throw $_.Exception.Message
# }
# #Remove Zerto Vars
# Remove-Item ENV:ZertoVersion -Force -ErrorAction Ignore
# Remove-Item ENV:ZertoToken -Force -ErrorAction Ignore
# return $Result
# }

# # .ExternalHelp ZertoModule.psm1-help.xml
# Function Connect-ZertoZVM {
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $true, HelpMessage = 'Zerto Server or ENV:\ZertoServer')] [string] $ZertoServer ,
# [Parameter(Mandatory = $false, HelpMessage = 'Zerto Server URL Port')] [string] $ZertoPort = 9669 ,
# [Parameter(Mandatory = $false, HelpMessage = 'User to connect to Zerto')] [string] $ZertoUser,
# [Parameter(Mandatory = $false, HelpMessage = 'Credential to use to connect to Zerto')] [PSCredential] $Credential
# )

# Set-Item ENV:ZertoServer $ZertoServer
# Set-Item ENV:ZertoPort $ZertoPort
# if ($Credential) {
# Set-Item ENV:ZertoToken ((Get-ZertoAuthToken -ZertoServer $ZertoServer -ZertoPort $ZertoPort -Credential $Credential) | ConvertTo-Json -Compress)
# }
# elseif ($ZertoUser) {
# Set-Item ENV:ZertoToken ((Get-ZertoAuthToken -ZertoServer $ZertoServer -ZertoPort $ZertoPort -ZertoUser $ZertoUser) | ConvertTo-Json -Compress)
# }
# else {
# Set-Item ENV:ZertoToken ((Get-ZertoAuthToken -ZertoServer $ZertoServer -ZertoPort $ZertoPort) | ConvertTo-Json -Compress)
# }
# Set-Item ENV:ZertoVersion (Get-ZertoLocalSite).version
# }

# # .ExternalHelp ZertoModule.psm1-help.xml
# Function Disconnect-ZertoZVM {
# Remove-ZertoAuthToken
# Remove-Item ENV:ZertoVersion -Force -ErrorAction Ignore
# Remove-Item ENV:ZertoServer -Force -ErrorAction Ignore
# Remove-Item ENV:ZertoPort -Force -ErrorAction Ignore
# Remove-Item ENV:ZertoToken -Force -ErrorAction Ignore
# }

# #endregion