Atempo.Lina.psm1

<#
 .Synopsis
  This Windows PowerShell module contains PowerCLI Cloud Infrastructure Suite cmdlets.
 
 .Description
  Provide basic management of Lina Agents
 
 .Example
Connect-BetaLinaServer -Server "https://10.0.0.1:8181" -User "superadmin" -Password "MyPassword"
Get-BetaLinaGlobalStats
Get-BetaLinaAgent
Get-BetaLinaAgentStats
Get-BetaLinaCurrentTenant
Get-BetaLinaStrategy
Get-BetaLinaTenant
New-BetaLinaAgent -Name "TEST-QA-API"
Set-BetaLinaAgent -Name "TEST-QA-API" -NewName "TEST-QA-API-RENAMED"
Get-BetaLinaAgent -Name "TEST-QA-API-RENAMED" | Remove-BetaLinaAgent
Get-BetaLinaTenant -Name "BaasCustomer1" | Set-BetaLinaCurrentTenant
Get-BetaLinaCurrentTenant
Disconnect-BetaLinaServer
#>


<# TODO
    improve global stats and agent stats
    manage display of replications
    missing objects (groups, paths, rules etc)
    Ability to pipe commands => should be done everywhere
    Improved error reporting (get error codes ?)
#>


<# Other URLS :
Global stats / info.xml : Objects in infolist
Protection / lst_dataprofiles.xml : Objects in HNConfig.DataProfileArray.DataProfile
Protection rules / lst_filters.xml : Objects in HNConfig.FilterRuleArray.FilterRule
Paths / lst_predefinedpaths.xml : Objects in HNConfig.PredefinedPathArray.PredefinedPath
File Types / lst_filetypes.xml : Objects in HNConfig.FileTypeArray.FileType
Agent groups / lst_hierarchies.xml : Objects in HNConfig.HierarchyArray.Hierarchy
User groups / ADM/list_user_group.json : Objects in user_groups
Groups to users / ADM/list_prof_ug_relation.json : Objects in relations
#>


# Needed for URLEncode
Add-Type -AssemblyName System.Web
$global:LoggedSession = $null
$global:GLOBAL_LINA_SERVER = $null
$global:LINA_TRANSLATIONS = $null
$global:GLOBAL_IGNORE_CERTIFICATES = $True

function Disable-SslVerification
{
    if (-not ([System.Management.Automation.PSTypeName]"TrustEverything").Type)
    {
        Add-Type -TypeDefinition  @"
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public static class TrustEverything
{
    private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain,
        SslPolicyErrors sslPolicyErrors) { return true; }
    public static void SetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = ValidationCallback; }
    public static void UnsetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = null; }
}
"@

    }
    [TrustEverything]::SetCallback()
}
function Enable-SslVerification
{
    if (([System.Management.Automation.PSTypeName]"TrustEverything").Type)
    {
        [TrustEverything]::UnsetCallback()
    }
}

function CallAPI(){
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$True,Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$Path,
        [Parameter(Mandatory=$False,Position=1)]
        [ValidateNotNullOrEmpty()]
        [string]$ContentType,
        [Parameter(Mandatory=$False,Position=2)]
        [ValidateNotNullOrEmpty()]
        [string]$Body,                  
        [Parameter()]
        [switch]$FirstConnection
    )
    
    if ($Path -like "*.json*") {
        $ContentType="application/json"
    }else {
        # most content is XML so this is default
        $ContentType="application/xml"
    }

    if ($FirstConnection) {
        if ($PSVersionTable.PSVersion.Major -lt 6 -AND $GLOBAL_IGNORE_CERTIFICATES) {
            <# Disable Certificate checking for WebRequest (Pre-PowerShell 6.0) #>
            Disable-SslVerification
            $request = Invoke-RestMethod -Uri $GLOBAL_LINA_SERVER$Path -SessionVariable Currentsession
        } elseif ($GLOBAL_IGNORE_CERTIFICATES) {
            <# Disable Certificate checking for WebRequest (PowerShell >= 6.0) #>
            $request = Invoke-RestMethod -Uri $GLOBAL_LINA_SERVER$Path -SessionVariable Currentsession -SkipCertificateCheck
        }else {
            # Certificate check is enabled
            $request = Invoke-RestMethod -Uri $GLOBAL_LINA_SERVER$Path -SessionVariable Currentsession
        }
        Set-Variable -name LoggedSession -Scope global -Value $Currentsession

    } else {
        # Next connections reuse the Session Cookie set globally
        if ($PSVersionTable.PSVersion.Major -ge 6 -AND $GLOBAL_IGNORE_CERTIFICATES) {
            <# Disable Certificate checking for WebRequest (PowerShell >= 6.0) #>
            $request = Invoke-RestMethod -Uri $GLOBAL_LINA_SERVER$Path -ContentType $ContentType -Method "Post" -Body $Body -WebSession $LoggedSession -SkipCertificateCheck
        }else {
            # Same request if enabled or not. Checkingt is disabled globally on PowerShell > 6.0
            $request = Invoke-RestMethod -Uri $GLOBAL_LINA_SERVER$Path -ContentType $ContentType -Method "Post" -Body $Body -WebSession $LoggedSession
        }
    }
    Return $request
}
function LinaToLocalTime ($lina_time) { 
    <# Lina Times are UTC based ? Not GMT ?#>
    $date=(Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($lina_time/1000))
    $oFromTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById("UTC")
    $oToTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById([System.TimeZoneInfo]::Local.Id)
    $utc = [System.TimeZoneInfo]::ConvertTimeToUtc($date, $oFromTimeZone)
    $newTime = [System.TimeZoneInfo]::ConvertTime($utc,$oToTimeZone)
    return $newTime
}

