Functions/Get.ps1


function Get-LinaGlobalStats {
    <#
.SYNOPSIS
Retrieves the global stats and configuration of the current Lina server.
.DESCRIPTION
Retrieves the global stats and configuration of the current Lina server such as the server version deduplication ratio, volume stored etc
.INPUTS
None
.OUTPUTS
LinaStats Object
.EXAMPLE
Get-LinaGlobalStats
Retrieve global infos of current Lina Server
.EXAMPLE
$lina_version = (Get-LinaGlobalStats).ALNVersion
Get current installed version of Lina sofware.
#>

    Write-Verbose "Getting global stats"
    $request = CallAPI -Path "/info.xml"
    $stats = ([xml]$request).infolist

    if ($stats.aln_version -like "* DEV") {
        $LinaVersion = [version]($stats.aln_version -replace " DEV", "")
        $LinaVersionType = "Beta"
    }
    else {
        $LinaVersion = [version]$stats.aln_version
        $LinaVersionType = "Stable"
    }

    $LinaStats = [PSCustomObject]@{
        PSTypeName        = 'LinaStats'
        LinaVersion       = $LinaVersion
        LinaVersionType   = $LinaVersionType

        PercentDiskUse    = $stats.disk_use
        DedupRatio        = $stats.dedup_ratio
        CompressionRatio  = $stats.cpr_ratio
        DiskAvailableGB   = [math]::Round(($stats.disk_avail) / (1024 * 1024 * 1024), 2)

        DiskSavingGB      = [math]::Round(($stats.vol_protected - $stats.vol_stored) / (1024 * 1024 * 1024), 1)
        VolumeProtectedGB = [math]::Round(($stats.vol_protected) / (1024 * 1024 * 1024), 1)
        VolumeRestoredGB  = [math]::Round(($stats.vol_restored) / (1024 * 1024 * 1024), 1)
        VolumeStoredGB    = [math]::Round(($stats.vol_stored) / (1024 * 1024 * 1024), 1)

        VolumeProtectedMB = [math]::Round(($stats.vol_protected) / (1024 * 1024))
        VolumeRestoredMB  = [math]::Round(($stats.vol_restored) / (1024 * 1024))
        VolumeStoredMB    = [math]::Round(($stats.vol_stored) / (1024 * 1024))
    }
    Return $LinaStats
}

