CoveBackupApi.psm1
#Region './Private/Convert-CoveUnixTime.ps1' -1 function Convert-CoveUnixTime { <# .SYNOPSIS A helper functions used to convert unix timestamps to or from DateTime objects .DESCRIPTION The Cove API provides timestamps in unix format, this function converts them to DateTime objects .EXAMPLE Convert-CoveUnixTime -UnixTime 1685522071 Converts the unix timestamp 1685522071 to a DateTime object .OUTPUTS System.DateTime or System.Int32 unix timestamp #> [CmdletBinding()] param ( # one of either the UnixTime or DateTime parameters must be specified [Parameter(Mandatory, ParameterSetName = 'UnixTime')] # The unix timestamp to convert [Parameter()] [int]$UnixTime, [Parameter(Mandatory, ParameterSetName = 'DateTime')] # The DateTime object to convert [Parameter()] [datetime]$DateTime ) begin { } process { $Epoch = New-Object DateTime 1970, 1, 1, 0, 0, 0, ([DateTimeKind]::Utc) if ($UnixTime) { return $Epoch.AddSeconds($UnixTime) } elseif ($DateTime) { return ($DateTime - $Epoch).TotalSeconds } } end { } } #EndRegion './Private/Convert-CoveUnixTime.ps1' 48 #Region './Private/Get-CoveBackupStatusMap.ps1' -1 function Get-CoveBackupStatusMap { <# .SYNOPSIS Gets the status descriptions for the numeric values returned from the Cove API .DESCRIPTION Returns objects with the status descriptions for the numeric values returned from the Cove API .PARAMETER FieldName The field name to return the key for .EXAMPLE Get-CoveBackupStatusMap Gets the full map .EXAMPLE Get-CoveBackupStatusMap -FieldName 'In Progress' Returns the numeric value for the status label 'In Progress' > 1 .OUTPUTS System.Collections.Hashtable #> [CmdletBinding()] param ( # Get the column header for a specific field name [Parameter()] [string] $FieldName ) begin { } process { $DataMap = @{ 1 = 'In Progress' 2 = 'Failed' 3 = 'Aborted' 5 = 'Completed' 6 = 'Interrupted' 7 = 'Not Started' 8 = 'Completed With Errors' 9 = 'In Progress With Faults' 10 = 'Over Quota' 11 = 'No Selection' 12 = 'Restarted' } if ($FieldName) { try { $NumericValue = $DataMap.GetEnumerator() | Where-Object { $_.Value -like $FieldName } | Select-Object -ExpandProperty Key return $NumericValue } catch { Write-Warning "Failed to find a column header for $FieldName" return $null } } return $DataMap } end { } } #EndRegion './Private/Get-CoveBackupStatusMap.ps1' 65 #Region './Private/Get-CoveDataMap.ps1' -1 function Get-CoveDataMap { <# .SYNOPSIS Gets the data maps for the Cove API .DESCRIPTION Returns objects with the data map for the Cove API given the parameter passed .PARAMETER DataMap The data map to return .PARAMETER FieldName The field name to return the column ID for .EXAMPLE Get-CoveDataMap Gets the full data map .EXAMPLE Get-CoveDataMap -DataMap DataSources Gets the backup data source types .EXAMPLE Get-CoveDataMap -DataMap ColumnHeaders Gets the column headers returned from the API .EXAMPLE Get-CoveDataMap -FieldName 'Hyper-V' Returns the column ID for the Hyper-V field (D14) .OUTPUTS System.Collections.Hashtable #> [CmdletBinding()] param ( # The data map to return [Parameter()] [ValidateSet('DataSources','ColumnHeaders','StatsFields')] [string]$DataMap, # Get the column header for a specific field name [Parameter()] [string] $FieldName ) begin { } process { $FullMap = @{ D01 = 'Files and Folders' D02 = 'System State' D03 = 'MsSql' D04 = 'VssExchange' D05 = 'Microsoft 365 SharePoint' D06 = 'NetworkShares' D07 = 'VssSystemState' D08 = 'VMware Virtual Machines' D09 = 'Total' D10 = 'VssMsSql' D11 = 'VssSharePoint' D12 = 'Oracle' D14 = 'Hyper-V' D15 = 'MySql' D16 = 'Virtual Disaster Recovery' D17 = 'Bare Metal Restore' D19 = 'Microsoft 365 Exchange' D20 = 'Microsoft 365 OneDrive' D23 = 'Microsoft 365 Teams' F00 = 'Last Session Status' # 1 - In process, 2 - Failed, 3 - Aborted, 5 - Completed, 6 - Interrupted, 7 - NotStarted, 8 - CompletedWithErrors, 9 - InProgressWithFaults, 10 - OverQuota, 11 - NoSelection, 12 - Restarted F01 = 'Last Session Selected Count' F02 = 'Last Session Processed Count' F03 = 'Last Session Selected Size' F04 = 'Last Session Processed Size' F05 = 'Last Session Sent Size' F06 = 'Last Session Errors Count' F07 = 'Protected size' F08 = 'Color bar - last 28 days' F09 = 'Last successful session Timestamp' F10 = 'Pre Recent Session Selected Count' F11 = 'Pre Recent Session Selected Size' F12 = 'Session duration' F13 = 'Last Session License Items count' F14 = 'Retention' F15 = 'Last Session Timestamp' F16 = 'Last Successful Session Status' F17 = 'Last Completed Session Status' F18 = 'Last Completed Session Timestamp' F19 = 'Last Session Verification Data' F20 = 'Last Session User Mailboxes Count' F21 = 'Last Session Shared Mailboxes Count' I0 = 'Device ID' I1 = 'Device name' I2 = 'Device name alias' I3 = 'Password' I4 = 'Creation date' I5 = 'Expiration date' I6 = 'Timestamp' # time I8 = 'Customer' I9 = 'Product ID' I10 = 'Product' I11 = 'Storage location' I12 = 'Device group name' I13 = 'Own user name' I14 = 'Used storage' I15 = 'Email' I16 = 'OS version' I17 = 'Client version' I18 = 'Computer name' I19 = 'Internal IPs' I20 = 'External IPs' I21 = 'MAC address' I22 = 'Dashboard frequency' I23 = 'Dashboard language' I24 = 'Time offset' I26 = 'Cabinet Storage Efficiency' I27 = 'Total Cabinets Count' I28 = 'Efficient Cabinet Count 0-25' I29 = 'Efficient Cabinet Count 26-50' I30 = 'Efficient Cabinet Count 50-75' I31 = 'Used Virtual Storage' I32 = 'OS type' # 1 - workstation, 2 - server, 0 - undefined I33 = 'Seeding mode' # 0 - Undefined, 1 - Normal, 2 - Seeding, 3 - PreSeeding, 4 - PostSeeding I34 = 'Anti Crypto enabled' I35 = 'LSV' # 0 - Disabled, 1 - Enabled I36 = 'Storage status' # 2 - Offline, 1 - Failed, 0 - Undefined, 50 - Running, 100 - Synchronized I37 = 'LSV status' # 2 - Offline, 1 - Failed, 0 - Undefined, 50 - Running, 100 - Synchronized I38 = 'Archived size' I39 = 'Retention units' I40 = 'Activity description' I41 = 'Number of Hyper-V virtual machines' I42 = 'Number of ESX virtual machines' I43 = 'Encryption status' I44 = 'Computer manufacturer' I45 = 'Computer model' I46 = 'Installation ID' I47 = 'Installation Mode' I48 = 'Restore email' I49 = 'Restore dashboard frequency' I50 = 'Restore dashboards language' I54 = 'Profile ID' I55 = 'Profile version' I56 = 'Profile' I57 = 'Stock Keeping Unit' I58 = 'Stock Keeping Unit of the previous month' I59 = 'Account type' I60 = 'Proxy Type' I62 = 'Most Recent Restore Plugin' I63 = 'Company Name' I64 = 'Address' I65 = 'Zip Code' I66 = 'Country' I67 = 'City' I68 = 'Phone Number' I69 = 'Fax Number' I70 = 'Contract Name' I71 = 'Group Name' I72 = 'Demo' I73 = 'Edu' I74 = 'Unattended Installation account ID' I75 = 'First Installation Flag' I76 = 'Maximum Allowed Version' I77 = 'Customer reference' I78 = 'Active data sources' I80 = 'Recovery Testing' I81 = 'Physicality' I82 = 'Passphrase' } if ($FieldName) { try { $ColumnHeaders = $FullMap.GetEnumerator() | Where-Object { $_.Value -like $FieldName } | Select-Object -ExpandProperty Key return $ColumnHeaders } catch { Write-Error "Failed to find a column header for $FieldName" return $null } } if ($DataMap -eq 'DataSources') { $Map = $FullMap.GetEnumerator() | Where-Object { $_.Name -like 'D*' } } if ($DataMap -eq 'StatsFields') { $Map = $FullMap.GetEnumerator() | Where-Object { $_.Name -like 'F*' } } if ($DataMap -eq 'ColumnHeaders') { $Map = $FullMap.GetEnumerator() | Where-Object { $_.Name -like 'I*' } } if (!$DataMap) { $Map = $FullMap } return $Map | Sort-Object -Property Value } end { } } #EndRegion './Private/Get-CoveDataMap.ps1' 197 #Region './Private/Get-CoveUnixTimeFields.ps1' -1 function Get-CoveUnixTimeFields { <# .SYNOPSIS Gets the Unix fields for the Cove API .DESCRIPTION Gets the Unix fields for the Cove API .EXAMPLE Get-CoveUnixFields -Verbose Returns the Unix fields for the Cove API .OUTPUTS System.Object[] #> [CmdletBinding()] [OutputType([System.Object[]])] param ( ) begin { } process { $UnixTimeFields = @( 'CreationTime', 'ExpirationTime', 'TrialExpirationTime', 'TrialRegistrationTime', 'Timestamp', 'I6', 'Expiration date', 'I5', 'Creation date', 'I4', 'F09', # Last successful session timestamp 'F15', # Last session timestamp 'F18' # Last completed session timestamp ) return $UnixTimeFields } end { } } #EndRegion './Private/Get-CoveUnixTimeFields.ps1' 47 #Region './Private/Invoke-CoveApiRequest.ps1' -1 function Invoke-CoveApiRequest { <# .SYNOPSIS Performs a request to the Cove API .DESCRIPTION A private function, will invoke a request to the Cove API when used within the CoveBackupApi module .EXAMPLE $params = @{ CoveMethod = 'EnumeratePartners' Params = @{ parentPartnerId = 123456 fields = @(0,1,3,4,5,8,9,10,18,20) fetchRecursively = $true } Id = 'jsonrpc' } $CoveCompanies = Invoke-CoveApiRequest @params Gets all companies from the Cove API where the Partner ID is 123456 .OUTPUTS System.Management.Automation.PSCustomObject #> [CmdletBinding()] param ( # The request method to call [Parameter()] [string]$Method = 'POST', # The Cove method to call [Parameter()] [string]$CoveMethod, # The parameters to pass to the method [Parameter()] [hashtable]$Params, # The url to override the default [Parameter()] [string]$UrlOverride, # The id of the request to pass [Parameter()] [string]$Id = 2 ) begin { if (!(Test-CoveApiVisa)) { New-CoveApiSession } } process { $RequestParams = @{ ContentType = 'application/json' Method = $Method Body = @{ jsonrpc = '2.0' method = $CoveMethod id = $Id visa = $Script:CoveApiSession.visa params = $Params } | ConvertTo-Json -Depth 20 Uri = $UrlOverride ? $UrlOverride : $Script:CoveApiCredentials.Url UseBasicParsing = $true SessionVariable = 'CoveSession' } Write-Debug "Sending request to $CoveMethod via $Method $($RequestParams | ConvertTo-Json -Depth 10)" try { $Request = Invoke-WebRequest @RequestParams } catch { Write-Debug "Request to $CoveMethod via $Method $($Request | ConvertTo-Json -Depth 10)" Throw "Failed to access $CoveMethod via $Method with: $($_.Exception.Message)" } if ($Request.StatusCode -ne 200) { Write-Debug "Request to $CoveMethod via $Method $($Request | ConvertTo-Json -Depth 10)" Throw "Failed to access $CoveMethod via $Method with: $($Request.StatusCode) - $($Request.StatusDescription)" } try { $Response = $Request | ConvertFrom-Json } catch { Write-Debug "Request to $CoveMethod via $Method $($Request | ConvertTo-Json -Depth 10)" Throw "Failed to parse the response from $CoveMethod via $Method with: $($_.Exception.Message)" } if ($Response.error) { Write-Debug "Request to $CoveMethod via $Method $($Request | ConvertTo-Json -Depth 10)" Write-Debug "Response from $CoveMethod via $Method $($Response | ConvertTo-Json -Depth 10)" Throw "Failed to access $CoveMethod via $Method with: $($Response.error.message)" } $Data = $Response.result.result if ($Data) { #extend the visa stored in the session $Script:CoveApiSession.visa = $Response.visa return $Data } Write-Verbose "No data returned from $CoveMethod via $Method" } end { } } #EndRegion './Private/Invoke-CoveApiRequest.ps1' 112 #Region './Private/Test-CoveApiVisa.ps1' -1 function Test-CoveApiVisa { <# .SYNOPSIS Tests to see if a valid visa exists for the Cove API .DESCRIPTION Checks for an existing valid visa .EXAMPLE Test-CoveApiVisa -Verbose Uses the script's default credentials to test for a valid visa .OUTPUTS System.Boolean #> [OutputType([System.Boolean])] [CmdletBinding()] param ( ) begin { } process { if (!$Script:CoveApiSession) { Write-Verbose "No visa found" return $false } if ($Script:CoveApiSession.validfrom -lt (Get-Date).ToUniversalTime().AddMinutes(-10)) { Write-Verbose "Visa expired, valid until $(($Script:CoveApiSession.validfrom).AddMinutes(15))" return $false } Write-Verbose "Visa found, valid until $(($Script:CoveApiSession.validfrom).AddMinutes(15))" return $true } end { } } #EndRegion './Private/Test-CoveApiVisa.ps1' 40 #Region './Public/Get-CoveCompany.ps1' -1 function Get-CoveCompany { <# .SYNOPSIS Gets companies from the Cove API .DESCRIPTION Gets companies from the Cove API, using the credentials stored in the script .EXAMPLE Get-CoveCompany -Verbose Gets all companies from the Cove API .EXAMPLE Get-CoveCompany -ParentPartnerId 123456 -Verbose Gets companies from the Cove API, where the parent partner ID is 123456 .EXAMPLE Get-CoveCompany -CompanyId 123456 -Verbose Gets the company with ID 123456 from the Cove API .OUTPUTS System.Management.Automation.PSCustomObject #> [CmdletBinding()] param ( # The ID of the partner to get companies for [Parameter()] [int]$ParentPartnerId, # The ID of the company to get [Parameter()] [int]$CompanyId, # Whether to return only sites, default is to return companies [Parameter()] [switch]$Sites ) begin { } process { $params = @{ CoveMethod = 'EnumeratePartners' Params = @{ parentPartnerId = $ParentPartnerId ? $ParentPartnerId : $Script:CoveApiSession.PartnerInfo.id fields = @(0,1,3,4,5,8,9,10,18,20) fetchRecursively = $true } Id = 'jsonrpc' } $Data = Invoke-CoveApiRequest @params if ($Data) { $UnixTimeFields = Get-CoveUnixTimeFields foreach ($Company in $Data.GetEnumerator()) { foreach ($Property in $Company.psobject.Properties) { if ($Property.Name -in $UnixTimeFields) { $Property.Value = Convert-CoveUnixTime -UnixTime $Property.Value } } } if ($CompanyId) { # This endpoint does not support filtering by ID, so we have to do it ourselves return $Data | Where-Object {$_.Id -eq $CompanyId} } if ($Sites) { return $Data | Where-Object {$_.Level -eq 'Site'} } else { return $Data | Where-Object {$_.Level -ne 'Site'} } } } end { } } #EndRegion './Public/Get-CoveCompany.ps1' 76 #Region './Public/Get-CoveCompanyInfo.ps1' -1 function Get-CoveCompanyInfo { <# .SYNOPSIS Gets detailed company info from the Cove API .DESCRIPTION Gets information fro the Cove API for a specified company, using the credentials stored in the script .PARAMETER CompanyId The ID of the company to get info for .EXAMPLE Get-CoveCompanyInfo -CompanyId 12345 -Verbose Gets information for the company with ID 12345 from the Cove API .OUTPUTS System.Management.Automation.PSCustomObject #> [CmdletBinding()] param ( # The ID of the company to get information for [Parameter(Mandatory)] [int]$CompanyId ) begin { } process { $params = @{ CoveMethod = 'GetPartnerInfoById' Params = @{ partnerId = $CompanyId } Id = 'jsonrpc' } $Data = Invoke-CoveApiRequest @params if ($Data) { $UnixTimeFields = Get-CoveUnixTimeFields foreach ($Property in $Data.psobject.Properties) { if ($Property.Name -in $UnixTimeFields) { $Property.Value = Convert-CoveUnixTime -UnixTime $Property.Value } } return $Data } } end { } } #EndRegion './Public/Get-CoveCompanyInfo.ps1' 54 #Region './Public/Get-CoveDevice.ps1' -1 function Get-CoveDevice { <# .SYNOPSIS Gets devices from the Cove API .DESCRIPTION Gets devices from the Cove API, using the credentials stored in the script .EXAMPLE Get-CoveDevice -Verbose Gets all devices from the Cove API .EXAMPLE Get-CoveDevice -PartnerId 1234 -Verbose Gets devices from the Cove API for the partner with ID 1234 .EXAMPLE Get-CoveDevice -DeviceId 1234 -Verbose Gets the device with ID 1234 from the Cove API .OUTPUTS System.Management.Automation.PSCustomObject #> [CmdletBinding()] param ( # The ID of the device to get [Parameter()] [int]$DeviceId, # The ID of the partner to get devices for [Parameter()] [int]$PartnerId ) begin { } process { $params = @{ CoveMethod = 'EnumerateAccounts' Params = @{ partnerId = $PartnerId ? $PartnerId : $Script:CoveApiSession.PartnerInfo.id } Id = 'jsonrpc' } $Data = Invoke-CoveApiRequest @params if ($Data) { $UnixTimeFields = Get-CoveUnixTimeFields if ($Data.Count -gt 1) { foreach ($Device in $Data.GetEnumerator()) { foreach ($Property in $Device.psobject.Properties) { if ($Property.Name -in $UnixTimeFields) { $Property.Value = Convert-CoveUnixTime -UnixTime $Property.Value } } } } else { foreach ($Property in $Data.psobject.Properties) { if ($Property.Name -in $UnixTimeFields) { $Property.Value = Convert-CoveUnixTime -UnixTime $Property.Value } } } Write-Verbose "Got $($Data.Count) devices" if ($DeviceId) { # This endpoint does not support API level filtering, so we'll simulate it with the results $Data = $Data | Where-Object { $_.Id -eq $DeviceId } } return $Data } Write-Verbose "Did not find any devices matching the criteria" } end { } } #EndRegion './Public/Get-CoveDevice.ps1' 75 #Region './Public/Get-CoveDeviceStatistic.ps1' -1 function Get-CoveDeviceStatistic { <# .SYNOPSIS Gets devices from the Cove API .DESCRIPTION Gets devices from the Cove API, using the credentials stored in the script .EXAMPLE Get-CoveDeviceStatistic -Verbose Gets devices from the Cove API .EXAMPLE Get-CoveDeviceStatistic -PartnerId 1234 -Verbose Gets devices from the Cove API for the partner with ID 1234 .OUTPUTS System.Collections.ArrayList #> [OutputType([System.Collections.ArrayList])] [CmdletBinding()] param ( # The ID of the partner to get devices for [Parameter()] [int]$PartnerId, # Filter by type of account - Must be M365, Servers, or Workstations [Parameter()] [ValidateSet('M365','Hardware')] [string]$BackupType ) begin { } process { $ColumnHeaders = Get-CoveDataMap -DataMap ColumnHeaders $DataSources = Get-CoveDataMap -DataMap DataSources $StatsFields = Get-CoveDataMap -DataMap StatsFields $StatusMap = Get-CoveBackupStatusMap $Filter = '' if ($BackupType) { switch ($BackupType) { 'M365' { $TypeID = 2 } 'Hardware' { $TypeID = 1 } default { } } $Filter = "$($ColumnHeaders | Where-Object {$_.Value -eq 'Account Type'} | Select-Object -ExpandProperty Key) == $($TypeID)" } $Columns = @( foreach ($Column in $ColumnHeaders.GetEnumerator()) { $Column.Key } foreach ($Source in $DataSources.GetEnumerator()) { foreach ($Field in $StatsFields.GetEnumerator()) { "$($Source.Key)$($Field.Key)" } } ) $params = @{ CoveMethod = 'EnumerateAccountStatistics' Params = @{ query = @{ PartnerId = $PartnerId ? $PartnerId : $Script:CoveApiSession.PartnerInfo.id RecordsCount = 1000 SelectionMode = 'Merged' StartRecordNumber = 0 Totals = @() Filter = $Filter Columns = $Columns OrderBy = "$(Get-CoveDataMap -FieldName 'Company Name') ASC" } } Id = 'jsonrpc' } Write-Verbose "Getting devices statatistics for Partner '$($params.Params.query.PartnerId)'" $Data = Invoke-CoveApiRequest @params if ($Data) { $UnixTimeFields = Get-CoveUnixTimeFields $DeviceStats = [System.Collections.ArrayList]@() foreach ($Statistic in $Data) { $DeviceStat = [PSCustomObject]@{ PartnerId = $Statistic.PartnerId AccountId = $Statistic.AccountId } foreach ($Setting in $Statistic.Settings.GetEnumerator()) { Write-Debug "Processing setting $($Setting.Key)" foreach ($Property in $Setting.psobject.Properties) { Write-Debug "- Processing property $($Property.Name)" $NameSubstring = $Property.Name.Length -gt 3 ? $Property.Name.Substring($Property.Name.Length - 3) : $null if ($Property.Name -is [string] -and ($Property.Name -in $UnixTimeFields -or ($NameSubstring -in $UnixTimeFields))) { $Value = Convert-CoveUnixTime -UnixTime $Property.Value } else { switch ($Property.Name) { 'I78' { # Data sources new column code $Sources = $($Setting.Value -split 'D' | Where-Object { $_ -ne '' }) $Value = foreach ($Source in $Sources) { $DataSources.GetEnumerator() | Where-Object { $_.Key -eq "D$Source" } | Select-Object -ExpandProperty Value } } default { $Value = $Property.Value } } } try { Write-Debug " - Getting column name for $($Property.Name) from column headers" $ColumnName = $ColumnHeaders.GetEnumerator() | Where-Object { $_.Key -eq $Property.Name } | Select-Object -ExpandProperty Value } catch { $ColumnName = $null } if (!$ColumnName) { $Keys = $Property.Name -split 'F' $Keys[1] = "F$($Keys[1])" $Source = $DataSources.GetEnumerator() | Where-Object { $_.Key -eq $Keys[0] } | Select-Object -ExpandProperty Value $Field = $StatsFields.GetEnumerator() | Where-Object { $_.Key -eq $Keys[1] } | Select-Object -ExpandProperty Value if (-not ($DeviceStat | Get-Member $Source)) { Write-Debug " - Creating new object for $Source with $Field" # add a new pscustomobject to the device stat object $DeviceStat | Add-Member -MemberType NoteProperty -Name $Source -Value ([PSCustomObject]@{}) } if ($Field -like '* Session Status') { if ($Value -in $StatusMap.Keys) { $Value = $StatusMap.[int]$Value } } Write-Debug " - Adding new note to $Source for $Field" $DeviceStat.$Source | Add-Member -MemberType NoteProperty -Name $Field -Value $Value continue } $ColumnName = $ColumnName ? $ColumnName : $Property.Name Write-Debug " Column name for $($Property.Name) is $ColumnName" $DeviceStat | Add-Member -MemberType NoteProperty -Name $ColumnName -Value $Value } } $DeviceStats.Add($DeviceStat) | Out-Null } return $DeviceStats } return $null } end { } } #EndRegion './Public/Get-CoveDeviceStatistic.ps1' 160 #Region './Public/Get-CovePartnerInfo.ps1' -1 function Get-CovePartnerInfo { <# .SYNOPSIS Gets the partner information for the Cove API .DESCRIPTION Gets the partner information for the Cove API, using the credentials stored in the script .EXAMPLE Get-CovePartnerInfo -Verbose Gets the partner information for the Cove API .OUTPUTS System.Management.Automation.PSCustomObject #> [CmdletBinding()] param ( ) begin { } process { $params = @{ CoveMethod = 'GetPartnerInfo' Params = @{ name = $Script:CoveApiCredentials.Partner } } $Data = Invoke-CoveApiRequest @params if ($Data) { foreach ($Property in $Data.psobject.Properties) { if ($Property.Name -in $UnixTimeFields) { $Property.Value = Convert-CoveUnixTime -UnixTime $Property.Value } } return $Data } Throw "Failed to get partner info" } end { } } #EndRegion './Public/Get-CovePartnerInfo.ps1' 45 #Region './Public/New-CoveApiCredential.ps1' -1 function New-CoveApiCredential { <# .SYNOPSIS Sets the credentials for the Cove API .DESCRIPTION Stores the attributes required by the Cove API to authenticate .PARAMETER User The username of the API user provided by Cove .PARAMETER Password The password of the user provided by Cove .PARAMETER Partner The partner name displayed in the Cove portal, with the format "PartnerName (admin@partnerdomain.tld)" .PARAMETER Url The URL for the Cove API (default: https://api.backup.management/jsonapi) .EXAMPLE $creds = @{ User = 'username@domain.tld' Password = 'supersecurepassword' | ConvertTo-SecureString -AsPlainText -Force Partner = 'PartnerName (admin@partnerdomain.tld)' } New-CoveApiCredential @creds Stores the required attributes for the Cove API to use in future calls .EXAMPLE $creds = @{ User = 'username@domain.tld' Password = 'supersecurepassword' | ConvertTo-SecureString -AsPlainText -Force Partner = 'PartnerName (admin@partnerdomain.tld)' Url = 'https://api.backup.management/jsonapi' } New-CoveApiCredential @creds Overrides the default URL for the Cove API and stores the required attributes for the Cove API to use in future calls .OUTPUTS None #> [CmdletBinding(SupportsShouldProcess)] param ( # Username for the API [Parameter(Mandatory = $true)] [string]$User, # Password for the API [Parameter(Mandatory = $true)] [securestring]$Password, # Partner name displayed in the Cove portal [Parameter(Mandatory = $true)] [string]$Partner, # URL for the Cove API (default: https://api.backup.management/jsonapi) [Parameter()] [string]$Url = "https://api.backup.management/jsonapi" ) begin { } process { if (!$User) { $User = Read-Host -Prompt "Enter the username for the Cove API" } if (!$Password) { $Password = Read-Host -Prompt "Enter the password for the Cove API" -AsSecureString } if (!$Partner) { $Partner = Read-Host -Prompt "Enter the partner name displayed in the Cove portal" } $Script:creds = @{ User = $User Password = $Password Partner = $Partner Url = $Url } Set-Variable -Name CoveApiCredentials -Value $script:creds -Scope Script -Visibility Private -Force } end { Remove-Variable -Name creds -Scope Script -Force } } #EndRegion './Public/New-CoveApiCredential.ps1' 85 #Region './Public/New-CoveApiSession.ps1' -1 function New-CoveApiSession { <# .SYNOPSIS Initiates a login session with the Cove API .DESCRIPTION Checks for an existing visa and if none is found, initiates a login session with the Cove API .EXAMPLE New-CoveApiSession -Verbose Initiates a login session with the Cove API and outputs the result to the console .OUTPUTS None #> [CmdletBinding(SupportsShouldProcess)] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUsernameAndPasswordParams', '')] param ( ) begin { } process { # if the debug flag is set if ($PSDebugContext) { Write-Debug "Debug flag set, purging existing session" Remove-Variable -Name CoveApiSession -Scope Script -Force return } if (Test-CoveApiVisa) { Write-Verbose "Visa found, no need to login" return } if (!$Script:CoveApiCredentials) { Write-Output "No credentials found, please run New-CoveApiCredential to set the credentials for Cove API" return $null } $params = @{ ContentType = 'application/json' Method = 'POST' Body = @{ jsonrpc = '2.0' method = 'Login' id = 2 params = @{ username = $Script:CoveApiCredentials.User password = (New-Object PSCredential 'user', $Script:CoveApiCredentials.Password).GetNetworkCredential().Password partner = $Script:CoveApiCredentials.Partner } } | ConvertTo-Json Uri = $Script:CoveApiCredentials.Url UseBasicParsing = $true SessionVariable = 'CoveSession' } try { $Request = Invoke-WebRequest @params } catch { Throw "Failed to login to Cove API: $($_.Exception.Message)" } New-Variable -Name CoveApiSession -Scope Script -Visibility Private -Force -Value @{} try { $Response = $Request | ConvertFrom-Json $Script:CoveApiSession.cookies = $CoveSession.Cookies.GetCookies($Script:CoveApiCredentials.Url) $Script:CoveApiSession.visa = $Response.visa $Script:CoveApiSession.userid = $Response.result.result.userid } catch { Throw "Failed to parse Cove API response: $($_.Exception.Message)" } if ($Response.error) { Throw "Failed to login to Cove API: $($Response.error.message)" } if (!$Script:CoveApiSession.visa) { Throw "Failed to login to Cove API: No visa returned" } # Set the expiry time for the visa $Script:CoveApiSession.validfrom = (Get-Date -Date "1970-01-01 00:00:00Z").ToUniversalTime().AddSeconds($Script:CoveApiSession.visa.split('-')[3]) Write-Verbose "Login successful, visa valid from $($Script:CoveApiSession.validfrom)" try { $Script:CoveApiSession.PartnerInfo = Get-CovePartnerInfo Write-Verbose "Partner $($Script:CoveApiSession.PartnerInfo.name) logged in with ID $($Script:CoveApiSession.PartnerInfo.id)" } catch { Throw "Failed to get partner info: $($_.Exception.Message)" } } end { } } #EndRegion './Public/New-CoveApiSession.ps1' 103 |