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 New-Lina Agent => use current tenant if not set Add an option for mass delete of agents and/or improve multiple objects in pipeline Set Silent returns in imbricated functions (see in New-LinaAgent for example) 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_SKIP_CERT = "" <# Disable Certificate checking for WebRequest (Pre-PowerShell 6.0) #> add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" <# Disable Certificate checking for WebRequest (PowerShell >= 6.0) #> if ($PSVersionTable.PSVersion.Major -ge 6) { $GLOBAL_SKIP_CERT = "-SkipCertificateCheck" } else { $GLOBAL_SKIP_CERT = "" } 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 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 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 $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 $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 $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 $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 $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 $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 $going_back = $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 } } } |