function Get-LinaAgent {
    <#
.SYNOPSIS
Retrieves the agents on a Lina server.
.DESCRIPTION
Retrieves the agents on a Lina server. Returns a set of agents that correspond to the filter criteria provided
.INPUTS
None
.OUTPUTS
Array of LinaAgent Objects
.PARAMETER Name
Name of the agent(s) to retrieve. Wilcards are allowed. For example : *DESKTOP*
.PARAMETER ID
ID of the agent to retrieve. For example : 134.
.EXAMPLE
Get-LinaAgent -Name "TEST"
Retrieves the agent named "TEST" and display its properties.
.EXAMPLE
$agents_desktop = Get-LinaAgent -Name "*DESKTOP*"
Retrieves all the agents with DESKTOP inside their names. The list returned can be passed to other functions.
.EXAMPLE
Get-LinaAgent | Where {$_.LastSyncTime -le ((Get-Date).AddDays(-14)) } | Select Name,Email,LastBackup,LastSyncTime | ft
Retrieves all the agents without backups since last 14 days.
.EXAMPLE
Get-LinaAgent -Name "TEST" | Remove-LinaAgent
Will get the agent named TEST then pass it to the next command for deletion.
#>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName", Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID
    )
    Write-Verbose "Getting list of agents"
    $timestamp = LinaTimestamp
    $Tenants = Get-LinaTenant
    $LinaItems = @()

    if ($global:INT_LINA_API_VERSION -le 50 ) {
        
        $agentstats = Get-LinaAgentStats

        # Using API 5.0 (XML and dissociated agent and AgentStats)
        $request = CallAPI -Path "/lst_clients.xml?timestamp=$timestamp&type=agent"
        $Items = ([xml]$request).HNConfig.ClientArray.Client

        foreach ($Item in $Items) {
            <# Filtering on ID or Name (only if provided) #>
            $Name_encoded = [System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding(28591).GetBytes($Item.Name))
            if ((!$Name -AND !$ID) -OR ( $Item.Name -like "$Name" -OR $Name_encoded -like "$Name" -OR $Item.ID -eq $ID)) {
                $current_agentstat = $agentstats | where-object { $_.ID -eq $Item.ID }

                $CurrentLinaItem = [PSCustomObject]@{
                    PSTypeName             = 'LinaAgent'
                    Name                   = $Name_encoded
                    ID                     = $Item.ID
                    Tenant                 = $Tenants | where-object { $_.ID -eq $Item.DomainID } | Select-Object -ExpandProperty Name
                    AgentGroup             = Translate($Item.AttachementArray.Attachement.Group.Name)
                    Strategy               = Translate($Item.ServiceProfile.Name)
                    Protection             = Translate($Item.DataProfile.Name)

                    ComputerName           = $current_agentstat.ComputerName
                    System                 = $current_agentstat.System
                    SystemCategory         = TranslateSystemCategories($current_agentstat.SystemCategory)
                    AgentVersion           = $current_agentstat.AgentVersion
                    LastLogon              = $current_agentstat.LastLogon
                    Email                  = $current_agentstat.Email
                    CdpType                = $current_agentstat.CdpType
                    Alert                  = $current_agentstat.Alert

                    # LastBackup = LastSync. LastCompleted session update even when there are some errors
                    LastBackup             = $current_agentstat.LastBackup

                    LastSessionStart       = $current_agentstat.LastSessionStart
                    LastSessionComplete    = $current_agentstat.LastSessionComplete
                    LastConnection         = $current_agentstat.LastConnection
                    LastSync               = $current_agentstat.LastSync

                    LastStartedSession     = $current_agentstat.LastStartedSession
                    LastCompletedSession   = $current_agentstat.LastCompletedSession
                    LastConnectionTime     = $current_agentstat.LastConnectionTime
                    LastSyncTime           = $current_agentstat.LastSyncTime

                    TenantID               = $Item.DomainID
                    AgentGroupID           = $Item.AttachementArray.Attachement.Group.ID
                    StrategyID             = $Item.ServiceProfile.ID
                    ProtectionID           = $Item.DataProfile.ID
                    
                    StrategyInternalName   = $Item.ServiceProfile.Name
                    ProtectionInternalName = $Item.DataProfile.Name

                }
                $LinaItems += $CurrentLinaItem
            }
        }
    }
    else {
        
        # Using API 5.1+ (JSON containing agent and agentStats)
        $request = CallAPI -Path "/stats_clients.json?timestamp=$timestamp"
        $Items = $request.ClientArray

        foreach ($Item in $Items) {
            #$Name_encoded = [System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding(28591).GetBytes($Item.AdminInfos.Name))
            $Name_encoded = FixEncoding($Item.AdminInfos.Name)
            <# Filtering on ID or Name (only if provided) #>
            if ((!$Name -AND !$ID) -OR ( $Item.AdminInfos.Name -like "$Name" -OR $Name_encoded -like "$Name" -OR $Item.AdminInfos.ID -eq $ID)) {


                # Avoid divisions by zero
                if ($Item.AdminInfos.Quotas.MaxProtSize -gt 0) { $MaxProtSize = (($Item.ServerInfos.Backup.ProtSize) / ($Item.AdminInfos.Quotas.MaxProtSize)) * 100 } else { $MaxProtSize = $null }
                if ($Item.AdminInfos.Quotas.MaxHistSize -gt 0) { $MaxHistSize = (($Item.ServerInfos.Backup.HistSize) / ($Item.AdminInfos.Quotas.MaxHistSize)) * 100 } else { $MaxHistSize = $null }
                if ($Item.AdminInfos.Quotas.MaxProtObjs -gt 0) { $MaxProtObjs = (($Item.ServerInfos.Backup.ProtObjs) / ($Item.AdminInfos.Quotas.MaxProtObjs)) * 100 } else { $MaxProtObjs = $null }
                if ($Item.AdminInfos.Quotas.MaxHistObjs -gt 0) { $MaxHistObjs = (($Item.ServerInfos.Backup.HistObjs) / ($Item.AdminInfos.Quotas.MaxHistObjs)) * 100 } else { $MaxHistObjs = $null }
                
                $CurrentLinaItem = [PSCustomObject]@{
                    Name                     = $Name_encoded
                    ID                       = $Item.AdminInfos.ID
                    Tenant                   = $Tenants | where-object { $_.ID -eq $Item.AdminInfos.DomainID } | Select-Object -ExpandProperty Name
                    AgentGroup               = Translate $Item.AdminInfos.AttachementArray.Group.Name 0 #Param 0 means encoding is already OK (UTF-8 because of JSON)
                    Strategy                 = Translate $Item.AdminInfos.ServiceProfile.Name 0 #Param 0 means encoding is already OK (UTF-8 because of JSON)
                    Protection               = Translate $Item.AdminInfos.DataProfile.Name 0 #Param 0 means encoding is already OK (UTF-8 because of JSON)

                    ComputerName             = $Item.AgentInfos.ComputerName
                    System                   = $Item.AgentInfos.System
                    SystemCategory           = TranslateSystemCategories($Item.AgentInfos.SystemCategory)
                    AgentVersion             = $Item.AgentInfos.AgentVersion
                    LastLogon                = $Item.AgentInfos.LastLogon
                    Email                    = $Item.AgentInfos.Email
                    CdpType                  = $Item.AgentInfos.CdpType
                    Alert                    = $Item.ServerInfos.Alerts.Alert
                        
                    ProtectedSizeMB          = [math]::Round(($Item.ServerInfos.Backup.ProtSize) / (1024 * 1024))
                    HistorySizeMB            = [math]::Round(($Item.ServerInfos.Backup.HistSize) / (1024 * 1024))
                    ProtectedObjects         = $Item.ServerInfos.Backup.ProtObjs
                    HistoryObjects           = $Item.ServerInfos.Backup.HistObjs

                    QuotaMaxProtSize         = $Item.AdminInfos.Quotas.MaxProtSize
                    QuotaMaxHistSize         = $Item.AdminInfos.Quotas.MaxHistSize
                    QuotaMaxProtObjs         = $Item.AdminInfos.Quotas.MaxProtObjs
                    QuotaMaxHistObjs         = $Item.AdminInfos.Quotas.MaxHistObjs

                    QuotaPercentUsedProtSize = [math]::Round($MaxProtSize)
                    QuotaPercentUsedHistSize = [math]::Round($MaxHistSize)
                    QuotaPercentUsedProtObjs = [math]::Round($MaxProtObjs)
                    QuotaPercentUsedHistObjs = [math]::Round($MaxHistObjs)
                        
                    # LastBackup = LastSync. LastCompleted session update even when there are some errors
                    LastBackup               = HumanFriendlyTimeSpan (LinaToLocalTime $Item.NetworkInfos.SyncTime)

                    LastSessionStart         = HumanFriendlyTimeSpan (LinaToLocalTime $Item.NetworkInfos.LastStartedSession)
                    LastSessionComplete      = HumanFriendlyTimeSpan (LinaToLocalTime $Item.NetworkInfos.LastCompletedSession)
                    LastConnection           = HumanFriendlyTimeSpan (LinaToLocalTime $Item.NetworkInfos.LastConnectionTime)
                    LastSync                 = HumanFriendlyTimeSpan (LinaToLocalTime $Item.NetworkInfos.SyncTime)

                    LastStartedSession       = LinaToLocalTime $Item.NetworkInfos.LastStartedSession
                    LastCompletedSession     = LinaToLocalTime $Item.NetworkInfos.LastCompletedSession
                    LastConnectionTime       = LinaToLocalTime $Item.NetworkInfos.LastConnectionTime
                    LastSyncTime             = LinaToLocalTime $Item.NetworkInfos.SyncTime

                    TenantID                 = $Item.AdminInfos.DomainID
                    AgentGroupID             = $Item.AdminInfos.AttachementArray.Group.ID
                    StrategyID               = $Item.AdminInfos.ServiceProfile.ID
                    ProtectionID             = $Item.AdminInfos.DataProfile.ID
                        
                    StrategyInternalName     = $Item.AdminInfos.ServiceProfile.Name
                    ProtectionInternalName   = $Item.AdminInfos.DataProfile.Name  
                }
                $LinaItems += $CurrentLinaItem
            }   
        }    
    
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No agent found."
        Return $Null
    }
    Return $LinaItems
}

function Get-LinaStrategy {
    <#
.SYNOPSIS
Retrieves the strategies on a Lina server.
.DESCRIPTION
Retrieves the strategies on a Lina server. Returns a set of strategies that correspond to the filter criteria provided.
If TenantID = 0, it is a global strategy across tenants.
.INPUTS
None
.OUTPUTS
Array of LinaStrategy Objects
.PARAMETER Name
Optional : Name of the strategy to retrieve. Wilcards are allowed. For example : *STRAT*
.PARAMETER ID
Optional : ID of the strategy to retrieve.
.EXAMPLE
Get-LinaStrategy
Retrieves all the strategies.
.EXAMPLE
Get-LinaStrategy -Name "*STRAT*"
Retrieves all the strategies with STRAT inside their names.
.EXAMPLE
Get-LinaStrategy -Name "*STRAT*" | Select-Object -Property Name,RPOInMinutes
Displays the list of strategies and their configured RPO in minutes.
#>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID
    )    
    Write-Verbose "Getting list of strategies"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/lst_serviceprofiles.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.ServiceProfileArray.ServiceProfile
    $Tenants = LinaTenantShort
    $LinaItems = @()
    foreach ($Item in $Items) {
        $translated_name = Translate($Item.Name)
        if ((!$Name -AND !$ID) -OR ( $Item.Name -like "$Name" -OR $Item.ID -eq $ID -OR $translated_name -like "$Name") ) {        
            
            if ([int]$Item.RepliTarget.ID -eq 0) {
                $replitarget = "None"
            }
            else {
                $replitarget = $Item.RepliTarget.Name
            }
            
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName               = 'LinaStrategy'
                Name                     = $translated_name
                ID                       = $Item.ID

                Tenant                   = ($Tenants | where-object { $_.ID -eq $Item.DomainID }).Name
                RPOInMinutes             = ($Item.ParamSchedule / 60)
                RetentionInDays          = $Item.ParamDataAging
                AlertAfterDays           = ($Item.ParamAlertTime / (24 * 3600))
                ThroughputLimitKBps      = $Item.ParamThroughputLimit
                ReplicationTarget        = $replitarget
                AlwaysEncrypt            = ![bool][int]$Item.ParamEncryptionActivated
                WanMode                  = [bool][int]$Item.ParamWanActivated
                CompressionAlgo          = $Item.ParamCompression
                AllowClientRPO           = [bool][int]$Item.ParamAllowClientRPO
                AllowClientRules         = [bool][int]$Item.ParamAllowClientRules
                AllowClientPause         = [bool][int]$Item.ParamAllowClientPause
                AllowClientBoost         = [bool][int]$Item.ParamAllowClientBoost
                AllowClientNetworkParams = [bool][int]$Item.ParamAllowClientNetworkParams
                AllowWebAccess           = [bool][int]$Item.ParamAllowWebAccess
                QuotaMaxProtSizeMB       = [math]::Round(($Item.ParamQuotaMaxProtSize) / (1024 * 1024))
                QuotaMaxProtObjs         = $Item.ParamQuotaMaxProtObjs
                QuotaMaxHistSizeMB       = [math]::Round(($Item.ParamQuotaMaxHistSize) / (1024 * 1024))
                QuotaMaxHistObjs         = $Item.ParamQuotaMaxHistObjs
                ReplicationTargetID      = $Item.RepliTarget.ID
                
                TenantID                 = $Item.DomainID
                InternalName             = $Item.Name
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No strategy found."
        Return $Null
    }
    Return $LinaItems
}