function InitTranslations() {
    Param(
        [Parameter(Mandatory=$True,Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$Lang
    )   
    $request = CallAPI "/Admin/locale/$lang.js"
    # Web request does not like the encoding on this one !
    $temp_utf = [System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding(28591).GetBytes($request.ToString()))
    $temp_split = $temp_utf -split '\n'
    $lines = ($temp_split | Select-String -Pattern "SERVER_NAME_","UNCAT_AGENTS_LABEL" ).line
    $translations = @{}
    foreach ($line in $lines) {
        $splitted = $line -split ': "'
        $key = $splitted[0].Trim().Replace('SERVER_NAME_','').Replace("__","_")
        $value = $splitted[1].Replace('",','').Trim()
        $translations.add($key,$value)
    }
    Set-Variable -name LINA_TRANSLATIONS -Scope global -Value $translations
}

function Translate() {
    Param(
        [Parameter(Mandatory=$True,Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$ToTranslate
    )

    $ToTranslate = $ToTranslate.TrimStart("_").TrimEnd("_")

    if ($ToTranslate -eq "UNCAT") { $ToTranslate = "UNCAT_AGENTS_LABEL"; }
    $translated = $LINA_TRANSLATIONS[$ToTranslate.Replace("__","_")]


    if ($translated) {
        return $translated
    }else {
        # No translation available. Use original text.
        return $ToTranslate
    }
}


function LinaTimestamp {
    return [math]::Round((New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds*1000)
}
function Connect-LinaServer {
    [cmdletbinding()]
    Param(
        [Parameter(ParameterSetName="Server",Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$Server,
        [Parameter(ParameterSetName="Server",Position=1)]
        [ValidateNotNullOrEmpty()]
        [string]$User,
        [Parameter(ParameterSetName="Server",Position=2)]
        [ValidateNotNullOrEmpty()]
        [string]$Password,
        [Parameter(Mandatory=$false,ParameterSetName="Server",Position=3)]
        [ValidateSet("en","fr","es","de")] 
        [string]$Locale="en",        
        [Parameter(Mandatory=$false,ParameterSetName="Server",Position=4)]
        [ValidateNotNullOrEmpty()]
        [string]$Tenant
    )

    Set-Variable -name GLOBAL_LINA_SERVER -Scope global -Value $Server
    $userenc=[System.Web.HttpUtility]::UrlEncode($User)
    $passenc=[System.Web.HttpUtility]::UrlEncode($Password)
    Write-Output "Connecting to Lina server $GLOBAL_LINA_SERVER"
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADE/login.html?user=$userenc&password=$passenc" -SessionVariable Currentsession
    #Set-Variable -name LoggedSession -Scope global -Value $Currentsession
    $request = CallAPI -Path "/ADE/login.html?user=$userenc&password=$passenc" -FirstConnection
    if ([string]$request -like "*- OK*") {
        InitTranslations($Locale)
        Write-Output "Successfully connected."
    } else {
        Write-Output "Error occurred trying to connect : \$request\"
    }    
}

function Disconnect-LinaServer {
    Write-Output "Disconnecting from Lina server $GLOBAL_LINA_SERVER"
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADE/logout.json" -WebSession $LoggedSession
    $request = CallAPI -Path "/ADE/logout.json"
    if ([string]$request -like "*- OK*") {
        Write-Output "Successfully disconnected."
    } else {
        Write-Output "Error occurred trying to disconnect : \$request\"
    }
}

function Get-LinaGlobalStats {
    Write-Output "Getting global stats"
    $request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/info.xml" -ContentType "application/xml" -WebSession $LoggedSession
    $request = CallAPI -Path "/info.xml"
    $stats = ([xml]$request).infolist
    $LinaStats = [PSCustomObject]@{
        PSTypeName                  = 'LinaStats'
        ALNVersion                  = $stats.aln_version
        PercentDiskUse              = $stats.disk_use
        DedupRatio                  = $stats.dedup_ratio
        DiskAvailableGB             = [math]::Round(($stats.disk_avail)/(1024*1024*1024),2)

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

        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 {
    [cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        [Parameter(ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName="ByID")]
        [ValidateRange(0,2147483647)]
        [int]$ID
    )
    Write-Output "Getting list of agents"
    $timestamp = LinaTimestamp
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/lst_clients.xml?timestamp=$timestamp&type=agent" -ContentType "application/xml" -WebSession $LoggedSession
    $request = CallAPI -Path "/lst_clients.xml?timestamp=$timestamp&type=agent"
    $Items = ([xml]$request).HNConfig.ClientArray.Client
    $Tenants = Get-LinaTenant
    $LinaItems = @()
    foreach ($Item in $Items) {
        <# Filtering on ID or Name (only if provided) #>
        if ((!$Name -AND !$ID) -OR ( $Item.Name -like "$Name" -OR  $Item.ID -eq $ID)) {
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName                  = 'LinaAgent'
                Name                        = $Item.Name
                ID                          = $Item.ID
                Tenant                      = $Tenants | where-object {$_.TenantID -eq $Item.DomainID} | Select-Object -ExpandProperty Name
                AgentGroup                  = Translate($Item.AttachementArray.Attachement.Group.Name)
                Strategy                    = Translate($Item.ServiceProfile.Name)
                Protection                  = Translate($Item.DataProfile.Name)

                StrategyName                = $Item.ServiceProfile.Name
                ProtectionName              = $Item.DataProfile.Name

                TenantID                    = $Item.DomainID
                AgentGroupID                = $Item.AttachementArray.Attachement.Group.ID
                StrategyID                  = $Item.ServiceProfile.ID
                ProtectionID                = $Item.DataProfile.ID
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    Return $LinaItems
}

function Get-LinaStrategy {
    [cmdletbinding()]
    Param(
        [Parameter(ParameterSetName="Name")]
        [ValidateNotNullOrEmpty()]
        [string]$Name
    )    
    Write-Output "Getting list of strategies"
    $timestamp = LinaTimestamp
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/lst_serviceprofiles.xml?timestamp=$timestamp" -ContentType "application/xml" -WebSession $LoggedSession
    $request = CallAPI -Path "/lst_serviceprofiles.xml?timestamp=$timestamp"
    $Items = ([xml]$request).HNConfig.ServiceProfileArray.ServiceProfile
    $LinaItems = @()
    foreach ($Item in $Items) {
        if (!$Name -OR $Item.name -like "$Name") {        
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName                  = 'LinaStrategy'
                Label                       = Translate($Item.Name)
                ID                          = $Item.ID
                Name                        = $Item.Name
                RPOInMinutes                = ($Item.ParamSchedule/60)
                RetentionInDays             = $Item.ParamDataAging
                AlertAfterDays              = ($Item.ParamAlertTime/(24*3600))
                ThroughputLimitKBps         = $Item.ParamThroughputLimit
                ReplicationTargets          = $Item.RepliTarget.ID
                Encryption                  = [bool]$Item.ParamEncryptionActivated
                WanMode                     = [bool]$Item.ParamWanActivated
                CompressionAlgo             = $Item.ParamCompression
                AllowClientRPO              = [bool]$Item.ParamAllowClientRPO
                AllowClientRules            = [bool]$Item.ParamAllowClientRules
                AllowClientPause            = [bool]$Item.ParamAllowClientPause
                AllowClientBoost            = [bool]$Item.ParamAllowClientBoost
                AllowClientNetworkParams    = [bool]$Item.ParamAllowClientNetworkParams
                AllowWebAccess              = [bool]$Item.ParamAllowWebAccess
                QuotaMaxProtSizeMB          = [math]::Round(($Item.ParamQuotaMaxProtSize)/(1024*1024))
                QuotaMaxProtObjs            = $Item.ParamQuotaMaxProtObjs
                QuotaMaxHistSizeMB          = [math]::Round(($Item.ParamQuotaMaxHistSize)/(1024*1024))
                QuotaMaxHistObjs            = $Item.ParamQuotaMaxHistObjs
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    Return $LinaItems
}

function Get-LinaTenant {
    [cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        [Parameter(ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName="ByID")]
        [ValidateNotNullOrEmpty()]
        [int]$ID
    )
    Write-Output "Getting list of tenants"
    $timestamp = LinaTimestamp
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADM/list_domain.json?timestamp=$timestamp" -ContentType "application/json" -WebSession $LoggedSession
    $request = CallAPI -Path "/ADM/list_domain.json?timestamp=$timestamp"
    $Items = $request.domains
    $LinaItems = @()
    foreach ($Item in $Items) {
        if ((!$Name -AND !$ID) -OR $Item.name -like "$Name" -OR $Item.ID -eq $ID ) {
            $CurrentLinaItem = [PSCustomObject]@{
                PSTypeName                  = 'LinaTenant'
                TenantID                    = $Item.id
                UUID                        = $Item.uuid
                Name                        = $Item.name
                Comment                     = $Item.comment
                IsDefault                   = [bool]$Item.def_domain
            }
            $LinaItems += $CurrentLinaItem
        }
        
    }
    Return $LinaItems
}

function Get-LinaAgentStats {
    [cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        [Parameter(ValueFromPipeline)]
        [pscustomobject]$lina_agent,
        [Parameter(ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName="ByID")]
        [ValidateRange(0,2147483647)]
        [int]$ID
    )
    Write-Output "Getting agents Statistics (only available if has been online)"
    $timestamp = LinaTimestamp
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/stats_clients.xml?timestamp=$timestamp" -ContentType "application/xml" -WebSession $LoggedSession
    $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                  = 'LinaAgentInfos'
                Name                        = $Item.AdminName
                ID                          = $Item.AdminID              
                ComputerName                = $Item.ComputerName
                System                      = $Item.System
                AgentVersion                = $Item.AgentVersion
                Strategy                    = Translate($Item.AdminServiceProfileName)
                Protection                  = Translate($Item.AdminDataProfileName)
                LastLogon                   = $Item.LastLogon
                Alert                       = $Item.Alert

                LastStartedSession          = LinaToLocalTime $Item.LastStartedSession
                LastCompletedSession        = LinaToLocalTime $Item.LastCompletedSession
                LastConnectionTime          = LinaToLocalTime $Item.LastConnectionTime
                LastSyncTime                = LinaToLocalTime $Item.LastSyncTime
                
                StrategyAdminName           = $Item.AdminServiceProfileName
                ProtectionAdminName         = $Item.AdminDataProfileName
            }
            $LinaItems += $CurrentLinaItem
        }
        
    }
    Return $LinaItems
}


function New-LinaAgent {
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,ParameterSetName="Name")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(Mandatory=$false,ParameterSetName="Name")]
        [ValidateNotNullOrEmpty()]
        [string]$TenantName        
    )
    Write-Output "Creating a Lina agent named $Name"
    $current_tenant = Get-LinaCurrentTenant 6>$null
    if (!$TenantName) {
        if (!$current_tenant -OR $current_tenant.TenantID -le 1) {
            # No current tenant (global view) => using default tenant
            $domain =  Get-LinaTenant 6>$null | Where-Object {$_.IsDefault} 
            $domain_id=[int]$domain.TenantID
            $domain_name=[string]$domain.Name
            Write-Output "No tenant selected, agent will be created in default tenant $domain_name (ID $domain_id)"
        } else {
            # Using Current tenant
            $domain =  Get-LinaCurrentTenant 6>$null
            $domain_id=[int]$domain.TenantID
            $domain_name=[string]$domain.Name            
            Write-Output "No tenant selected, agent will be created in current tenant $domain_name (ID $domain_id)"
        }
    }else {
        $domain =  Get-LinaTenant 6>$null | Where-Object {$_.Name -eq $TenantName} 
        $domain_id=[int]$domain.TenantID
        $domain_name=[string]$domain.Name
        if ( !($domain_id -gt 0) ) {
            Write-Output "Error : No tenant found with name $TenantName. Please input the exact name of the Tenant"
            Return
        }
    }
    
    #Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADM/domain_set_current.json?domain_id=$domain_id" -ContentType "application/json" -WebSession $LoggedSession | Out-Null
    #CallAPI -Path "/ADM/domain_set_current.json?domain_id=$domain_id"
    Set-LinaCurrentTenant -ID $domain_id | Out-Null 

    $body = 'data=<?xml version="1.0" encoding="UTF-8"?><HNConfig><Func>ADD</Func><Client><Name>'+$Name+'</Name></Client></HNConfig>'
    #$request = Invoke-WebRequest -Uri "$GLOBAL_LINA_SERVER/mng_client.html" -Method "POST" -ContentType "application/xml" -Body $body -WebSession $LoggedSession
    $request = CallAPI -Path "/mng_client.html" -ContentType "application/xml" -Body $body
    
    # Setting back the current tenant to what it was before the New-LinaAgent command
    $current_tenant | Set-LinaCurrentTenant | Out-Null
    if ([string]$request -like "*[0]*") {
        Write-Output "Agent $Name successfully created."
        $agent_created = Get-LinaAgent -Name $Name | Out-Null
        Return $agent_created
    } else {
        Write-Output "Error occurred trying to create agent $Name : \$request\"
        Return $null
    }    
}
function Get-LinaCurrentTenant {
    Write-Output "Getting current tenant"
    $timestamp = LinaTimestamp
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADE/check_session.xml?timestamp=$timestamp" -ContentType "application/xml" -WebSession $LoggedSession
    $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) {
        Write-Output "No current tenant (ID = -1 or 1). Global view on all tenants."
        Return $current_tenant_id
    }elseif ($current_tenant_id -gt 1) {
        Write-Output "Current tenant ID is $current_tenant_id"
        $current_tenant = Get-LinaTenant -ID $current_tenant_id
        Return $current_tenant
    } else {
        Write-Output "Error occurred trying to get current tenant : \$request\"
        Return $null
    }
}
function Set-LinaCurrentTenant {
    [cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        [Parameter(ValueFromPipeline,ParameterSetName="ByObject")]
        [pscustomobject]$lina_tenant,
        [Parameter(Mandatory=$true,ParameterSetName="ByID")]
        [ValidateNotNullOrEmpty()]
        [string]$ID,
        [Parameter(Mandatory=$false,ParameterSetName="All")]
        [ValidateNotNullOrEmpty()]
        [switch]$All        
    )
    
    # All tenants is 1 or -1 (no tenant selected, global view)
    if ($All) {
        $ID=1
    }elseif ($lina_tenant -AND $lina_tenant.TenantID -ge 1) {
        $ID=$lina_tenant.TenantID
    }elseif (!$ID) {
        $ID=1
    }
    Write-Output "Setting current tenant to Tenant ID $ID"
    #$request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADM/domain_set_current.json?domain_id=$ID" -ContentType "application/json" -WebSession $LoggedSession
    $request = CallAPI -Path "/ADM/domain_set_current.json?domain_id=$ID"
    if ($request.status -eq 0) {
        Write-Output "Current tenant has been set to tenant ID $ID"
        Return
    } else {
        Write-Output "Error occurred trying to set current tenant : \$request\"
        Return
    }
}


function Remove-LinaAgent {
<#
.SYNOPSIS
Deletes a Lina Agent from a Lina Server.
.DESCRIPTION
Deletes a Lina Agent. Unique data will be reclaimed automatically by server after some time (configurable).
.INPUTS
Accept pipelining of LinaAgent objects (from Get-LinaAgent for example)
.PARAMETER Name
Name of the agent to delete. Wildcards are accepted (don't forget to enable Bulk mode for actions on multiple agents).
.PARAMETER WhatIf
No actual deletion will happen if set. It will only display what agents would be deleted.
Sometimes also called "Dry Run mode"
.PARAMETER Bulk
Security parameter to enable deletion of multiple agents. If not set only one agent will be deleted.
.EXAMPLE
Remove-LinaAgent -Name "AGENT132"
Real deletion of a single agent by name
.EXAMPLE
Remove-LinaAgent -Name "AGENT1*" -Bulk -WhatIf
Simulates deletion of a multiple agents by name (WhatIf mode)
.EXAMPLE
Remove-LinaAgent -Name "AGENT1*" -Bulk
Real deletion of a multiple agents by name
.EXAMPLE
Get-LinaAgent -ID 164 | Remove-LinaAgent -WhatIf
Real deletion of a single agent by piping it from a Get
.EXAMPLE
Get-LinaAgent -Name "TEST1*" | Remove-LinaAgent -Bulk -WhatIf
Simulates deletion of multiple agents by piping them from a Get (WhatIf mode)
#>

    [cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        [Parameter(ValueFromPipeline=$True,ParameterSetName="ByPipeline")]
        [pscustomobject[]]$LinaAgents,

        [Parameter(Mandatory=$True,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$AgentName,

        # Do not delete, only show will be done
        [Parameter(Mandatory=$False,ParameterSetName="ByPipeline")]
        [Parameter(Mandatory=$False,ParameterSetName="ByName")]
        [switch]$WhatIf,

        # Enable deleting multiple agents
        [Parameter(Mandatory=$False,ParameterSetName="ByPipeline")]
        [Parameter(Mandatory=$False,ParameterSetName="ByName")]        
        [switch]$Bulk
    )
    BEGIN {}
    PROCESS {
        $nb_of_agents_deleted=0

        if (!$LinaAgents) { 
            # Agents not pipelined => populate using name argument
            $LinaAgents = Get-LinaAgent -Name $AgentName 6>$null
            if (!$LinaAgents) {
                # No agent found by name
                Write-Output "WARNING : No agent found with this name."
                return
            }
                    # We are sure that we have some agents so we continue
            $names=$LinaAgents.Name
            Write-Output "Deleting Lina agent(s) : $names"
        }

        foreach ($lina_agent in $LinaAgents) {
            # I don't know why but sometimes we go in foreach but element is empty ?!
            If(!$lina_agent.ID) { return }
            if ($nb_of_agents_deleted -ge 1 -AND !$Bulk) {
                Write-Output "WARNING : Bulk mode has not been enabled, only one agent will be deleted for security."
                return
            }
            $Name = $lina_agent.Name
            $delete_id = $lina_agent.ID
            
            if (!$delete_id) {
                Write-Output "WARNING : No agent found with this name."
                return
            }else {
                $body = 'data=<?xml version="1.0" encoding="UTF-8"?><HNConfig><Func>DEL</Func><Client><ID>'+$delete_id+'</ID></Client></HNConfig>'
                if (!$WhatIf) {
                    #$request = Invoke-WebRequest -Uri "$GLOBAL_LINA_SERVER/mng_client.html" -Method "POST" -ContentType "application/xml" -Body $body -WebSession $LoggedSession
                    $request = CallAPI -Path "/mng_client.html" -ContentType "application/xml" -Body $body 
                }else {
                    # WhatIf mode enabled => does not delete agent
                    $request = "WHATIF"
                }
                if ([string]$request -like "*[0]*") {
                    Write-Output "Agent $Name successfully deleted."
                } elseif ($request -eq "WHATIF") {
                    Write-Output "Agent $Name will be deleted if not using 'WhatIf' mode"
                }else {
                    Write-Output "Error occurred trying to delete agent $Name : \$request\"
                }
            }
            $nb_of_agents_deleted +=1
 
        }

    }
    END {}

}

function Set-LinaAgent {
    [cmdletbinding()]
    Param(
        [Parameter(ParameterSetName="UpdateName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName="UpdateName")]
        [ValidateNotNullOrEmpty()]
        [string]$Newname            
    )
    Write-Output "Renaming Lina agent named $Name to new name $Newname"
    $Items = Get-LinaAgent
    foreach ($Item in $Items) {
        if ($Item.Name -eq $Name) {
            $rename_id=$Item.ID
            Write-Output "Found agent named $Name with ID $rename_id"
        }
    }
    if (!$rename_id) {
        Write-Output "WARNING : No agent found with this name."
        return
    }else {
        $body = 'data=<?xml version="1.0" encoding="UTF-8"?><HNConfig><Func>REN</Func><Client><ID>'+$rename_id+'</ID><Name>'+$Newname+'</Name></Client></HNConfig>'
        $timestamp = LinaTimestamp
        #$request = Invoke-WebRequest -Uri "$GLOBAL_LINA_SERVER/mng_client.html?timestamp=$timestamp" -Method "POST" -ContentType "application/xml" -Body $body -WebSession $LoggedSession
        $request = CallAPI -Path "/mng_client.html?timestamp=$timestamp" -ContentType "application/xml" -Body $body
        if ([string]$request -like "*[0]*") {
            Write-Output "Agent $Name successfully renamed to $Newname."
            Return
        } else {
            Write-Output "Error occurred trying to delete agent $Name : \$request\"
            Return
        }
    }
}