Atempo.Lina.psm1

<#
 .Synopsis
  This Windows PowerShell module contains PowerCLI Cloud Infrastructure Suite cmdlets.
 
 .Description
  Provide basic management of Lina Agents
 
 .Example
    # Getting list of agents
    Connect-LinaServer -Server "https://10.0.0.1:8181" -User "superadmin" -Password "MyPassword"
    Get-LinaAgent
    Disconnect-LinaServer
#>



<# TODO
    manage $Body in CallAPI
    Get locales for default stragies names (locale/en.js for example)
    Ability to pipe commands
    Improved error reporting
#>


<# 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: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()]
        [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 -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 -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 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)]
        [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-Host "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*") {
        Write-Host "Successfully connected."
    } else {
        Write-Host "Error occurred trying to connect : \$request\"
    }    
}

function Disconnect-LinaServer {
    Write-Host "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-Host "Successfully disconnected."
    } else {
        Write-Host "Error occurred trying to disconnect : \$request\"
    }
}

function Get-LinaGlobalStats {
    Write-Host "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-Host "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
    $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
                TenantID                    = $Item.DomainID
                Strategy                    = $Item.ServiceProfile.Name
                Protection                  = $Item.DataProfile.Name         
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    Return $LinaItems
}

function Get-LinaStrategy {
    [cmdletbinding()]
    Param(
        [Parameter(ParameterSetName="Name")]
        [ValidateNotNullOrEmpty()]
        [string]$Name
    )    
    Write-Host "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'
                ID                          = $Item.ID
                Name                        = $Item.Name
                RPOInMinutes                = ($Item.ParamSchedule/60)
                RetentionInDays             = $Item.ParamDataAging
            }
            $LinaItems += $CurrentLinaItem
        }
    }
    Return $LinaItems
}

function Get-LinaTenant {
    [cmdletbinding(DefaultParameterSetName="ByName")]
    Param(
        [Parameter(ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName="ByID")]
        [ValidateNotNullOrEmpty()]
        [int]$ID
    )
    Write-Host "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-Host "Getting agents info"
    $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                    = $Item.AdminServiceProfileName
                Protection                  = $Item.AdminDataProfileName
                LastLogon                   = $Item.LastLogon
                Alert                       = $Item.Alert
                LastStartedSession          = LinaToLocalTime $Item.LastStartedSession
                LastCompletedSession        = LinaToLocalTime $Item.LastCompletedSession
                LastConnectionTime          = LinaToLocalTime $Item.LastConnectionTime
                LastSyncTime                = LinaToLocalTime $Item.LastSyncTime           
            }
            $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-Host "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-Host "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-Host "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-Host "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" | 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

    # Setting back the current tenant to what it was before the New-LinaAgent command
    $current_tenant | Set-LinaCurrentTenant 6>$null 
    if ([string]$request -like "*[0]*") {
        Write-Host "Agent $Name successfully created."
        Return Get-LinaAgent -Name $Name
    } else {
        Write-Host "Error occurred trying to create agent $Name : \$request\"
        Return $null
    }    
}
function Get-LinaCurrentTenant {
    Write-Host "Getting current tenant"
    $timestamp = LinaTimestamp
    $request = Invoke-RestMethod -Uri "$GLOBAL_LINA_SERVER/ADE/check_session.xml?timestamp=$timestamp" -ContentType "application/xml" -WebSession $LoggedSession
    $current_tenant_id = [int](([xml]$request).session.effective_domain_id)
    if ($current_tenant_id -eq -1 -OR $current_tenant_id -eq 1) {
        Write-Host "No current tenant (ID = -1 or 1). Global view on all tenants."
        Return $current_tenant_id
    }elseif ($current_tenant_id -gt 1) {
        Write-Host "Current tenant ID is $current_tenant_id"
        Return Get-LinaTenant -ID $current_tenant_id
    } else {
        Write-Host "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-Host "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
    if ($request.status -eq 0) {
        Write-Host "Current tenant has been set to tenant ID $ID"
        Return
    } else {
        Write-Host "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()]
    Param(
        [Parameter(ValueFromPipeline=$True,ParameterSetName="ByPipeline")]
        [pscustomobject[]]$LinaAgents,

        [Parameter(ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        # 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 {
        if (!$LinaAgents) { 
            $LinaAgents = Get-LinaAgent -Name $Name 6>$null
        }
        $names=$LinaAgents.Name
        Write-Host "Deleting Lina agent(s) : $names"}
    PROCESS {
        $nb_of_agents_deleted=0
        <#
        if (!$LinaAgents) {
            $LinaAgents = Get-LinaAgent -Name $Name 6>$null
        }#>

         
        foreach ($lina_agent in $LinaAgents) {
           
            $Name = $lina_agent.Name
            $delete_id = $lina_agent.ID
            
            
            if (!$delete_id) {
                Write-Host "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
                }else {
                    # WhatIf mode enabled => does not delete agent
                    $request = "WHATIF"
                }
                if ([string]$request -like "*[0]*") {
                    Write-Host "Agent $Name successfully deleted."
                } elseif ($request -eq "WHATIF") {
                    Write-Host "Agent $Name will be deleted if not using 'WhatIf' mode"
                }else {
                    Write-Host "Error occurred trying to delete agent $Name : \$request\"
                }
            }
            $nb_of_agents_deleted +=1
            if ($nb_of_agents_deleted -ge 1 -AND !$Bulk) {
                Write-Host "WARNING : Bulk mode has not been enabled, only one agent will be deleted for security."
                Return
            }
        }
    }
    END {}

}

function Set-LinaAgent {
    [cmdletbinding()]
    Param(
        [Parameter(ParameterSetName="UpdateName")]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
        [Parameter(ParameterSetName="UpdateName")]
        [ValidateNotNullOrEmpty()]
        [string]$Newname            
    )
    Write-Host "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-Host "Found agent named $Name with ID $rename_id"
        }
    }
    if (!$rename_id) {
        Write-Host "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
        if ([string]$request -like "*[0]*") {
            Write-Host "Agent $Name successfully renamed to $Newname."
            Return
        } else {
            Write-Host "Error occurred trying to delete agent $Name : \$request\"
            Return
        }
    }
}