function Get-LinaProtection {
    <#
    .SYNOPSIS
    Retrieves the protection policies on a Lina server.
    .DESCRIPTION
    Retrieves the protection policies on a Lina server. Returns a set of protections that correspond to the filter criteria provided.
    .INPUTS
    None
    .OUTPUTS
    Array of LinaProtection Objects
    .PARAMETER Name
    Optional : Name of the protection to retrieve. Wilcards are allowed. For example : *PROT*
    .PARAMETER ID
    Optional : ID of the protection to retrieve.
    .PARAMETER ProtectionZone
    Optional : Filter by Protection zone name used in subrules. No wildcard allowed.
    .PARAMETER ProtectionRule
    Optional : Filter by Protection rule name used in subrules. No wildcard allowed.
    .EXAMPLE
    Get-LinaProtection
    Retrieves all the protections.
    .EXAMPLE
    Get-LinaProtection -Name "*PROT*"
    Retrieves all the protection with PROT inside their names.
    .EXAMPLE
    Get-LinaProtection -ID 15
    Retrieves the protection with ID 15
    .EXAMPLE
    Get-LinaProtection -ProtectionZone "The entire computer"
    Retrieves the protection with a subrule containing the protection zone named "MyProtection"
    .EXAMPLE
    Get-LinaProtection -ProtectionRule "Protect all objects"
    Retrieves the protection with a subrule containing the protection rule named "MyProtection"
    #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID,
        [Parameter(ParameterSetName = "ByProtRule")]
        [ValidateNotNullOrEmpty()]
        [string]$ProtectionRule,
        [Parameter(ParameterSetName = "ByProtZone")]
        [ValidateNotNullOrEmpty()]
        [string]$ProtectionZone           
            
    )    
    Write-Verbose "Getting list of protection policies"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/lst_dataprofiles.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.DataProfileArray.DataProfile
    $Tenants = LinaTenantShort
    $protection_rules = Get-LinaProtectionRule
    $protection_zones = Get-LinaProtectionZone       
    $LinaItems = @()

    if ($ProtectionRule) {
        $protection_rule_id_filter = ($protection_rules | Where-Object { $_.Name -eq $ProtectionRule }).ID
        if (!$protection_rule_id_filter) {
            Write-Host2 "No protection rule found with name $ProtectionRule. Please provide the exact name"
            return
        }
    }
    else {
        $protection_rule_id_filter = -1
    } 

    if ($ProtectionZone) {
        $protection_zone_id_filter = ($protection_zones | Where-Object { $_.Name -eq $ProtectionZone }).ID
        if (!$protection_zone_id_filter) {
            Write-Host2 "No protection zone found with name $ProtectionZone. Please provide the exact name"
            return
        }            
    }
    else {
        $protection_zone_id_filter = -1
    }  

    foreach ($Item in $Items) {

        if ((!$Name -AND !$ID -AND !$ProtectionRule -AND !$ProtectionZone ) -OR ( $Item.Name -like "$Name" -OR $Item.ID -eq $ID -OR (Translate($Item.Name)) -like "$Name" -OR $Item.RuleArray.RulePredef.FilterRuleID -contains $protection_rule_id_filter -OR $Item.RuleArray.RulePredef.PredefinedPathID -contains $protection_zone_id_filter) ) {        
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName       = 'LinaProtection'
                Name             = Translate($Item.Name)
                ID               = $Item.ID

                Tenant           = ($Tenants | where-object { $_.ID -eq $Item.DomainID }).Name
                OS               = $Item.OS
                BareMetalRestore = [bool][int]$Item.BMR
                BuiltIn          = [bool]($null -eq $Item.CustomRef)
                TenantID         = $Item.DomainID
                InternalName     = $Item.Name
            }
            $i = 1
            foreach ($subrule in $Item.RuleArray.RulePredef) {
                $subrule_protection = $protection_rules | where-object { $_.ID -eq $subrule.FilterRuleID }
                $subrule_path = $protection_zones | where-object { $_.ID -eq $subrule.PredefinedPathID }

                $CurrentLinaItem | add-member -membertype noteproperty -name "Rule#$i" -value ($subrule_path.Name + " ( " + $subrule_path.Path + " ) >> " + $subrule_protection.Name)
                $i++
            }

            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No protection found."
        Return $Null
    }        
    Return $LinaItems
}
    
function Get-LinaProtectionZone {
    <#
            .SYNOPSIS
            Retrieves the protection zones on a Lina server.
            .DESCRIPTION
            Retrieves the protection zones on a Lina server. Returns a set of protection zones that correspond to the filter criteria provided.
            .INPUTS
            None
            .OUTPUTS
            Array of LinaProtectionZone Objects
            .PARAMETER Name
            Optional : Name of the protection zone to retrieve. Wilcards are allowed. For example : *Mac*
            .PARAMETER ID
            Optional : ID of the protection zone to retrieve.
            .PARAMETER Path
            Optional : Return protection containing this exact path. Wildcards character (*) will be considered only as stars.
            .PARAMETER MatchingPath
            Optional : Return protection matching this path. Wilcards are allowed.
            .EXAMPLE
            Get-LinaProtectionZone
            Retrieves all the protection zones.
            .EXAMPLE
            Get-LinaProtectionZone -Name "*Mac*"
            Retrieves all the protection zones with Mac inside their names.
            .EXAMPLE
            Get-LinaProtectionZone -Path "\*\Users\*\"
            Retrieves the protection zones matching this exact path.
            .EXAMPLE
            Get-LinaProtectionZone -MatchingPath "\*\Users\*\"
            Retrieves all the protection zones matching this path (stars are considered as wildcards)
            #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID,
        [Parameter(ParameterSetName = "ByPath")]
        [ValidateNotNullOrEmpty()]
        [string]$Path,
        [Parameter(ParameterSetName = "ByMatchingPath")]
        [ValidateNotNullOrEmpty()]
        [string]$MatchingPath                   
    )    
    Write-Verbose "Getting list of protection zones"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/lst_predefinedpaths.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.PredefinedPathArray.PredefinedPath
    $Tenants = LinaTenantShort
    $LinaItems = @()
    foreach ($Item in $Items) {

        if ((!$Name -AND !$ID -AND !$Path -AND !$MatchingPath) -OR ( $Item.Name -like "$Name" -OR $Item.ID -eq $ID -OR (Translate($Item.Name)) -like "$Name" -OR $Item.Path -eq "$Path" -OR $Item.Path -like "$MatchingPath" ) ) {        
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName = 'LinaProtectionZone'
                Name       = Translate($Item.Name)
                ID         = $Item.ID
        
                Tenant     = ($Tenants | where-object { $_.ID -eq $Item.DomainID }).Name
                OS         = $Item.OS
                Path       = $Item.Path
                BuiltIn    = [bool]($null -eq $Item.CustomRef)

                TenantID   = $Item.DomainID
    
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No protection zone found."
        Return $Null
    }        
    Return $LinaItems
}

function Get-LinaFileCategory {
    <#
        .SYNOPSIS
        Retrieves the file categories on a Lina server.
        .DESCRIPTION
        Retrieves the file categories on a Lina server. Returns a set of file categories that correspond to the filter criteria provided.
        .INPUTS
        None
        .OUTPUTS
        Array of LinaFileCategory Objects
        .PARAMETER Name
        Optional : Name of the file category to retrieve. Wilcards are allowed. For example : *FILECAT*
        .PARAMETER ID
        Optional : ID of the file category to retrieve.
        .EXAMPLE
        Get-LinaFileCategory
        Retrieves all the file categories.
        .EXAMPLE
        Get-LinaProtection -Name "*Text*"
        Retrieves all the file categories with Text inside their names.
        #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID
    )    
    Write-Verbose "Getting list of file categories"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/lst_filetypes.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.FileTypeArray.FileType
    $Tenants = LinaTenantShort
    $LinaItems = @()
    foreach ($Item in $Items) {
        if ((!$Name -AND !$ID) -OR ( $Item.Name -like "$Name" -OR $Item.ID -eq $ID -OR (Translate($Item.Name)) -like "$Name" ) ) {        
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName     = 'LinaFileCategory'
                Name           = Translate($Item.Name)
                ID             = $Item.ID
    
                Tenant         = ($Tenants | where-object { $_.ID -eq $Item.DomainID }).Name
                FileExtensions = $Item.ExtArray.Ext
                BuiltIn        = [bool]($null -eq $Item.CustomRef)
    
                TenantID       = $Item.DomainID

            }
            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No file category found."
        Return $Null
    }        
    Return $LinaItems
}

function TranslateBehaviors ($to_translate) {
    switch ( $to_translate ) {
        "INCL" { $result = "Include / No Agent modification allowed" }
        "EXCL" { $result = "Exclude / No Agent modification allowed" }
        "ADVINCL" { $result = "Include / Allow agents modifications" }
        "ADVEXCL" { $result = "Exclude / Allow agents modifications" }
    }
    return $result
}

function Get-LinaProtectionRule {
    <#
            .SYNOPSIS
            Retrieves the protection rules on a Lina server.
            .DESCRIPTION
            Retrieves the protection rules on a Lina server. Returns a set of file categories that correspond to the filter criteria provided.
            .INPUTS
            None
            .OUTPUTS
            Array of LinaProtectionRules Objects
            .PARAMETER Name
            Optional : Name of the protection rule to retrieve. Wilcards are allowed. For example : *FILECAT*
            .PARAMETER ID
            Optional : ID of the protection rule to retrieve.
            .EXAMPLE
            Get-LinaProtectionRule
            Retrieves all the protection rules.
            .EXAMPLE
            Get-LinaProtectionRule -Name "*Office*"
            Retrieves all the protection rules with Office inside their names.
            #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID
    )    
    Write-Verbose "Getting list of protection rules"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/lst_filters.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.FilterRuleArray.FilterRule
    $Tenants = LinaTenantShort
    $FileCategories = Get-LinaFileCategory
    $LinaItems = @()
    foreach ($Item in $Items) {
        if ((!$Name -AND !$ID) -OR ( $Item.Name -like "$Name" -OR $Item.ID -eq $ID -OR (Translate($Item.Name)) -like "$Name" ) ) {        

                        
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName      = 'LinaProtectionRule'
                Name            = Translate($Item.Name)
                ID              = $Item.ID
                Tenant          = ($Tenants | where-object { $_.ID -eq $Item.DomainID }).Name
                DefaultBehavior = TranslateBehaviors($Item.DefaultBehavior)
                BuiltIn         = [bool]($null -eq $Item.CustomRef)
                TenantID        = $Item.DomainID
    
            }
            $i = 1
            foreach ($subrule in $Item.SubRuleArray.SubRule) {
                $filecat_name = ($FileCategories | where-object { $_.ID -eq $subrule.FileType.ID }).Name
                $rule_behavior = TranslateBehaviors($subrule.Behavior)

                $CurrentLinaItem | add-member -membertype noteproperty -name "Rule#$i" -value ($rule_behavior + ' : ' + $filecat_name)
                $i++
            }

            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No protection rule found."
        Return $Null
    }        
    Return $LinaItems
}

function TranslatePermissions($permissions, $perm_category) {

    $perms_filtered = $permissions | Where-Object { $_ -like "*$perm_category" } | ForEach-Object { $_ -replace "$perm_category", "" }

    $short_perms = ""
    ForEach ($perm in $perms_filtered) {
        $short_perms += $perm + ","
    }
    # Trimming last character ,
    $short_perms = $short_perms -replace ",$"

    Switch ($perm_category) {
        { 'UserProfiles', 'Users', 'Replications', 'AlnAgent', 'AlnStrategy', 'AlnProtection', 'AlnProtectionRule', 'AlnProtectionZone', 'AlnFileCategory', 'Domains' -contains $_ } {
            if ($short_perms -eq "View,Create,Delete,Set") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'Alerts', 'Services', 'BMR', 'License', 'Smtp', 'Ldap', 'Config' -contains $_ } {
            if ($short_perms -eq "View,Set") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'Support', 'Files', 'Smtp', 'Ldap', 'Config' -contains $_ } {
            if ($short_perms -eq "View") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'Snapshot' -contains $_ } {
            if ($short_perms -eq "View,Create,Delete") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'Tunables' -contains $_ } {
            if ($short_perms -eq "View,Set,ViewAdvanced") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'Statistics' -contains $_ } {
            if ($short_perms -eq "View,Recompute") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'AlnDefaultConfiguration', 'AlnGlobalDefaultConfiguration' -contains $_ } {
            if ($short_perms -eq "Set") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        { 'Service' -contains $_ } {
            if ($short_perms -eq "Restart") {
                Return "Full"
            }
            else {
                Return $short_perms
            }
        }
        Default {
            Return $short_perms
        }
    }
    if ($short_perms -like "*View,Create,Delete,Set*" -OR $short_perms -like "*ViewAll,Create,Delete,Set*") {
        Return "ALL"
    }
    Return $short_perms
}

function Get-LinaUserProfile {
    <#
    .SYNOPSIS
    Retrieves the user profiles
    .DESCRIPTION
    Retrieves the user profiles.
    By default only show Lina permissions (corresponds to Lina tab in Web interface).
    Use the -ShowAllPermissions to also displays Users tab and Server Tab permissions.
    "Full" means that the user have all the possible permissions in the category.
    Note : Requires PowerShell 5.0 or greater.
    .INPUTS
    None
    .OUTPUTS
    Array of LinaUserProfile Objects
    .PARAMETER Name
    Optional : Name of the user profile to retrieve. Wilcards are allowed. For example : *UserProfile*
    .PARAMETER ID
    Optional : ID of the user profile to retrieve.
    .PARAMETER Tenant
    Optional : Tenant of the user profile to retrieve.
    .EXAMPLE
    Get-LinaUserProfile
    Retrieves all the user profiles and shows only Lina permissions
    .EXAMPLE
    Get-LinaUserProfile -ShowAllPermissions
    Retrieves all the user profiles and shows all permissions Lina + Users + Server
    .EXAMPLE
    Get-LinaUserProfile -Name "MyProfile"
    Retrieves MyProfile Lina permissions
    .EXAMPLE
    Get-LinaUserProfile -Tenant "MyTenant" | Where {$_.BuiltIn -eq $False -AND $_.Name -ne "Default"}
    Retrieves all custom profiles from Tenant MyTenant
    #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID,
        [Parameter(Mandatory = $False)]
        [ValidateNotNullOrEmpty()]
        [string]$Tenant,
        [Parameter(Mandatory = $False)]
        [Switch]$ShowAllPermissions
    )    
    Write-Verbose "Getting list of user profiles"
    if ($PSVersionTable.PSVersion.Major -lt 5) {
        Write-Host2 "ERROR : This cmdlet requires PowerShell 5.0 or greater in order to work"
        Return 
    }
 
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/ADM/list_profile.json?timestamp=$timestamp"
    $Items = $request.profiles
    $Tenants = LinaTenantShort
    $LinaItems = @()
        
    # Filter on Tenant
    if ($Tenant) {
        $domain = $Tenants | Where-Object { $_.Name -eq $Tenant }
        $domain_id = [int]$domain.ID
        $domain_name = [string]$domain.Name
    }

    foreach ($Item in $Items) {
        # Fixing name of default Administrator Profile
        if ($Item.name -eq "Admin" -AND $Item.custom -eq $False) {
            $translated_name = FixEncoding(Translate "USER_PROFILE_NAME_ADMIN")
        }
        else {
            # Only one item is builtin, all others are custom
            $translated_name = FixEncoding($Item.name)
        }

        # Filtering specific accounts SuperAdmin and Guest
        if ((!$Name -AND !$ID -AND $Item.name -notin ("SuperAdmin", "Guest")) -OR ( $Item.name -like "$Name" -OR $Item.id -eq $ID -OR $translated_name -like "$Name") ) {        
                
            # When Roles are negatives, means we have to use highest value less this one (+1 but i don't know why ..)
            # Negative values are used by default profiles only
            if ($Item.roles1 -lt 0) {
                $roles1_value = $ROLES1_MAX + $Item.roles1 + 1
            }
            else {
                $roles1_value = $Item.roles1
            }

            if ($Item.roles2 -lt 0) {
                $roles2_value = $ROLES2_MAX + $Item.roles2 + 1
            }
            else {
                $roles2_value = $Item.roles2
            }

            if ($Item.roles3 -lt 0) {
                $roles3_value = $ROLES3_MAX + $Item.roles3 + 1
            }
            else {
                $roles3_value = $Item.roles3
            }

            if ($Item.roles4 -lt 0) {
                $roles4_value = $ROLES4_MAX + $Item.roles4 + 1
            }
            else {
                $roles4_value = $Item.roles4
            }

            $roles1_list = [ROLES1_LIST]$roles1_value -split ", "
            $roles2_list = [ROLES2_LIST]$roles2_value -split ", "
            $roles3_list = [ROLES3_LIST]$roles3_value -split ", "
            $roles4_list = [ROLES4_LIST]$roles4_value -split ", "

            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName                 = 'LinaUserProfile'
                Name                       = $translated_name
                ID                         = $Item.id
                Tenant                     = ($Tenants | where-object { $_.ID -eq $Item.domain_id }).Name
                # Because is not in use in the Web interface
                #Comment = $Item.comment

                Lina_Agents                = TranslatePermissions $roles3_list "AlnAgent"
                Lina_Strategies            = TranslatePermissions $roles3_list "AlnStrategy"
                Lina_Protections           = TranslatePermissions $roles3_list "AlnProtection"
                Lina_ProtectionRules       = TranslatePermissions $roles3_list "AlnProtectionRule"
                Lina_ProtectionZones       = TranslatePermissions $roles4_list "AlnProtectionZone"
                Lina_FileCategories        = TranslatePermissions $roles4_list "AlnFileCategory"
                Lina_Preferences           = TranslatePermissions $roles4_list "AlnDefaultConfiguration"
                Lina_GlobalDefaultSettings = TranslatePermissions $roles4_list "AlnGlobalDefaultConfiguration"
                # Lina_CrossRestore = TranslatePermissions $roles1_list "CrossResto"
                # Lina_BMRRestore = TranslatePermissions $roles1_list "BMRResto"
                    
            }

            if ($ShowAllPermissions) {
                $CurrentLinaItem | add-member -membertype noteproperty -name "Users_Users"          -value ( TranslatePermissions $roles1_list "Users" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Users_UserProfiles"   -value ( TranslatePermissions $roles1_list "UserProfiles" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Users_SMTP"           -value ( TranslatePermissions $roles2_list "Smtp" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Users_LDAP"           -value ( TranslatePermissions $roles2_list "Ldap" )
                    
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Replications"       -value ( TranslatePermissions $roles1_list "Replications" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Snapshot"           -value ( TranslatePermissions $roles2_list "Snapshot" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Configuration"      -value ( TranslatePermissions $roles2_list "Config" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Alerts"             -value ( TranslatePermissions $roles1_list "Alerts" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Services"           -value ( TranslatePermissions $roles1_list "Services" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_License"            -value ( TranslatePermissions $roles2_list "License" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Maintenance"        -value ( TranslatePermissions $roles1_list "Support" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Files"              -value ( TranslatePermissions $roles2_list "Files" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_FineTuning"         -value ( TranslatePermissions $roles2_list "Tunables" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_Statistics"         -value ( TranslatePermissions $roles2_list "Statistics" )
                $CurrentLinaItem | add-member -membertype noteproperty -name "Server_ServiceRestart"     -value ( TranslatePermissions $roles2_list "Service" )
                #Streams = TranslatePermissions $roles2_list "Streams"
            }
            $CurrentLinaItem | add-member -membertype noteproperty -name "BuiltIn" -value ( [bool](!$Item.custom) )
            $CurrentLinaItem | add-member -membertype noteproperty -name "UUID" -value ( $Item.uuid )
            $CurrentLinaItem | add-member -membertype noteproperty -name "InternalRoles1" -value ( $roles1_value )
            $CurrentLinaItem | add-member -membertype noteproperty -name "InternalRoles2" -value ( $roles2_value )
            $CurrentLinaItem | add-member -membertype noteproperty -name "InternalRoles3" -value ( $roles3_value )
            $CurrentLinaItem | add-member -membertype noteproperty -name "InternalRoles4" -value ( $roles4_value )
            $CurrentLinaItem | add-member -membertype noteproperty -name "TenantID" -value ( $Item.domain_id )
            $CurrentLinaItem | add-member -membertype noteproperty -name "InternalName" -value ( $Item.name )

            # Filtering User profiles by tenant when tenant is provided
            if (!$Tenant -OR $CurrentLinaItem.TenantID -eq $domain_id) {
                $LinaItems += $CurrentLinaItem
            }
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No user profile found."
        return $null
    }
    Return $LinaItems
}

function Get-LinaUser {
    <#
            .SYNOPSIS
            Retrieves the users on a Lina server.
            .DESCRIPTION
            Retrieves the users on a Lina server.
            .INPUTS
            None
            .OUTPUTS
            Array of LinaUser Objects
            .PARAMETER Name
            Optional : Name of the user to retrieve. Wilcards are allowed. For example : *Jon*
            .PARAMETER ID
            Optional : ID of the user to retrieve.
            .EXAMPLE
            Get-LinaUser
            Retrieves all the users.
            .EXAMPLE
            Get-LinaUser -Name "*Jon*"
            Retrieves all the users with Jon inside their names.
            #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID                 
    )    
    Write-Verbose "Getting list of users"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/ADM/user.json?timestamp=$timestamp"
    $Items = $request.users
    $request2 = CallAPI -Path "/ADM/list_user_ug_relation.json?timestamp=$timestamp"
    $User_to_UserGroup = $request2.relations
    $Tenants = LinaTenantShort
    $UserGroups = Get-LinaUserGroup
    $LinaItems = @()
    foreach ($Item in $Items) {
        if ((!$Name -AND !$ID -AND $Item.name -notin ("superadmin", "guest")) -OR ( $Item.name -like "$Name" -OR $Item.id -eq $ID -OR (FixEncoding($Item.name)) -like "$Name" ) ) {        
            $UserGroupID= ($User_to_UserGroup | where-object {$_.user_id -eq $Item.id}).ug_id
            $UserGroupObject = $UserGroups | where-object { $_.ID -eq $UserGroupID }
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName  = 'LinaUser'
                Name        = FixEncoding($Item.name)
                ID          = $Item.id
                Tenant      = ($Tenants | where-object { $_.ID -eq $Item.domain_id }).Name
                UserGroup   = $UserGroupObject.Name
                UserProfile = $UserGroupObject.UserProfile
                Disabled    = [bool]($Item.disabled)
                # Have to check what is type
                Type        = $global:INT_USER_TYPES[$Item.type]
                BuiltIn     = [bool](!$Item.custom)
                TenantID    = $Item.domain_id
                UserGroupID = $UserGroupObject.ID
                UserProfileID = $UserGroupObject.UserProfileID
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No user found."
        Return $Null
    }        
    Return $LinaItems
}

function Get-LinaUserGroup {
    <#
            .SYNOPSIS
            Retrieves the user groups on a Lina server.
            .DESCRIPTION
            Retrieves the user groups on a Lina server.
            .INPUTS
            None
            .OUTPUTS
            Array of LinaUserGroup Objects
            .PARAMETER Name
            Optional : Name of the user group to retrieve. Wilcards are allowed. For example : *Admin*
            .PARAMETER ID
            Optional : ID of the user group to retrieve.
            .EXAMPLE
            Get-LinaUserGroup
            Retrieves all the user groups.
            .EXAMPLE
            Get-LinaUserGroup -Name "*Admin*"
            Retrieves all the user groups with Admin inside their names.
            #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID                 
    )    
    Write-Verbose "Getting list of user groups"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/ADM/list_user_group.json?timestamp=$timestamp"
    $Items = $request.user_groups
    $request2 = CallAPI -Path "/ADM/list_prof_ug_relation.json?timestamp=$timestamp"
    $UserGroup_to_UserProfile = $request2.relations
    $Tenants = LinaTenantShort
    $UserProfiles = Get-LinaUserProfile
    $LinaItems = @()
    foreach ($Item in $Items) {
        if ($Item.custom) {
            $ug_name=FixEncoding($Item.name)
        }else {
            $name_upper=$Item.name.ToUpper()
            $ug_name=Translate("USER_GROUP_NAME_$name_upper")
        }
         
        if ((!$Name -AND !$ID -AND $Item.name -notin ("SuperAdmin", "Guest")) -OR ( $Item.name -like "$Name" -OR $Item.id -eq $ID -OR $ug_name -like "$Name" ) ) {        
            $UserProfileID= ($UserGroup_to_UserProfile | where-object {$_.ug_id -eq $Item.id}).prof_id
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName = 'LinaUserGroup'
                Name          = $ug_name
                ID            = $Item.id
                Tenant        = ($Tenants | where-object { $_.ID -eq $Item.domain_id }).Name
                UserProfile   = ($UserProfiles | where-object { $_.ID -eq $UserProfileID }).Name
                BuiltIn       = [bool](!$Item.custom)
                TenantID      = $Item.domain_id
                UserProfileID = $UserProfileID
                InternalName  = $Item.name
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No user group found."
        Return $Null
    }        
    Return $LinaItems
}

function Get-LinaTenant {
    <#
.SYNOPSIS
Retrieves the tenants (entities) on a Lina server.
.DESCRIPTION
Retrieves the tenants (entities) on a Lina server. Returns a set of tenants that correspond to the filter criteria provided.
.INPUTS
None
.OUTPUTS
Array of LinaTenant Objects
.PARAMETER Name
Optional : Name of the tenant to retrieve. Wilcards are allowed. For example : *Tenant*
.PARAMETER ID
Optional : ID of the tenant to retrieve.
.PARAMETER Default
Get the default tenant if any
.EXAMPLE
Get-LinaTenant
Retrieve all tenants
.EXAMPLE
Get-LinaTenant -Name "BaasCustomer1"
Retrieve Tenant named BaasCustomer1
.EXAMPLE
Get-LinaTenant -ID 2
Retrieve Tenant with ID 2
.EXAMPLE
Get-LinaTenant -Default
Retrieve the default tenant (if any)
#>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(Mandatory = $false, Position = 0, ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(Mandatory = $True, ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID,
        [Parameter(Mandatory = $True, ParameterSetName = "Default")]
        [switch]$Default
    )
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/ADE/check_session.xml?timestamp=$timestamp"
    $current_tenant_id = [int](([xml]$request).session.effective_domain_id)

    if ($current_tenant_id -gt 1) {
        Write-Host2 "WARNING : to list tenants you should be logged as superadmin and be in the global view (using Set-LinaCurrentTenant -All). Current tenant ID is : $current_tenant_id"
        return ""
    }

    Write-Verbose "Getting list of tenants"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/ADM/list_domain.json?timestamp=$timestamp"
    $Items = $request.domains
  
    $request2 = CallAPI -Path "/lst_globals.xml?domain_id=0"
    $prefs_global = ([xml]$request2).HNConfig.Globals
    $prefs_tenants = ([xml]$request2).HNConfig.Globals.DomainGlobalsArray.DomainGlobals

    
    $cache_strategies = Get-LinaStrategy
    $cache_protections = Get-LinaProtection


    $LinaItems = @()
    foreach ($Item in $Items) {
        $name_encoded = FixEncoding($Item.name)
        if ((!$Name -AND !$ID) -OR $Item.name -like "$Name" -OR $name_encoded -like "$Name" -OR $Item.id -eq $ID ) {
            if ($prefs_tenants.DomainID -contains [int]$Item.id) {
                $DefaultStrategyID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).WinDefaultServiceProfileID
                $WindowsDefaultProtectionID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).WinDefaultDataProfileID
                $MacDefaultProtectionID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).MacDefaultDataProfileID
                $LinuxDefaultProtectionID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).LinuxDefaultDataProfileID
            }
            else {
                $DefaultStrategyID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).WinDefaultServiceProfileID
                $WindowsDefaultProtectionID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).WinDefaultDataProfileID
                $MacDefaultProtectionID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).MacDefaultDataProfileID
                $LinuxDefaultProtectionID = ($prefs_tenants | where-object { $_.DomainID -eq [int]$Item.id }).LinuxDefaultDataProfileID
            }
            # These ones are always shared across tenants
            $AutoCreateClients = [bool][int]$prefs_global.AutoCreateClients

            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName                 = 'LinaTenant'
                Name                       = $name_encoded
                ID                         = $Item.id

                # Had to reencode to UTF-8 because of a bug or maybe to bad return type
                Comment                    = FixEncoding($Item.comment)
                IsDefault                  = [bool][int]$Item.def_domain

                AutoCreateClients          = $AutoCreateClients
                WindowsDefaultProtection   = ($cache_protections | Where-Object { $WindowsDefaultProtectionID -eq $_.ID }).Name
                MacDefaultProtection       = ($cache_protections | Where-Object { $MacDefaultProtectionID -eq $_.ID }).Name
                LinuxDefaultProtection     = ($cache_protections | Where-Object { $LinuxDefaultProtectionID -eq $_.ID }).Name
                DefaultStrategy            = ($cache_strategies | Where-Object { $DefaultStrategyID -eq $_.ID }).Name
                
                # Need to check if this one is always global or not
                # WebRestoreEnabled = $tenant_config.WebRestoreEnabled

                WindowsDefaultProtectionID = $WindowsDefaultProtectionID
                MacDefaultProtectionID     = $MacDefaultProtectionID
                LinuxDefaultProtectionID   = $LinuxDefaultProtectionID   
                DefaultStrategyID          = $DefaultStrategyID

                UUID                       = $Item.uuid
            }
            $LinaItems += $CurrentLinaItem
        }
        
    }

    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No tenant found."
        Return $null
    }
    
    if ($Default) {
        Return ($LinaItems | Where-Object { $_.IsDefault })
    }
    else {
        Return $LinaItems
    }
}

function LinaTenantShort {
    <#
    .SYNOPSIS
    Retrieves the tenants (entities) on a Lina server.
    .DESCRIPTION
    Retrieves the tenants (entities) on a Lina server. Returns a set of tenants that correspond to the filter criteria provided.
    .INPUTS
    None
    .OUTPUTS
    Array of LinaTenant Objects
    .PARAMETER Name
    Optional : Name of the tenant to retrieve. Wilcards are allowed. For example : *Tenant*
    .PARAMETER ID
    Optional : ID of the tenant to retrieve.
    .PARAMETER Default
    Get the default tenant if any
    .EXAMPLE
    Get-LinaTenant
    Retrieve all tenants
    .EXAMPLE
    Get-LinaTenant -Name "BaasCustomer1"
    Retrieve Tenant named BaasCustomer1
    .EXAMPLE
    Get-LinaTenant -ID 2
    Retrieve Tenant with ID 2
    .EXAMPLE
    Get-LinaTenant -Default
    Retrieve the default tenant (if any)
    #>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(Mandatory = $false, Position = 0, ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(Mandatory = $True, ParameterSetName = "ByID")]
        [ValidateRange(-1, 2147483647)]
        [int]$ID,
        [Parameter(Mandatory = $True, ParameterSetName = "Default")]
        [switch]$Default
    
    )
    Write-Verbose "Getting list of tenants (short)"
    $request = CallAPI -Path "/ADM/list_domain.json?timestamp=$timestamp"
    $Items = $request.domains
    $LinaItems = @()
    foreach ($Item in $Items) {
        $name_encoded = FixEncoding($Item.name)
        if ((!$Name -AND !$ID) -OR $Item.name -like "$Name" -OR $name_encoded -like "$Name" -OR $Item.id -eq $ID ) {
    
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName = 'LinaTenant'
                Name       = FixEncoding($Item.name)
                ID         = $Item.id
    
                # Had to reencode to UTF-8 because of a bug or maybe to bad return type
                Comment    = FixEncoding($Item.comment)
                IsDefault  = [bool][int]$Item.def_domain
    
                UUID       = $Item.uuid
            }
            $LinaItems += $CurrentLinaItem
        }
            
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No tenant found."
        Return $Null
    }
    if ($Default) {
        Return ($LinaItems | Where-Object { $_.IsDefault })
    }
    else {
        Return $LinaItems
    }
}

function Get-LinaAgentStats {
    <#
.SYNOPSIS
Retrieves the agents statistics and advanced information on a Lina server.
.DESCRIPTION
Retrieves the agents statistics and advanced information on a Lina server. Statistics are only available for agent that have been online at least one time.
.INPUTS
None
.OUTPUTS
Array of LinaAgentStats Objects
.PARAMETER Name
Name of the agent(s) to retrieve. Wilcards are allowed. For example : *DESKTOP*
.PARAMETER ID
ID of the agent to retrieve. For example : 134.
.EXAMPLE
Get-LinaAgentStats
Retrieve all agent stats
.EXAMPLE
Get-LinaAgentStats | where {$_.LastLogon -like "*mike*"}
Retrieve agent info on agents where mike is logged in.
.EXAMPLE
Get-LinaAgentStats | where {$_.LastCompletedSession -le (Get-Date).AddDays(-7)}
Retrieve agent info on agents with no completed backups in last 7 days
#>

    [cmdletbinding(DefaultParameterSetName = "ByName")]
    Param(
        [Parameter(ValueFromPipeline)]
        [pscustomobject]$lina_agent,
        [Parameter(ParameterSetName = "ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID
    )
    if ($global:INT_LINA_API_VERSION -ge 51) {
        Write-Host2 "WARNING : Get-LinaAgentStats is deprecated with Lina 5.1, use Get-LinaAgent instead. Commands have been merged"
        return 
    }
    Write-Verbose "Getting agents Statistics (only available if has been online)"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/stats_clients.xml?timestamp=$timestamp"
    $Items = ([xml]$request).Stats.ClientArray.Client
    $LinaItems = @()
    foreach ($Item in $Items) {
        <# Filtering on ID or Name (only if provided) #>
        if ((!$Name -AND !$ID -AND !$lina_agent) -OR ($Item.AdminName -like "$Name" -OR $Item.AdminID -eq $ID -OR $lina_agent.ID -eq $Item.AdminID ) ) {
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName             = 'LinaAgentStats'
                Name                   = $Item.AdminName
                ID                     = $Item.AdminID

                ComputerName           = $Item.ComputerName
                System                 = $Item.System
                SystemCategory         = TranslateSystemCategories($Item.SystemCategory)
                AgentVersion           = $Item.AgentVersion
                Strategy               = Translate($Item.AdminServiceProfileName)
                Protection             = Translate($Item.AdminDataProfileName)
                LastLogon              = $Item.LastLogon
                Email                  = $Item.Email
                CdpType                = $Item.CdpType
                Alert                  = $Item.Alert
                
                LastBackup             = HumanFriendlyTimeSpan (LinaToLocalTime $Item.SyncTime)

                LastSessionStart       = HumanFriendlyTimeSpan (LinaToLocalTime $Item.LastStartedSession)
                LastSessionComplete    = HumanFriendlyTimeSpan (LinaToLocalTime $Item.LastCompletedSession)
                LastConnection         = HumanFriendlyTimeSpan (LinaToLocalTime $Item.LastConnectionTime)
                LastSync               = HumanFriendlyTimeSpan (LinaToLocalTime $Item.SyncTime)

                LastStartedSession     = LinaToLocalTime $Item.LastStartedSession
                LastCompletedSession   = LinaToLocalTime $Item.LastCompletedSession
                LastConnectionTime     = LinaToLocalTime $Item.LastConnectionTime
                LastSyncTime           = LinaToLocalTime $Item.SyncTime
                
                StrategyInternalName   = $Item.AdminServiceProfileName
                ProtectionInternalName = $Item.AdminDataProfileName
            }
            $LinaItems += $CurrentLinaItem
        }
        
    }
    if ($LinaItems.Count -eq 0) {
        Write-Verbose "No agent statistics found."
        Return $Null
    }        
    Return $LinaItems
}

function Get-LinaAgentGroup {
    <#
.SYNOPSIS
Retrieves the agent groups
.DESCRIPTION
Retrieves the agent groups (Main view of agents)
.INPUTS
None
.OUTPUTS
Array of LinaAgentGroup Objects
.PARAMETER Name
Name of the Group to retrieve. Wilcards are allowed. For example : *UNCATEGOR*
.PARAMETER ID
ID of the group retrieve. For example : 4.
.PARAMETER Tenant
Name of the Tenant hosting the groups
Can also be used in conjunction with -Name to filter by name AND Tenant.
Can be useful if multiple groups have the same name in multiple tenants.
.EXAMPLE
Get-LinaAgentGroup
Retrieve all agent groups
.EXAMPLE
Get-LinaAgentGroup -ID 131
Retrieve agent group by it ID. Will return a unique object.
.EXAMPLE
Get-LinaAgentGroup -Name "Group1"
Retrieve agent group by its Name. Wilcards are allowed.
Warning : result may not be unique even without using wildcards. Group names may not be unique across tenants.
.EXAMPLE
Get-LinaAgentGroup -Tenant "MyTenant"
Retrieve agent groups of the Tenant MyTenant
.EXAMPLE
Get-LinaAgentGroup -Name "Group1" -Tenant "BaasCustomer1"
Filter agent group by name and by Tenant MyTenant. If not using wildcards in name, return will be unique.
#>

    [cmdletbinding(DefaultParameterSetName = 'ByNothing')]
    Param(
        [Parameter(Mandatory = $true, ParameterSetName = "ByName")]
        [Parameter(Mandatory = $True, ParameterSetName = "ByNameAndTenant")]
        [Parameter(Mandatory = $false, ParameterSetName = "ByNothing")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(Mandatory = $true, ParameterSetName = "ByID")]
        [ValidateRange(0, 2147483647)]
        [int]$ID,
        [Parameter(Mandatory = $True, ParameterSetName = "ByTenant")]
        [Parameter(Mandatory = $True, ParameterSetName = "ByNameAndTenant")]
        [Parameter(Mandatory = $false, ParameterSetName = "ByNothing")]
        [ValidateNotNullOrEmpty()]
        [string]$Tenant
    )
    if ($Tenant) {
        $TenantID = (LinaTenantShort -Name $Tenant).ID
        Write-Verbose "Getting agent groups for Tenant $Tenant (ID $TenantID)"
    }
    else {
        Write-Verbose "Getting agent groups"
    }
        
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/lst_hierarchies.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.HierarchyArray.Hierarchy.GroupArray.Group
    $Tenants = LinaTenantShort
    $LinaItems = @()
    foreach ($Item in $Items) {
        # PreFiltering By Tenant (Groups in tenant 0 are for all Tenants, example : Unsorted agents)
        if (!$TenantID -OR $Item.DomainID -eq $TenantID -OR $Item.DomainID -eq 0 ) {
            <# Filtering on ID or Name (only if provided) #>
            $name_translation = Translate($Item.Name) 
            if ((!$Name -AND !$ID) -OR ( $name_translation -like "$Name" -OR $Item.ID -eq $ID) ) {
                $CurrentLinaItem = [PSCustomObject]@{
                    PSTypeName   = 'LinaAgentGroup'
                    Name         = $name_translation
                    ID           = $Item.ID
                    Tenant       = $Tenants | where-object { $_.ID -eq $Item.DomainID } | Select-Object -ExpandProperty Name
                    NbAgents     = $Item.NbRefs 

                    InternalName = $Item.Name
                    TenantID     = $Item.DomainID
                }
                $LinaItems += $CurrentLinaItem
            }
        }
            
    }
    if ($LinaItems.Count -eq 0) {
        Write-Host2 "No agent group found."
        Return $Null
    }            
    Return $LinaItems
}
 
function Get-LinaCurrentTenantID {
    <#
.SYNOPSIS
Get the current tenant
.DESCRIPTION
Get the current tenant. If current tenant is the Global View (no tenant selected), it will return -1.
.INPUTS
None
.OUTPUTS
Current tenant ID
.EXAMPLE
$current_tenant_id = Get-LinaCurrentTenantID
Get the current tenant ID.
#>

    Write-Verbose "Getting current tenant"
    $timestamp = LinaTimestamp
    $request = CallAPI -Path "/ADE/check_session.xml?timestamp=$timestamp"
    $current_tenant_id = [int](([xml]$request).session.effective_domain_id)
    if ($current_tenant_id -eq -1 -OR $current_tenant_id -eq 1) {
        # Notes on tenant numbers : -1 and 0 => Global View, 1 = Root (first level tenant invisible/ contains superadmin and guest). >1 : Second level tenants
        Write-Host2 "No current tenant selected (ID = -1 or 1). Global view on all tenants."
        Return -1
    }
    elseif ($current_tenant_id -gt 1) {
        $current_tenant = LinaTenantShort -ID $current_tenant_id
        $current_tenant_name = $current_tenant.Name 
        Write-Host2 "Current tenant is $current_tenant_name (ID $current_tenant_id)"
        Return $current_tenant_id
    }
    else {
        TranslateErrorCode -LinaError $request -FailedAction "get current tenant"
        Return $null
    }
}