msp360.psm1

function Install-MBSAgent {
    <#
    .SYNOPSIS
        Install MBS backup agent on a local machine
    .DESCRIPTION
        Cmdlet installs MBS backup agent on a local machine
    .EXAMPLE
        PS C:\> Install-MBSAgent -URL https://s3.amazonaws.com/cb_setups/MBS/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX/CompanyName_vX.X.X.XX.exe
        Install the MBS backup agent.
    .EXAMPLE
        PS C:\> Install-MBSAgent -URL https://s3.amazonaws.com/cb_setups/MBS/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX/CompanyName_vX.X.X.XX.exe -Force
        Force to reinstall the MBS backup agent.
    .INPUTS
        None
    .OUTPUTS
        String
    .NOTES
        Author: Alex Volkov
    .LINK
        https://kb.msp360.com/managed-backup-service/powershell-module/cmdlets/install-mbsagent
    #>

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName, ValueFromPipeline=$true, HelpMessage="MBS agent URL. Copy the link from MBS portal in Download section.")]
        [String]
        $URL,
        #
        [Parameter(Mandatory=$false, HelpMessage="Force to reinstall the agent")]
        [switch]
        $Force
    )
    
    begin {

    }
    
    process {
        $TempPath = "$env:TMP"
        $TempFolder = "backup"
        if ($Force) {
            $Folder = New-Item -Path "$TempPath" -Name "$TempFolder" -ItemType "directory" -ErrorAction SilentlyContinue
            (New-Object Net.WebClient).DownloadFile("$URL", "$TempPath\$TempFolder\cbl.exe")
            Start-Process -FilePath "$TempPath\$TempFolder\cbl.exe" -ArgumentList "/S" -NoNewWindow -Wait
            Remove-Item -Path "$TempPath\$TempFolder" -Force -Recurse
        }else{
            if (Get-MBSAgent -ErrorAction SilentlyContinue) 
            {
                Write-Host "The backup agent is already installed."
            }else{
                $Folder = New-Item -Path "$TempPath" -Name "$TempFolder" -ItemType "directory"
                (New-Object Net.WebClient).DownloadFile("$URL", "$TempPath\$TempFolder\cbl.exe") 
                Start-Process -FilePath "$TempPath\$TempFolder\cbl.exe" -ArgumentList "/S" -NoNewWindow -Wait
                Remove-Item -Path "$TempPath\$TempFolder" -Force -Recurse
            }
        }
    }
    
    end {

    }
}

function Remove-MBSAgent {
    <#
    .SYNOPSIS
        Removes MBS backup agent from a local machine.
    .DESCRIPTION
        Cmdlet silently removes MBS backup agent on a local machine.
    .EXAMPLE
        PS C:> Remove-MBSAgent
 
        Are you sure you want to perform this action?
        Performing the operation "Remove-MBSAgent" on target "the backup agent"
        [Y] Yes [N] No (default is "N"):Y
 
        The backup agent has been uninstalled.
    .EXAMPLE
        PS C:> Remove-MBSAgent -Force
 
        The backup agent has been uninstalled.
    .INPUTS
        None
    .OUTPUTS
        String
    #>


    [CmdletBinding()]
    param (
       #
       [Parameter(Mandatory=$false, HelpMessage="Force to uninstall MBS agent. Confirmation message will be skipped.")]
       [switch]$Force 
    )
    
    begin {
        
    }
    
    process {
        if ($CBB = Get-MBSAgent -ErrorAction SilentlyContinue)
        {
            if ($Force){
                Start-Process -FilePath $CBB.UninstallString -ArgumentList "/S" -NoNewWindow -Wait
                Write-Host "The backup agent has been uninstalled."            
            }else{
                if (Confirm-MBSAction -Operation "Remove-MBSAgent" -Target "the backup agent"){
                    Start-Process -FilePath $CBB.UninstallString -ArgumentList "/S" -NoNewWindow -Wait
                    Write-Host "The backup agent has been uninstalled."
                }
            }
            
        }else{
            Write-Host "Cannot find the backup agent."
        }
    }
    
    end {
        
    }
}

function Get-MBSAgent {
    <#
    .SYNOPSIS
        Get MBS agent parameters (version 0.2.2)
    .DESCRIPTION
        Gets the information about MBS agent settings, paths, etc. The function pulls the registry values of the installed MBS backup agent and parses additional values.
    .EXAMPLE
        Get-MBSAgent
        Lists all of the parameters on the system into an object
    .INPUTS
        None.
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    .NOTES
        The properties from registry path UninstallKey are fetched dynamically. If the software will add new keys, they can be listed by the function.
    #>


    [CmdletBinding()]
    param (
        
    )


    if (((Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{07BCB989-197A-4E3D-852D-DE8363860401}" -Name "UninstallKey" -ErrorAction SilentlyContinue).'UninstallKey') -eq $null) {
        Write-Error "ERROR: MSP360 Online backup agent is not installed on this machine."
        return $false
    }

    $UninstallKey = (Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{07BCB989-197A-4E3D-852D-DE8363860401}" -Name "UninstallKey")."UninstallKey"
    $UninstallPath = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{07BCB989-197A-4E3D-852D-DE8363860401}"
    $FullPath = (Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\$UninstallKey" -Name "(default)")."(default)"
    $RegistryEntries = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\$UninstallKey"
    $CBBPath = $FullPath.Substring(0, $FullPath.LastIndexOf('\'))
    $CBBName = $FullPath.Substring($CBBPath.Length+1) -replace ".{4}$"
    $CBBCompany = $RegistryEntries.Publisher
    $CBBCLIPath = $CBBPath+"\cbb.exe"

    if (Test-Path -Path "$env:ProgramData\Online Backup\enginesettings.list") {
        $CBBProgramData = "$env:ProgramData\Online Backup"
    }
    elseif (Test-Path -Path "$env:ProgramData\$CBBCompany\enginesettings.list") {
        $CBBProgramData = "$env:ProgramData\$CBBCompany"
    } else {
        Write-Error "ERROR: The folder with backup agent settings not found"
        return $false
    }

    $MBSAgent = New-Object -TypeName psobject
    $MBSAgent | Add-Member -MemberType NoteProperty -Name UninstallKey -Value $UninstallKey
    $UninstallPath | Get-Member -MemberType NoteProperty | ForEach-Object {
        if (($_.Name -ne "UninstallKey") -And ($_.Name -ne "(default)") -And ($_.Name -ne "PSChildName") -And ($_.Name -ne "PSParentPath") -And ($_.Name -ne "PSPath") -And ($_.Name -ne "PSProvider")) {
            $PropertyName = $_.Name
            $MBSAgent | Add-Member -MemberType NoteProperty -Name $PropertyName -Value $UninstallPath.$PropertyName
        }
    }
    $MBSAgent | Add-Member -MemberType NoteProperty -Name FullPath -Value $FullPath
    $RegistryEntries | Get-Member -MemberType NoteProperty | ForEach-Object {
        if (($_.Name -ne "(default)") -And ($_.Name -ne "PSChildName") -And ($_.Name -ne "PSParentPath") -And ($_.Name -ne "PSPath") -And ($_.Name -ne "PSProvider")) {
            $PropertyName = $_.Name
            $MBSAgent | Add-Member -MemberType NoteProperty -Name $PropertyName -Value $RegistryEntries.$PropertyName
        }
    }
    $MBSAgent | Add-Member -MemberType NoteProperty -Name CBBPath -Value $CBBPath
    $MBSAgent | Add-Member -MemberType NoteProperty -Name CBBName -Value $CBBName
    $MBSAgent | Add-Member -MemberType NoteProperty -Name CBBCLIPath -Value $CBBCLIPath
    $MBSAgent | Add-Member -MemberType NoteProperty -Name CBBProgramData -Value $CBBProgramData

    return $MBSAgent
}

function Get-MBSApiUrl {
    <#
    .SYNOPSIS
        The cmdlet returns MBS API URLs object
    .DESCRIPTION
        The cmdlet returns MBS API URLs object
    .EXAMPLE
        PS C:\> Get-MBSApiUrl
        Explanation of what the example does
    .INPUTS
        None
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    .NOTES
         
    #>


    #param ($obj)

    $obj = New-Object -TypeName psobject
    $obj | Add-Member -MemberType NoteProperty -Name Users -Value 'https://api.mspbackups.com/api/Users'
    $obj | Add-Member -MemberType NoteProperty -Name UsersAuthenticate -Value 'https://api.mspbackups.com/api/Users/Authenticate'
    $obj | Add-Member -MemberType NoteProperty -Name ProviderLogin -Value 'https://api.mspbackups.com/api/Provider/Login'
    $obj | Add-Member -MemberType NoteProperty -Name Packages -Value 'https://api.mspbackups.com/api/Packages'
    $obj | Add-Member -MemberType NoteProperty -Name Monitoring -Value 'https://api.mspbackups.com/api/Monitoring'
    $obj | Add-Member -MemberType NoteProperty -Name Companies -Value 'https://api.mspbackups.com/api/Companies'
    $obj | Add-Member -MemberType NoteProperty -Name Licenses -Value 'https://api.mspbackups.com/api/Licenses'
    $obj | Add-Member -MemberType NoteProperty -Name Destinations -Value 'https://api.mspbackups.com/api/Destinations'
    $obj | Add-Member -MemberType NoteProperty -Name Accounts -Value 'https://api.mspbackups.com/api/Accounts'
    $obj | Add-Member -MemberType NoteProperty -Name Billing -Value 'https://api.mspbackups.com/api/Billing'
    $obj | Add-Member -MemberType NoteProperty -Name Builds -Value 'https://api.mspbackups.com/api/Builds'
    $obj | Add-Member -MemberType NoteProperty -Name Administrators -Value 'https://api.mspbackups.com/api/Administrators'
    $obj | Add-Member -MemberType NoteProperty -Name ReportIssue -Value 'https://api.mspbackups.com/api/ReportIssue'
    return $obj
}

function Write-HostAndLog {
    param(
    $Message,
    [String]$FilePath,
    [boolean]$showMessage = $true
    )
    if($showMessage){Write-Host "$Message"}
    (Get-Date -Format g) + " $Message" | Out-File -FilePath $FilePath -Append
}

function Import-MBSUsers{
    <#
    .Synopsis
    The cmdlet imports users from CSV file to MBS via API 2.0
    .DESCRIPTION
    The cmdlet imports users from CSV file to MBS via API 2.0
    .PARAMETER APIlogin
    Mandatory parameter. Specify MSB API login name. You can generate new one in General settings https://mspbackups.com/Admin/Settings.aspx
 
    .PARAMETER APIpassword
    Mandatory parameter. Specify MSB API password. You can generate new one in General settings https://mspbackups.com/Admin/Settings.aspx
 
    .PARAMETER LogFilePath
    Optional parameter. Specify log file path. The script uses \api.log by default.
 
    .PARAMETER UserFile
    Optional parameter. Specify user csv file path. The script uses \Users.csv by default.
 
    .EXAMPLE
        .\Import-Users.ps1 -APIlogin VFBB634wKpHQ -APIpassword ggH9ng6ertrB445BPDQQwU3
    .EXAMPLE
        .\Import-Users.ps1 -APIlogin VFBB634wKpHQ -APIpassword ggH9ng6ertrB445BPDQQwU3 -UserFile Users.csv -LogFilePath Mylog.txt
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$True)]
        [string]$APIlogin,
        [Parameter(Mandatory=$True)]
        [string]$APIpassword,
        [string]$LogFilePath = "api.log",
        [string]$UserFile = "Users.csv")

    $versionMinimum = [Version]'3.0'

    if ($versionMinimum -le $PSVersionTable.PSVersion)
    { 
        Write-HostAndLog -Message "*********** The script has started ****************" -FilePath $LogFilePath
        
        #Magic
        if (Test-Path $UserFile){
            $UrlUsers = (Get-MBSApiUrl).Users
            $UrlProviderLogin = (Get-MBSApiUrl).ProviderLogin
            $BodyProviderLogin = @{
                UserName = $APIlogin 
                Password = $APIpassword
            }
            $Login = Invoke-RestMethod -Method 'Post' -Uri $UrlProviderLogin -Body $BodyProviderLogin 
            $headers = @{
                'Authorization' = "Bearer " + $Login.access_token
                'Accept' = "application/json"
            }
            Write-HostAndLog -Message ($headers|ConvertTo-Json) -FilePath $LogFilePath -showMessage $false
            $UsersCSV = Import-Csv -Path $UserFile
            $i=0
            $UsersCSV | ForEach-Object{
                Write-Progress -Activity "Adding users to MBS" -Id 1 -PercentComplete (($i/$UsersCSV.Length)*100) -CurrentOperation $_.Email
                Write-HostAndLog -Message ("Adding user "+$_.Email) -FilePath $LogFilePath
                $NotificationEmailsArray = $_.'NotificationEmails' -split ';'
                $UsersPost = @{
                    Email = $_.'Email'.Trim()
                    FirstName =  $_.'FirstName'
                    LastName =  $_.'LastName'
                    NotificationEmails = @($NotificationEmailsArray)
                    Company =  $_.'Company'.Trim()
                    Enabled =  $_.'Enabled'
                    Password =  $_.'Password'
                    SendEmailInstruction =  $_.'SendEmailInstruction'
                }
                Write-HostAndLog -Message ($UsersPost|ConvertTo-Json) -FilePath $LogFilePath -showMessage $false
                $UsersResponse = Invoke-RestMethod -Uri $UrlUsers -Method POST -Headers $headers -Body ($UsersPost|ConvertTo-Json) -ContentType 'application/json'
                Write-HostAndLog -Message ("Response: "+$UsersResponse) -FilePath $LogFilePath
                $i++
            }
        }else{
            Write-HostAndLog -Message "Cannot find file $UserFile" -FilePath $LogFilePath
        }
        
        Write-HostAndLog -Message "*********** The script has finished ****************" -FilePath $LogFilePath
    }else{
        "This script requires PowerShell $versionMinimum. Update PowerSheel https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell"
        
    }
}

function Get-MBSStorageAccount {
    <#
    .SYNOPSIS
        Get MBS storage accounts assigned to the MBS agent
    .DESCRIPTION
        Get MBS storage accounts assigned to the MBS agent
    .EXAMPLE
        PS C:\> Get-MBSStorageAccount | ft
        Get all assigned storage accounts
    .EXAMPLE
        PS C:\> Get-MBSStorageAccount -ID 92ad7b17-9e2a-41bb-b0e6-c11d60fe9c63
        Get storage account by ID
    .EXAMPLE
        PS C:\> Get-MBSStorageAccount -Name "Oracle Cloud"
        Get all assigned storage accounts
    .INPUTS
        None
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    .NOTES
         
    #>


    param(
        [Parameter(Mandatory=$false, HelpMessage="Storage account ID")]
        [string]$ID,
        [Parameter(Mandatory=$false, HelpMessage="Storage account name")]
        [string]$Name
    )

    function Add-AccountContent ($Account) {
        $StorageAccount  = New-Object -TypeName psobject
        $StorageAccount | Add-Member -MemberType NoteProperty -Name DisplayName -Value $Account.DisplayName
        $StorageAccount | Add-Member -MemberType NoteProperty -Name ID -Value $Account.ID
        if ($Account.Type -eq "FileSystemConnection") {
            $StorageAccount | Add-Member -MemberType NoteProperty -Name SGCloudTypeValue -Value "FileSystemConnection"
        }else {
            $StorageAccount | Add-Member -MemberType NoteProperty -Name SGCloudTypeValue -Value $Account.SGCloudTypeValue
        }
        
        $StorageAccount | Add-Member -MemberType NoteProperty -Name Bucket -Value $Account.Bucket
        $StorageAccount | Add-Member -MemberType NoteProperty -Name SGFolderPath -Value $Account.SGFolderPath
        $StorageAccount | Add-Member -MemberType NoteProperty -Name IsRestoreOnly -Value $Account.IsRestoreOnly
        $StorageAccount | Add-Member -MemberType NoteProperty -Name UseSSL -Value $Account.UseSSL
        $StorageAccount | Add-Member -MemberType NoteProperty -Name BackupPath -Value $Account.BackupPath
        $StorageAccount | Add-Member -MemberType NoteProperty -Name SGAccountID -Value $Account.SGAccountID
        return $StorageAccount
    }

    if (Get-MBSAgent -ErrorAction SilentlyContinue) {
        $CBBProgramData = (Get-MBSAgent).CBBProgramData
        $StorageAccountsArray = @()
        $enginesettings = [xml](Get-Content ("$CBBProgramData\enginesettings.list"))
        foreach ($Account in ($enginesettings.EngineSettings.Accounts.BaseConnection)){
            if($ID){
                if($ID -eq $Account.ID){
                    $StorageAccountsArray += Add-AccountContent $Account
                }
            }elseif($Name){
                if($Name -eq $Account.DisplayName){
                    $StorageAccountsArray += Add-AccountContent $Account
                }
            }else{
                $StorageAccountsArray += Add-AccountContent $Account
            }
        }    
        return $StorageAccountsArray
    }
}

function Get-MBSBackupPlan {
    <#
    .SYNOPSIS
        Get backup plans from MBS backup agent.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType All -PlanType All
        Lists all backup plans
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType Local -PlanType All
        Lists only backup plans with a local destination.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType Cloud -PlanType All
        Lists only backup plans with a cloud destination.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType All -PlanType File-Level
        Lists all File-level backup plans.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType All -PlanType Image-Based
        Lists all Image-Based backup plans.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType Local -PlanType Image-Based
        Lists Image-Based backup plans with a local destination.
    .INPUTS
        None
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    .NOTES
         
    #>

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Backup destination storage type.")]
        [ValidateSet("All", "Local", "Cloud", "Hybrid")]
        [string]
        $StorageType = "All",
        #
        [Parameter(Mandatory=$false, HelpMessage="Backup plan type.")]
        [ValidateSet("All", "File-Level", "Image-Based", "MSSQL","MSExchange","VMware","Hyper-V")]
        [string]
        $PlanType = "All"
    )

    function Add-BackupPlanContent ($BasePlan) {
        $BackupPlans  = New-Object -TypeName psobject
        $BackupPlans | Add-Member -MemberType NoteProperty -Name Name -Value $BasePlan.Name
        $BackupPlans | Add-Member -MemberType NoteProperty -Name ID -Value $BasePlan.ID
        $BackupPlans | Add-Member -MemberType NoteProperty -Name Type -Value $BasePlan.Type
        $BackupPlans | Add-Member -MemberType NoteProperty -Name Bucket -Value $BasePlan.Bucket
        
        $Items  = @()
        $ExcludedItems  = @()
        if ($BackupPlan.BasePlan.type -eq "Plan") {
            $element = $BasePlan.SelectSingleNode("//Items")
            $element.PlanItem | ForEach-Object{
                $Items  += $_.Path
            }
            
            $element = $BasePlan.SelectSingleNode("//ExcludedItems")
            $element.PlanItem | ForEach-Object{
                $ExcludedItems  += $_.Path
            }
        }
        $BackupPlans | Add-Member -MemberType NoteProperty -Name Items -Value $Items
        $BackupPlans | Add-Member -MemberType NoteProperty -Name ExcludedItems -Value $ExcludedItems
        
        $Disks  = @()
        if ($BackupPlan.BasePlan.type -eq "BackupDiskImagePlan") {
            $element = $BasePlan.SelectSingleNode("//DiskInfo")
            $element.DiskInfoCommunication | ForEach-Object{
                $Disk  = New-Object -TypeName psobject
                $Disk | Add-Member -MemberType NoteProperty -Name Enabled -Value $_.Enabled
                $Disk | Add-Member -MemberType NoteProperty -Name DiskNumber -Value $_.DiskNumber
                $Disk | Add-Member -MemberType NoteProperty -Name DiskId -Value $_.DiskId
                $Disk | Add-Member -MemberType NoteProperty -Name Capacity -Value $_.Capacity
                $Disk | Add-Member -MemberType NoteProperty -Name DriveType -Value $_.DriveType
                $Disk | Add-Member -MemberType NoteProperty -Name Model -Value $_.Model
                $Disk | Add-Member -MemberType NoteProperty -Name PartitionTableType -Value $_.PartitionTableType
                $Volumes  = @()
                $_.Volumes.VolumeInfoCommunication | ForEach-Object {
                    $Volume  = New-Object -TypeName psobject
                    $Volume | Add-Member -MemberType NoteProperty -Name Enabled -Value $_.Enabled
                    $Volume | Add-Member -MemberType NoteProperty -Name Supported -Value $_.Supported
                    $Volume | Add-Member -MemberType NoteProperty -Name Dynamic -Value $_.Dynamic
                    $Volume | Add-Member -MemberType NoteProperty -Name Identity -Value $_.Identity
                    $Volume | Add-Member -MemberType NoteProperty -Name DiskId -Value $_.DiskId
                    $Volume | Add-Member -MemberType NoteProperty -Name WindowsVolumeIdentity -Value $_.WindowsVolumeIdentity
                    $Volume | Add-Member -MemberType NoteProperty -Name FileSystemType -Value $_.FileSystemType
                    $Volume | Add-Member -MemberType NoteProperty -Name Label -Value $_.Label
                    $Volume | Add-Member -MemberType NoteProperty -Name DriveType -Value $_.DriveType
                    $Volume | Add-Member -MemberType NoteProperty -Name UsedSpace -Value $_.UsedSpace
                    $Volume | Add-Member -MemberType NoteProperty -Name RequiredBySystem -Value $_.RequiredBySystem
                    $Volume | Add-Member -MemberType NoteProperty -Name IsBoot -Value $_.IsBoot
                    $Volume | Add-Member -MemberType NoteProperty -Name IsBitLocker -Value $_.IsBitLocker
                    $Volumes  += $Volume
                }
                $Disk | Add-Member -MemberType NoteProperty -Name Volumes -Value $Volumes
                $Disks  += $Disk
            }
        }
        $BackupPlans | Add-Member -MemberType NoteProperty -Name Disks -Value $Disks
        return $BackupPlans
    }

    function Compare-StorageTypes {
        param (
            $Account,
            [string]$StorageType
        )

        $result = $false
        switch -exact ($StorageType) {
            "All" {$result = $true}
            "Cloud" { 
                if($Account.SGCloudTypeValue -ne "FileSystemConnection" -and $Account.SGCloudTypeValue -ne "PhysicalFile" -and $BackupPlan.BasePlan.HybridID -eq "00000000-0000-0000-0000-000000000000"){
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            "Local" {
                if($Account.SGCloudTypeValue -eq "FileSystemConnection" -or $Account.SGCloudTypeValue -eq "PhysicalFile"){
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            "Hybrid" {
                if ($BackupPlan.BasePlan.HybridID -ne "00000000-0000-0000-0000-000000000000") {
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            Default {}
        }
        return $result
    }

    if (Get-MBSAgent -ErrorAction SilentlyContinue) {
        Write-Verbose -Message "Arguments: -StorageType $StorageType -PlanType $PlanType"
        $CBBProgramData = (Get-MBSAgent).CBBProgramData

        $BackupPlansArray = @()
        #-Filter "*.cbb"
        foreach ($_ in (Get-ChildItem ("$CBBProgramData\*.cbb")  -ErrorAction SilentlyContinue)){ 
            if (Get-Content $_.FullName){
                $BackupPlan = [xml](Get-Content ($_.FullName))
                switch ($PlanType) {
                    All 
                    { 
                        if ($BackupPlan.BasePlan.type -notlike "*Restore*" -and $BackupPlan.BasePlan.type -ne "ConsistencyCheckPlan"){
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    File-Level 
                    { 
                        if ($BackupPlan.BasePlan.type -eq "Plan"){
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    Image-Based 
                    {
                        if ($BackupPlan.BasePlan.type -eq "BackupDiskImagePlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    MSSQL 
                    {
                        if ($BackupPlan.BasePlan.type -eq "BackupDatabasePlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    MSExchange 
                    {
                        if ($BackupPlan.BasePlan.type -eq "BackupExchangePlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    VMware 
                    {
                        if ($BackupPlan.BasePlan.type -eq "BackupVirtualMachinesESXiPlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    Hyper-V 
                    {
                        if ($BackupPlan.BasePlan.type -eq "BackupVirtualMachinesHyperVPlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $BackupPlan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $BackupPlansArray += Add-BackupPlanContent ($BackupPlan.BasePlan)
                            }
                        }
                    }
                    Default {Write-Error -message "Incorrect PlanType parameter"}
                }
            }
        }
        return $BackupPlansArray
    }
}

function Get-MBSRestorePlan {
    <#
    .SYNOPSIS
        Get restore plans from MBS backup agent.
    .EXAMPLE
        PS C:\> Get-MBSRestorePlan -StorageType All -PlanType All
        Lists all restore plans
    .EXAMPLE
        PS C:\> Get-MBSRestorePlan -StorageType Local -PlanType All
        Lists only restore plans with a local destination.
    .EXAMPLE
        PS C:\> Get-MBSRestorePlan -StorageType Cloud -PlanType All
        Lists only restore plans with a cloud destination.
    .EXAMPLE
        PS C:\> Get-MBSRestorePlan -StorageType All -PlanType File-Level
        Lists all File-level restore plans.
    .EXAMPLE
        PS C:\> Get-MBSRestorePlan -StorageType All -PlanType Image-Based
        Lists all Image-Based restore plans.
    .EXAMPLE
        PS C:\> Get-MBSRestorePlan -StorageType Local -PlanType Image-Based
        Lists Image-Based restore plans with a local destination.
    .INPUTS
        None
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    .NOTES
         
    #>

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Destination storage type.")]
        [ValidateSet("All", "Local", "Cloud")]
        [string]
        $StorageType = "All",
        #
        [Parameter(Mandatory=$false, HelpMessage="Restore plan type.")]
        [ValidateSet("All", "File-Level", "Image-Based", "MSSQL","MSExchange","VMware","Hyper-V")]
        [string]
        $PlanType = "All"
    )

    function Add-PlanContent ($BasePlan) {
        $Plans  = New-Object -TypeName psobject
        $Plans | Add-Member -MemberType NoteProperty -Name Name -Value $BasePlan.Name
        $Plans | Add-Member -MemberType NoteProperty -Name ID -Value $BasePlan.ID
        $Plans | Add-Member -MemberType NoteProperty -Name Type -Value $BasePlan.Type
        $Plans | Add-Member -MemberType NoteProperty -Name Bucket -Value $BasePlan.Bucket
        return $Plans
    }

    function Compare-StorageTypes {
        param (
            $Account,
            [string]$StorageType
        )

        $result = $false
        switch -exact ($StorageType) {
            "All" {$result = $true}
            "Cloud" { 
                if($Account.SGCloudTypeValue -ne "FileSystemConnection" -and $Account.SGCloudTypeValue -ne "PhysicalFile"){
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            "Local" {
                if($Account.SGCloudTypeValue -eq "FileSystemConnection" -or $Account.SGCloudTypeValue -eq "PhysicalFile"){
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            Default {}
        }
        return $result
    }

    if (Get-MBSAgent -ErrorAction SilentlyContinue) {
        $CBBProgramData = (Get-MBSAgent).CBBProgramData

        $PlansArray = @()

        foreach ($_ in (Get-ChildItem ("$CBBProgramData") -Filter "*.cbb" -ErrorAction SilentlyContinue)){ 
            if (Get-Content $_.FullName){
                $Plan = [xml](Get-Content ($_.FullName))
                switch ($PlanType) {
                    All 
                    { 
                        if ($Plan.BasePlan.type -notlike "Backup*" -and $Plan.BasePlan.type -ne "ConsistencyCheckPlan" -and $Plan.BasePlan.type -ne "Plan"){
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    File-Level 
                    { 
                        if ($Plan.BasePlan.type -eq "RestorePlan"){
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    Image-Based 
                    {
                        if ($Plan.BasePlan.type -eq "RestoreDiskImagePlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    MSSQL 
                    {
                        if ($Plan.BasePlan.type -eq "RestoreDatabasePlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    MSExchange 
                    {
                        if ($Plan.BasePlan.type -eq "RestoreExchangePlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    VMware 
                    {
                        if ($Plan.BasePlan.type -eq "RestoreVirtualMachinesESXiPlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    Hyper-V 
                    {
                        if ($Plan.BasePlan.type -eq "RestoreVirtualMachinesHyperVPlan") {
                            if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                                $PlansArray += Add-PlanContent ($Plan.BasePlan)
                            }
                        }
                    }
                    Default {Write-Error -message "Incorrect PlanType parameter"}
                }
            }
        }
        return $PlansArray
    }
}

function Get-MBSConsistencyCheckPlan {
    <#
    .SYNOPSIS
        Lists consistency check plans.
    .DESCRIPTION
        Lists consistency check plans.
    .EXAMPLE
        PS C:\> Get-MBSConsistencyCheckPlan -StorageType All
        List all consistency checks
    .EXAMPLE
        PS C:\> Get-MBSConsistencyCheckPlan -StorageType Local
        List only consistency checks for local storages
    .EXAMPLE
        PS C:\> Get-MBSConsistencyCheckPlan -StorageType Cloud
        List only consistency checks for cloud storages
    .INPUTS
        None
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    .NOTES
         
    #>

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false)]
        [ValidateSet("All", "Local", "Cloud")]
        [string]
        $StorageType = "All"
    )
    
    
    function Add-PlanContent ($BasePlan) {
        $Plans  = New-Object -TypeName psobject
        $Plans | Add-Member -MemberType NoteProperty -Name Name -Value $BasePlan.Name
        $Plans | Add-Member -MemberType NoteProperty -Name ID -Value $BasePlan.ID
        $Plans | Add-Member -MemberType NoteProperty -Name Type -Value $BasePlan.Type
        $Plans | Add-Member -MemberType NoteProperty -Name Bucket -Value $BasePlan.Bucket
        $Schedule  = New-Object -TypeName psobject
        $Schedule | Add-Member -MemberType NoteProperty -Name Enabled -Value $BasePlan.Schedule.Enabled
        $Schedule | Add-Member -MemberType NoteProperty -Name RecurType -Value $BasePlan.Schedule.RecurType
        $Schedule | Add-Member -MemberType NoteProperty -Name RepeatEvery -Value $BasePlan.Schedule.RepeatEvery
        $Schedule | Add-Member -MemberType NoteProperty -Name OnceDate -Value $BasePlan.Schedule.OnceDate
        $Schedule | Add-Member -MemberType NoteProperty -Name DailyRecurrence -Value $BasePlan.Schedule.DailyRecurrence
        $Schedule | Add-Member -MemberType NoteProperty -Name DailyRecurrencePeriod -Value $BasePlan.Schedule.DailyRecurrencePeriod
        $Schedule | Add-Member -MemberType NoteProperty -Name DailyFromHour -Value $BasePlan.Schedule.DailyFromHour
        $Schedule | Add-Member -MemberType NoteProperty -Name DailyFromMinutes -Value $BasePlan.Schedule.DailyFromMinutes
        $Schedule | Add-Member -MemberType NoteProperty -Name DailyTillHour -Value $BasePlan.Schedule.DailyTillHour
        $Schedule | Add-Member -MemberType NoteProperty -Name DailyTillMinutes -Value $BasePlan.Schedule.DailyTillMinutes
        $Schedule | Add-Member -MemberType NoteProperty -Name Hour -Value $BasePlan.Schedule.Hour
        $Schedule | Add-Member -MemberType NoteProperty -Name Minutes -Value $BasePlan.Schedule.Minutes
        $Schedule | Add-Member -MemberType NoteProperty -Name Seconds -Value $BasePlan.Schedule.Seconds
        $Schedule | Add-Member -MemberType NoteProperty -Name WeekDays -Value $BasePlan.Schedule.WeekDays
        $Schedule | Add-Member -MemberType NoteProperty -Name DayOfWeek -Value $BasePlan.Schedule.DayOfWeek
        $Schedule | Add-Member -MemberType NoteProperty -Name WeekNumber -Value $BasePlan.Schedule.WeekNumber
        $Schedule | Add-Member -MemberType NoteProperty -Name DayOfMonth -Value $BasePlan.Schedule.DayOfMonth
        $Schedule | Add-Member -MemberType NoteProperty -Name StopAfterTicks -Value $BasePlan.Schedule.StopAfterTicks
      
        #$obj = ($BasePlan.SelectNodes("Schedule/*") | Select-Object -Expand Name)
        ##$obj = $obj.split()
        #$obj -split ' '| get-member
        #ForEach-Object -InputObject ($obj -split ' ') -Process {
        # #$objname = "Schedule/"+$_.'#text'
        # $_
        # $Schedule | Add-Member -MemberType NoteProperty -Name $_ -Value 'test'
        #}
        #$Schedule | Add-Member -MemberType NoteProperty -Name Enabled -Value $BasePlan.Schedule.Enabled
        #$BasePlan.SelectNodes("Schedule/*") | Select-Object -Expand Name, '#text'
        $Plans | Add-Member -MemberType NoteProperty -Name Schedule -Value $Schedule
        return $Plans
    }

    function Compare-StorageTypes {
        param (
            $Account,
            [string]$StorageType
        )

        $result = $false
        switch -exact ($StorageType) {
            "All" {$result = $true}
            "Cloud" { 
                if($Account.SGCloudTypeValue -ne "FileSystemConnection" -and $Account.SGCloudTypeValue -ne "PhysicalFile"){
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            "Local" {
                if($Account.SGCloudTypeValue -eq "FileSystemConnection" -or $Account.SGCloudTypeValue -eq "PhysicalFile"){
                    $result = $true 
                }else {
                    $result = $false
                }
            }
            Default {}
        }
        return $result
    }

    if (Get-MBSAgent -ErrorAction SilentlyContinue) {
        $CBBProgramData = (Get-MBSAgent).CBBProgramData
        $PlansArray = @()

        foreach ($_ in (Get-ChildItem ("$CBBProgramData") -Filter "*.cbb" -ErrorAction SilentlyContinue)){ 
            if (Get-Content $_.FullName){
                $Plan = [xml](Get-Content ($_.FullName))
                if ($Plan.BasePlan.type -eq "ConsistencyCheckPlan"){
                    if(Compare-StorageTypes -Account (Get-MBSStorageAccount -ID $Plan.BasePlan.ConnectionID) -StorageType $StorageType){
                        $PlansArray += Add-PlanContent ($Plan.BasePlan)
                    }
                }
            }
        }
        return $PlansArray
    }
}

function Edit-MBSBackupPlan {
    <#
    .SYNOPSIS
        Edit MBS backup plan.
    .DESCRIPTION
        Edit MBS supported backup plan. File-Level and Image-Based backup plan type are supported.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan | Edit-MBSBackupPlan -CommonParameterSet -Compression $true
        Enable compression option for all supported backup plans.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -PlanType File-Level | Edit-MBSBackupPlan -FileLevelParameterSet -ntfs $true
        Enable backup NTFS permissions option for all file-level backup plans.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -PlanType Image-Based | Edit-MBSBackupPlan -ImageBasedParameterSet -BackupVolumes SystemRequired
        Add only system required volumes to all image-based backup plans.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType Cloud -PlanType Image-Based | Edit-MBSBackupPlan -ImageBasedParameterSet -BackupVolumes SystemRequired
        Add only system required volumes to cloud image-based backup plans.
    .INPUTS
        System.String[]
        System.String
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    #>


    [CmdletBinding(DefaultParameterSetName='Common')]
    param (
        #
        [Parameter(Mandatory=$True, HelpMessage="Backup plan settings related to File-Level backup plan type", ParameterSetName='FileLevel')]
        [switch]
        $FileLevelParameterSet,
        #
        [Parameter(Mandatory=$True, HelpMessage="Backup plan settings related to Image-Based backup plan type", ParameterSetName='ImageBased')]
        [switch]
        $ImageBasedParameterSet,
        #
        [Parameter(Mandatory=$True, HelpMessage="Backup plan settings related to any backup plan type. Like Encryption, Compression, Retention policy, Schedule, etc.", ParameterSetName='Common')]
        [switch]
        $CommonParameterSet,
        #
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $ID,
        #
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $Name,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to change storage account. Use Get-MBSStorageAccount to list storages", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to change storage account. Use Get-MBSStorageAccount to list storages", ParameterSetName='FileLevel')]
        [ValidateSet("ExcludeEncryptedFiles", "ExcludeTempWindowsAppsFolders","ExcludeOneDriveFolders","AddFixedDrivesToIBB", "AddFixedDrivesToFileLevel", "DisablePreAction")]
        [string]
        $SpecialFunction,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to change storage account. Use Get-MBSStorageAccount to list storages", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to change storage account. Use Get-MBSStorageAccount to list storages", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to change storage account. Use Get-MBSStorageAccount to list storages", ParameterSetName='FileLevel')]
        [string]
        $StorageAccountID,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to rename plan", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to rename plan", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to rename plan", ParameterSetName='FileLevel')]
        [String]
        $NewName,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable encryption", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable encryption", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable encryption", ParameterSetName='FileLevel')]
        [switch]
        $DisableEncryption,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable schedule", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable schedule", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable schedule", ParameterSetName='FileLevel')]
        [switch]
        $DisableSchedule,
        #
        [Parameter(Mandatory=$False, HelpMessage="Sync before run.", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Sync before run.", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Sync before run.", ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $SyncBeforeRun,
        #
        [Parameter(Mandatory=$False, HelpMessage="Use server side encryption (valid only for Amazon S3)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Use server side encryption (valid only for Amazon S3)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Use server side encryption (valid only for Amazon S3)", ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $ServerSideEncryption,
        #
        [Parameter(Mandatory=$False, HelpMessage="Encryption algorithm. Possible values: AES128-256", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Encryption algorithm. Possible values: AES128-256", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Encryption algorithm. Possible values: AES128-256", ParameterSetName='FileLevel')]
        [ValidateSet("AES128", "AES192","AES256")]
        [String]
        $EncryptionAlgorithm,
        #
        [Parameter(Mandatory=$False, HelpMessage="Encryption password. Use -EncryptionPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Encryption password. Use -EncryptionPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Encryption password. Use -EncryptionPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)", ParameterSetName='FileLevel')]
        [SecureString]
        $EncryptionPassword,
        #
        [Parameter(Mandatory=$False, HelpMessage="Compress files", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Compress files", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Compress files", ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $Compression,
        #
        [Parameter(Mandatory=$False, HelpMessage="Storage Class (valid only for Amazon S3)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Storage Class (valid only for Amazon S3)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Storage Class (valid only for Amazon S3)", ParameterSetName='FileLevel')]
        [ValidateSet("Standard", "IntelligentTiering", "StandardIA", "OneZoneIA", "Glacier", "GlacierDeepArchive")]
        [String]
        $StorageClass,
        #
        [Parameter(Mandatory=$False, HelpMessage="Save backup plan configuration to the backup storage", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Save backup plan configuration to the backup storage", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Save backup plan configuration to the backup storage", ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $SaveBPConfiguration,
        #
        [Parameter(Mandatory=$False, HelpMessage="Output format. Possible values: short, full(default)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Output format. Possible values: short, full(default)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Output format. Possible values: short, full(default)", ParameterSetName='FileLevel')]
        [ValidateSet("short", "full")]
        [String]
        $output,
        #
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)", ParameterSetName='FileLevel')]
        [SecureString]
        $MasterPassword,
        # ------------------------- Schedule -----------------------------
        [Parameter(Mandatory=$False, HelpMessage="Specify schedule recurring type", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify schedule recurring type", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify schedule recurring type", ParameterSetName='FileLevel')]
        [ValidateSet("day", "week", "month", "dayofmonth", "real-time")]
        [String]
        $RecurringType,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify datetime or time of schedule. Example -at ""06/09/19 7:43 AM"" , or -at ""7:43 AM"" for every day schedule", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify datetime or time of schedule. Example -at ""06/09/19 7:43 AM"" , or -at ""7:43 AM"" for every day schedule", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify datetime or time of schedule. Example -at ""06/09/19 7:43 AM"" , or -at ""7:43 AM"" for every day schedule", ParameterSetName='FileLevel')]
        [String]
        $At,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify day for 'dayofmonth' schedule (1..31)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify day for 'dayofmonth' schedule (1..31)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify day for 'dayofmonth' schedule (1..31)", ParameterSetName='FileLevel')]
        [Int32][ValidateRange(1,31)]
        $DayOfMonth,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify day(s) of week for weekly schedule. Example: ""su, mo, tu, we, th, fr, sa"". Or specify day of week for monthly schedule", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify day(s) of week for weekly schedule. Example: ""su, mo, tu, we, th, fr, sa"". Or specify day of week for monthly schedule", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify day(s) of week for weekly schedule. Example: ""su, mo, tu, we, th, fr, sa"". Or specify day of week for monthly schedule", ParameterSetName='FileLevel')]
        [ValidateSet("su", "mo", "tu", "we", "th", "fr", "sa")]
        [string[]]
        $WeekDay,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify number of week. Possible values: First, Second, Third, Fourth, Penultimate, Last", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify number of week. Possible values: First, Second, Third, Fourth, Penultimate, Last", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify number of week. Possible values: First, Second, Third, Fourth, Penultimate, Last", ParameterSetName='FileLevel')]
        [ValidateSet("First", "Second", "Third", "Fourth", "Penultimate", "Last")]
        [string]
        $WeekNumber,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify daily recurring from value", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily recurring from value", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily recurring from value", ParameterSetName='FileLevel')]
        [string]
        $DailyFrom,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify daily recurring till value", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily recurring till value", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily recurring till value", ParameterSetName='FileLevel')]
        [string]
        $DailyTill,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify recurring period type. Possible values: hour, min", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify recurring period type. Possible values: hour, min", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify recurring period type. Possible values: hour, min", ParameterSetName='FileLevel')]
        [ValidateSet("hour", "min")]
        [string]
        $Occurs,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify recurring period value", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify recurring period value", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify recurring period value", ParameterSetName='FileLevel')]
        [string]
        $OccursValue,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify repeat period value. Possible values: 1..31", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify repeat period value. Possible values: 1..31", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify repeat period value. Possible values: 1..31", ParameterSetName='FileLevel')]
        [Int32][ValidateRange(1,31)]
        $RepeatEvery,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify start date of repetitions", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify start date of repetitions", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify start date of repetitions", ParameterSetName='FileLevel')]
        [string]
        $repeatStartDate,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify time in HH:MM to stop the plan if it runs for HH hours MM minutes. Example -stopAfter ""20:30"" or -stopAfter ""100:00"" etc.", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify time in HH:MM to stop the plan if it runs for HH hours MM minutes. Example -stopAfter ""20:30"" or -stopAfter ""100:00"" etc.", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify time in HH:MM to stop the plan if it runs for HH hours MM minutes. Example -stopAfter ""20:30"" or -stopAfter ""100:00"" etc.", ParameterSetName='FileLevel')]
        [string]
        $stopAfter,
        # ------------------ Pre / Post actions ----------------------------
        [Parameter(Mandatory=$False, HelpMessage="Specify command to be executed before backup completes.", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify command to be executed before backup completes.", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify command to be executed before backup completes.", ParameterSetName='FileLevel')]
        [string]
        $preActionCommand,
        #
        [Parameter(Mandatory=$False, HelpMessage='Specify to continue backup plan if pre-backup action failed. Possible values: $true/$false', ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage='Specify to continue backup plan if pre-backup action failed. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage='Specify to continue backup plan if pre-backup action failed. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Alias("pac")]
        [Nullable[boolean]]
        $preActionContinueAnyway,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify command to be executed after backup has been successfully completed.", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify command to be executed after backup has been successfully completed.", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify command to be executed after backup has been successfully completed.", ParameterSetName='FileLevel')]
        [string]
        $postActionCommand,
        #
        [Parameter(Mandatory=$False, HelpMessage='Specify to execute post-backup action in any case (regardless the backup result). Possible values: $true/$false', ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage='Specify to execute post-backup action in any case (regardless the backup result). Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage='Specify to execute post-backup action in any case (regardless the backup result). Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Alias("paa")]
        [Nullable[boolean]]
        $postActionRunAnyway,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to receive notification email when backup fails (errorOnly) or in all cases (on). Prior to turn on the notification settings must be configured. Possible values: errorOnly, on, off", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to receive notification email when backup fails (errorOnly) or in all cases (on). Prior to turn on the notification settings must be configured. Possible values: errorOnly, on, off", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to receive notification email when backup fails (errorOnly) or in all cases (on). Prior to turn on the notification settings must be configured. Possible values: errorOnly, on, off", ParameterSetName='FileLevel')]
        [ValidateSet("errorOnly", "on", "off")]
        [string]
        $notification,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to add entry to Windows Event Log when backup fails (errorOnly) or in all cases (on). Possible values: errorOnly, on, off", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to add entry to Windows Event Log when backup fails (errorOnly) or in all cases (on). Possible values: errorOnly, on, off", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to add entry to Windows Event Log when backup fails (errorOnly) or in all cases (on). Possible values: errorOnly, on, off", ParameterSetName='FileLevel')]
        [ValidateSet("errorOnly", "on", "off")]
        [string]
        $winLog,
        # ---------------------------- Retention Policy -------------------------
        
        [Parameter(Mandatory=$False, HelpMessage="Purge versions that are older than period (except lastest version). Possible values: no, 1d(day), 1w(week), 1m(month)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Purge versions that are older than period (except lastest version). Possible values: no, 1d(day), 1w(week), 1m(month)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Purge versions that are older than period (except lastest version). Possible values: no, 1d(day), 1w(week), 1m(month)", ParameterSetName='FileLevel')]
        [string]
        $purge,
        #
        [Parameter(Mandatory=$False, HelpMessage="Keep limited number of versions. Possible values: all, number", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Keep limited number of versions. Possible values: all, number", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Keep limited number of versions. Possible values: all, number", ParameterSetName='FileLevel')]
        [string]
        $keep,
        #
        [Parameter(Mandatory=$False, HelpMessage='Always keep the last version. Possible values: $true/$false', ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage='Always keep the last version. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage='Always keep the last version. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $keepLastVersion,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify purge delay. Possible values: no, 1d(day), 1w(week), 1m(month)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify purge delay. Possible values: no, 1d(day), 1w(week), 1m(month)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify purge delay. Possible values: no, 1d(day), 1w(week), 1m(month)", ParameterSetName='FileLevel')]
        [string]
        $delayPurge,
        #-------------------------Full schedule -----------------------------------
        [Parameter(Mandatory=$False, HelpMessage='Run missed scheduled backup immediately when computer starts up. Possible values: $true/$false', ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage='Run missed scheduled backup immediately when computer starts up. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage='Run missed scheduled backup immediately when computer starts up. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $runMissed,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify force full schedule recurring type. Possible values: day, week, month, dayofmonth, real-time", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full schedule recurring type. Possible values: day, week, month, dayofmonth, real-time", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full schedule recurring type. Possible values: day, week, month, dayofmonth, real-time", ParameterSetName='FileLevel')]
        [ValidateSet("day", "week", "month", "dayofmonth", "real-time")]
        [string]
        $RecurringTypeForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify datetime or time of force full schedule. Example -atForceFull ""06/09/19 7:43 AM"" , or -atForceFull ""7:43 AM"" for every day force full schedule", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify datetime or time of force full schedule. Example -atForceFull ""06/09/19 7:43 AM"" , or -atForceFull ""7:43 AM"" for every day force full schedule", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify datetime or time of force full schedule. Example -atForceFull ""06/09/19 7:43 AM"" , or -atForceFull ""7:43 AM"" for every day force full schedule", ParameterSetName='FileLevel')]
        [string]
        $atForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify day for 'dayofmonth' force full schedule (1..31)", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify day for 'dayofmonth' force full schedule (1..31)", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify day for 'dayofmonth' force full schedule (1..31)", ParameterSetName='FileLevel')]
        [Int32][ValidateRange(1,31)]
        $dayForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="listOfWeekDays. Specify day(s) of week for weekly force full schedule. Example: ""su, mo, tu, we, th, fr, sa"". Or specify day of week for monthly force full schedule", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="listOfWeekDays. Specify day(s) of week for weekly force full schedule. Example: ""su, mo, tu, we, th, fr, sa"". Or specify day of week for monthly force full schedule", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="listOfWeekDays. Specify day(s) of week for weekly force full schedule. Example: ""su, mo, tu, we, th, fr, sa"". Or specify day of week for monthly force full schedule", ParameterSetName='FileLevel')]
        [string]
        $weekdayForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify number of week. Possible values: First, Second, Third, Fourth, Penultimate, Last", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify number of week. Possible values: First, Second, Third, Fourth, Penultimate, Last", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify number of week. Possible values: First, Second, Third, Fourth, Penultimate, Last", ParameterSetName='FileLevel')]
        [ValidateSet("First", "Second", "Third", "Fourth", "Penultimate", "Last")]
        [string]
        $weeknumberForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify daily force full recurring from value", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily force full recurring from value", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily force full recurring from value", ParameterSetName='FileLevel')]
        [string]
        $dailyFromForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify daily force full recurring till value", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily force full recurring till value", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify daily force full recurring till value", ParameterSetName='FileLevel')]
        [string]
        $dailyTillForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify force full recurring period type. Possible values: hour, min", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full recurring period type. Possible values: hour, min", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full recurring period type. Possible values: hour, min", ParameterSetName='FileLevel')]
        [ValidateSet("hour", "min")]
        [string]
        $occursForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify force full recurring period value", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full recurring period value", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full recurring period value", ParameterSetName='FileLevel')]
        [string]
        $occurValueForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify force full repeat period value. Possible values: 1..31", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full repeat period value. Possible values: 1..31", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full repeat period value. Possible values: 1..31", ParameterSetName='FileLevel')]
        [Int32][ValidateRange(1,31)]
        $repeatEveryForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify force full start date of repetitions", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full start date of repetitions", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full start date of repetitions", ParameterSetName='FileLevel')]
        [string]
        $repeatStartDateForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify force full time in HH:MM to stop the plan if it runs for HH hours MM minutes. Example -stopAfterForceFull ""20:30"" or -stopAfterForceFull ""100:00"" etc.", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full time in HH:MM to stop the plan if it runs for HH hours MM minutes. Example -stopAfterForceFull ""20:30"" or -stopAfterForceFull ""100:00"" etc.", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify force full time in HH:MM to stop the plan if it runs for HH hours MM minutes. Example -stopAfterForceFull ""20:30"" or -stopAfterForceFull ""100:00"" etc.", ParameterSetName='FileLevel')]
        [string]
        $stopAfterForceFull,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify rebackup datetime. Example: ""06/09/19 7:43 AM""", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify rebackup datetime. Example: ""06/09/19 7:43 AM""", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify rebackup datetime. Example: ""06/09/19 7:43 AM""", ParameterSetName='FileLevel')]
        [string]
        $rebackupDate,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable schedule force full", ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable schedule force full", ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage="Specify to disable schedule force full", ParameterSetName='FileLevel')]
        [switch]
        $DisableForceFullSchedule,
        #---------------------------- Block Level ------------------
        [Parameter(Mandatory=$False, HelpMessage='Use block level backup. Possible values: $true/$false', ParameterSetName='Common')]
        [Parameter(Mandatory=$False, HelpMessage='Use block level backup. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Parameter(Mandatory=$False, HelpMessage='Use block level backup. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $useBlockLevelBackup,
        # --------------------------- File Backup settings ------------

        [Parameter(Mandatory=$False, HelpMessage="Backup NTFS permissions", ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $ntfs,
        #
        [Parameter(Mandatory=$False, HelpMessage='Force using VSS (Volume Shadow Copy Service). Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $ForceUsingVSS,
        #
        [Parameter(Mandatory=$False, HelpMessage='Use share read/write mode on errors. Can help if file is open in share read/write mode. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $sharerw,
        #
        [Parameter(Mandatory=$False, HelpMessage="Delete files that have been deleted locally after specified number of days. Example: ""-df 30""", ParameterSetName='FileLevel')]
        [Alias("df")]        
        [string]
        $DeleteLocallyDeletedFilesAfter,
        #
        [Parameter(Mandatory=$False, HelpMessage='Backup empty folders. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $BackupEmptyFolders,
        #
        [Parameter(Mandatory=$False, HelpMessage="Backup files only after specific date. Example: ""06/09/19 7:43 AM""", ParameterSetName='FileLevel')]
        [string]
        $oa,
        #
        [Parameter(Mandatory=$False, HelpMessage='Except system and hidden files. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $es,
        #
        [Parameter(Mandatory=$False, HelpMessage="Skip folders. Example: -skipfolder ""bin;*temp*;My*""", ParameterSetName='FileLevel')]
        [string]
        $SkipFolders,
        #
        [Parameter(Mandatory=$False, HelpMessage="Include files mask. Example: -ifm ""*.doc;*.xls""", ParameterSetName='FileLevel')]
        [string]
        $IncludeFilesMask,
        #
        [Parameter(Mandatory=$False, HelpMessage="Exclude files mask. Example: -efm ""*.bak;*.tmp""", ParameterSetName='FileLevel')]
        [string]
        $ExcludeFilesMask,
        #
        [Parameter(Mandatory=$False, HelpMessage='Ignore errors path not found. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Alias("iepnf")]        
        [Nullable[boolean]]
        $IgnoreErrorPathNotFound,
        #
        [Parameter(Mandatory=$False, HelpMessage='Track deleted files data. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $TrackDeletedFiles,
        #
        [Parameter(Mandatory=$False, HelpMessage="Add a new file to backup plan", ParameterSetName='FileLevel')]
        [string]
        $AddNewFile,
        #
        [Parameter(Mandatory=$False, HelpMessage="Add a new directory to backup plan", ParameterSetName='FileLevel')]
        [string]
        $AddNewFolder,
        #
        [Parameter(Mandatory=$False, HelpMessage="Exclude a file from backup plan", ParameterSetName='FileLevel')]
        [string]
        $ExcludeFile,
        #
        [Parameter(Mandatory=$False, HelpMessage="Exclude a directory from backup plan", ParameterSetName='FileLevel')]
        [string]
        $ExcludeDirectory,
        #
        [Parameter(Mandatory=$False, HelpMessage="Backup file", ParameterSetName='FileLevel')]
        [string]
        $BackupFile,
        #
        [Parameter(Mandatory=$False, HelpMessage="Backup directory", ParameterSetName='FileLevel')]
        [string]
        $BackupDirectory,
        #
        [Parameter(Mandatory=$False, HelpMessage='Specify to generate detailed report. Possible values: $true/$false', ParameterSetName='FileLevel')]
        [Nullable[boolean]]
        $GenerateDetailedReport,
        # ------------------------- Image-Based --------------------------------------
        [Parameter(Mandatory=$False, HelpMessage="Backup Volumes type", ParameterSetName='ImageBased')]
        [ValidateSet("AllVolumes", "SystemRequired", "SelectedVolumes")]
        [string]
        $BackupVolumes,
        #
        [Parameter(Mandatory=$False, HelpMessage="Backup selected volumes with the specified ids.", ParameterSetName='ImageBased')]
        [string[]]
        $Volumes,
        #
        [Parameter(Mandatory=$False, HelpMessage='Disable VSS, use direct access to NTFS volume. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Nullable[boolean]]
        $disableVSS,
        #
        [Parameter(Mandatory=$False, HelpMessage='Ignore bad sectors. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Nullable[boolean]]
        $ignoreBadSectors,
        #
        [Parameter(Mandatory=$False, HelpMessage='Use system VSS provider. Possible values: $true/$false', ParameterSetName='ImageBased')]
        [Nullable[boolean]]
        $useSystemVSS,
        #
        [Parameter(Mandatory=$False, HelpMessage="Prefetch block count (0 - 100, 0 without prefetch)", ParameterSetName='ImageBased')]
        [Int32][ValidateRange(0,100)]
        $prefetchBlockCount,
        #
        [Parameter(Mandatory=$False, HelpMessage="Block size. Possible values: 128, 256, 512, 1024", ParameterSetName='ImageBased')]
        [ValidateSet("128", "256", "512", "1024")]
        [string]
        $blockSize
    )

    
    
    begin {
        $CBB = Get-MBSAgent
    }
    
    process {
        function Set-Arguments {
            if ($StorageAccountID){$Argument += " -aid $StorageAccountID"}
            if ($NewName){$Argument += " -nn ""$NewName"""}
            if ($SyncBeforeRun -ne $null){
                if ($SyncBeforeRun) {
                    $Argument += " -sync yes"
                }else{
                    $Argument += " -sync no"
                }
            }
            if ($Compression -ne $null){
                if ($Compression) {
                    $Argument += " -c yes"
                }else{
                    $Argument += " -c no"
                }
            }
            if ($DisableEncryption){$Argument += " -ed"}
            if ($DisableSchedule){$Argument += " -sd"}
            if ($ServerSideEncryption -ne $null){
                if ($ServerSideEncryption) {
                    $Argument += " -sse yes"
                }else{
                    $Argument += " -sse no"
                }
            }
            if ($EncryptionAlgorithm){$Argument += " -ea $EncryptionAlgorithm"}
            if ($EncryptionPassword){$Argument += " -ep """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($EncryptionPassword)))+""""}
            if ($StorageClass){$Argument += " -sc $StorageClass"}
            if ($SaveBPConfiguration -ne $null){
                if ($SaveBPConfiguration) {
                    $Argument += " -sp yes"
                }else{
                    $Argument += " -sp no"
                }
            }
            if ($SaveBPRecurringTypeConfiguration){$Argument += " -every $RecurringType"}
            if ($At){$Argument += " -at $At"}
            if ($DayOfMonth){$Argument += " -day $DayOfMonth"}
            if ($Weekday){$Argument += " -weekday "+($Weekday -join ",")}
            if ($Weeknumber){$Argument += " -weeknumber $Weeknumber"}
            if ($DailyFrom){$Argument += " -dailyFrom $DailyFrom"}
            if ($DailyTill){$Argument += " -dailyTill $DailyTill"}
            if ($Occurs){$Argument += " -occurs $Occurs"}
            if ($OccurValue){$Argument += " -occurValue $OccurValue"}
            if ($repeatStartDate){$Argument += " -repeatStartDate $repeatStartDate"}
            if ($stopAfter){$Argument += " -stopAfter $stopAfter"}
            if ($preActionCommand){$Argument += " -preAction ""$preActionCommand"""}
            if ($preActionContinueAnyway -ne $null){
                if ($preActionContinueAnyway) {
                    $Argument += " -pac yes"
                }else{
                    $Argument += " -pac no"
                }
            }
            if ($postActionCommand){$Argument += " -postAction ""$postActionCommand"""}
            if ($postActionRunAnyway -ne $null){
                if ($postActionRunAnyway) {
                    $Argument += " -paa yes"
                }else{
                    $Argument += " -paa no"
                }
            }
            if ($notification){$Argument += " -notification $notification"}
            if ($winLog){$Argument += " -winLog $winLog"}
            if ($purge){$Argument += " -purge $purge"}
            if ($keep){$Argument += " -keep $keep"}
            if ($keepLastVersion -ne $null){
                if ($keepLastVersion) {
                    $Argument += " -keepLastVersion yes"
                }else{
                    $Argument += " -keepLastVersion no"
                }
            }
            if ($delayPurge){$Argument += " -delayPurge $delayPurge"}
            if ($runMissed -ne $null){
                if ($runMissed) {
                    $Argument += " -runMissed yes"
                }else{
                    $Argument += " -runMissed no"
                }
            }
            if ($RecurringTypeForceFull){$Argument += " -everyForceFull $RecurringTypeForceFull"}
            if ($atForceFull){$Argument += " -atForceFull $atForceFull"}
            if ($dayForceFull){$Argument += " -dayForceFull $dayForceFull"}
            if ($weekdayForceFull){$Argument += " -weekdayForceFull $weekdayForceFull"}
            if ($weeknumberForceFull){$Argument += " -weeknumberForceFull $weeknumberForceFull"}
            if ($dailyFromForceFull){$Argument += " -dailyFromForceFull $dailyFromForceFull"}
            if ($dailyTillForceFull){$Argument += " -dailyTillForceFull $dailyTillForceFull"}
            if ($occursForceFull){$Argument += " -occursForceFull $occursForceFull"}
            if ($occurValueForceFull){$Argument += " -occurValueForceFull $occurValueForceFull"}
            if ($repeatEveryForceFull){$Argument += " -repeatEveryForceFull $repeatEveryForceFull"}
            if ($repeatStartDateForceFull){$Argument += " -repeatStartDateForceFull $repeatStartDateForceFull"}
            if ($stopAfterForceFull){$Argument += " -stopAfterForceFull $stopAfterForceFull"}
            if ($rebackupDate){$Argument += " -rebackupDate $rebackupDate"}
            if ($DisableForceFullSchedule){$Argument += " -sdForce"}
            if ($useBlockLevelBackup -ne $null){
                if ($useBlockLevelBackup) {
                    $Argument += " -useBlockLevelBackup yes"
                }else{
                    $Argument += " -useBlockLevelBackup no"
                }
            }

            # --------- File-Level ------------
            if ($ntfs -ne $null){
                if ($ntfs) {
                    $Argument += " -ntfs yes"
                }else{
                    $Argument += " -ntfs no"
                }
            }
            if ($ForceUsingVSS -ne $null){
                if ($ForceUsingVSS) {
                    $Argument += " -vss yes"
                }else{
                    $Argument += " -vss no"
                }
            }
            if ($sharerw -ne $null){
                if ($sharerw) {
                    $Argument += " -sharerw yes"
                }else{
                    $Argument += " -sharerw no"
                }
            }
            if ($DeleteLocallyDeletedFilesAfter){$Argument += " -df $DeleteLocallyDeletedFilesAfter"}
            if ($BackupEmptyFolders -ne $null){
                if ($BackupEmptyFolders) {
                    $Argument += " -bef yes"
                }else{
                    $Argument += " -bef no"
                }
            }
            if ($oa){$Argument += " -oa $oa"}
            if ($es -ne $null){
                if ($es) {
                    $Argument += " -es yes"
                }else{
                    $Argument += " -es no"
                }
            }
            if ($SkipFolders){$Argument += " -skipf $SkipFolders"}
            if ($IncludeFilesMask){$Argument += " -ifm $IncludeFilesMask"}
            if ($IgnoreErrorPathNotFound -ne $null){
                if ($IgnoreErrorPathNotFound) {
                    $Argument += " -iepnf yes"
                }else{
                    $Argument += " -iepnf no"
                }
            }
            if ($TrackDeletedFiles -ne $null){
                if ($TrackDeletedFiles) {
                    $Argument += " -trackdeleted yes"
                }else{
                    $Argument += " -trackdeleted no"
                }
            }
            if ($AddNewFile){$Argument += " -af ""$AddNewFile"""}
            if ($AddNewFolder){$Argument += " -ad ""$AddNewFolder"""}
            if ($ExcludeFile){$Argument += " -rf ""$ExcludeFile"""}
            if ($ExcludeDirectory){$Argument += " -rd ""$ExcludeDirectory"""}
            if ($BackupFile){$Argument += " -f ""$BackupFile"""}
            if ($BackupDirectory){$Argument += " -d ""$BackupDirectory"""}
            if ($GenerateDetailedReport -ne $null){
                if ($GenerateDetailedReport) {
                    $Argument += " -dr yes"
                }else{
                    $Argument += " -dr no"
                }
            }
            if ($output){$Argument += " -output $output"}
            if ($MasterPassword){$Argument += " -mp """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MasterPassword)))+""""}

            # ------------- Image-Based -------------

            switch ($BackupVolumes) {
                'AllVolumes' {$Argument += " -av"}
                'SystemRequired' {$Argument += " -r"}
                'SelectedVolumes' {
                    ForEach-Object -InputObject $Volumes -Process {
                        Write-Verbose -Message "Arguments: $Argument"
                        $Argument += " -v $_"
                        Write-Verbose -Message "Arguments: $Argument"
                    }
                }
                Default {}
            }

            if ($disableVSS -ne $null){
                if ($disableVSS) {
                    $Argument += " -disableVSS yes"
                }else{
                    $Argument += " -disableVSS no"
                }
            }
            if ($ignoreBadSectors -ne $null){
                if ($ignoreBadSectors) {
                    $Argument += " -ignoreBadSectors yes"
                }else{
                    $Argument += " -ignoreBadSectors no"
                }
            }
            if ($useSystemVSS -ne $null){
                if ($useSystemVSS) {
                    $Argument += " -useSystemVSS yes"
                }else{
                    $Argument += " -useSystemVSS no"
                }
            }
            if ($prefetchBlockCount){$Argument += " -prefetchBlockCount $prefetchBlockCount"}
            if ($blockSize){$Argument += " -blockSize $blockSize"}
            
            Return $Argument
        }

        if ($CBB = Get-MBSAgent -ErrorAction SilentlyContinue){
            if ($SpecialFunction) {
                if ($_){
                    $BackupPlan = $_
                }else{
                    if($ID){
                        $BackupPlan = Get-MBSBackupPlan | Where-Object {$_.ID -eq $ID}
                    }else{
                        $BackupPlan = Get-MBSBackupPlan | Where-Object {$_.Name -eq $Name}
                    }
                }
                
                switch ($SpecialFunction) {
                    "ExcludeEncryptedFiles" {
                        if ($BackupPlan.Type -eq "Plan") {
                            Write-Host "Searching for encrypted files in plan:" $BackupPlan.Name -ForegroundColor Green
                            $Arguments = "editBackupPlan -id "+$ID
                            if ($MasterPassword) {
                                if ($MasterPassword){$Arguments += " -mp """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MasterPassword)))+""""}
                            }
                            $FoundFlag = $false
                            foreach ($Item in $BackupPlan.Items)
                            {
                                
                                foreach ($File in (get-childitem ($Item) -Recurse -Force -ErrorAction SilentlyContinue | Where-Object {$_.Attributes -ge "Encrypted"}))
                                {
                                    Write-Host "File "$File.FullName "is encrypted and added to exclusion list"
                                    $Arguments += " -rf """+$File.FullName+""""
                                    $FoundFlag = $True
                                }
                                
                            }
                            if ($FoundFlag) {
                                Write-Verbose -Message "Arguments: $Arguments"
                                Start-Process -FilePath $CBB.CBBCLIPath -ArgumentList $Arguments -NoNewWindow -Wait
                            }
                        }else{
                            Write-Host "ExcludeEncryptedFiles option supports only File-Level backup plans."
                        }
                    }
                    "ExcludeTempWindowsAppsFolders" {
                        $versionMinimum = [Version]'3.0'
                        if ($versionMinimum -le $PSVersionTable.PSVersion){
                            if ($BackupPlan.Type -eq "Plan") {
                                $Exclusions = '%USERPROFILE%\AppData\Local\Microsoft\WindowsApps', '%USERPROFILE%\AppData\Local\Packages', '%USERPROFILE%\AppData\Local\Temp'
                                $BackupPlanXml = [xml](Get-Content ($CBB.CBBProgramData+"\"+$BackupPlan.ID+".cbb"))
                                Write-Host "Adding exclusions to plan:" $BackupPlan.Name -ForegroundColor Green
                                foreach($exclusion in $Exclusions){
                                    $element = ((($BackupPlanXml.BasePlan.SelectSingleNode("//ExcludedItems")).AppendChild($BackupPlanXml.CreateElement("PlanItem"))).AppendChild($BackupPlanXml.CreateElement("Path"))).AppendChild($BackupPlanXml.CreateTextNode($exclusion))
                                }
                                Import-Configuration -BackupPlanXml $BackupPlanXml -MasterPassword $MasterPassword
                            }else{
                                Write-Host "ExcludeTempWindowsAppsFolders option supports only File-Level backup plans."
                            }
                        }else{
                            "This script requires PowerShell $versionMinimum. Update PowerShell https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell"
                        }
                    }
                    "ExcludeOneDriveFolders" {
                        $versionMinimum = [Version]'3.0'
                        if ($versionMinimum -le $PSVersionTable.PSVersion){
                            if ($BackupPlan.Type -eq "Plan") {
                                $UserProf = Get-ChildItem -Path Registry::HKEY_USERS -ErrorAction SilentlyContinue | Select-Object Name
                                $OneDrivePathArray = @()
                                $OneDriveRegKeys = @("\Software\Microsoft\OneDrive\Accounts\Business1\ScopeIdToMountPointPathCache","\Software\Microsoft\OneDrive\Accounts\Personal\ScopeIdToMountPointPathCache")
                                $UserProf  | ForEach-Object {
                                    foreach ($OneDriveRegKey in $OneDriveRegKeys) {
                                        if (Test-Path -Path ("Registry::"+$_.Name+$OneDriveRegKey)){
                                            $UserProfile = $_.Name
                                            $OneDriveFolder = Get-Item -Path  ("Registry::"+$UserProfile+$OneDriveRegKey)| Select-Object -ExpandProperty Property 
                                            $OneDriveFolder | Foreach-Object {$OneDrivePathArray +=(Get-ItemProperty -Path ("Registry::"+$UserProfile+$OneDriveRegKey) -Name $_)."$_"}
                                        }
                                    }
                                }
                                
                                $BackupPlanXml = [xml](Get-Content ($CBB.CBBProgramData+"\"+$BackupPlan.ID+".cbb"))
                                Write-Host "Adding exclusions to plan:" $BackupPlan.Name -ForegroundColor Green
                                foreach($exclusion in $OneDrivePathArray){
                                    $element = ((($BackupPlanXml.BasePlan.SelectSingleNode("//ExcludedItems")).AppendChild($BackupPlanXml.CreateElement("PlanItem"))).AppendChild($BackupPlanXml.CreateElement("Path"))).AppendChild($BackupPlanXml.CreateTextNode($exclusion))
                                }
                                Import-Configuration -BackupPlanXml $BackupPlanXml -MasterPassword $MasterPassword
                            }else{
                                Write-Host "ExcludeOneDriveFolders option supports only File-Level backup plans."
                            }
                        }else{
                            "This script requires PowerShell $versionMinimum. Update PowerShell https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell"
                        }
                    }
                    "AddFixedDrivesToIBB" {
                        $versionMinimum = [Version]'3.0'
                        if ($versionMinimum -le $PSVersionTable.PSVersion){
                            if ($BackupPlan.Type -eq "BackupDiskImagePlan") {
                                $BackupPlanXml = [xml](Get-Content ($CBB.CBBProgramData+"\"+$BackupPlan.ID+".cbb"))
                                $BackupPlanXml.BasePlan.BackupVolumes = "SelectedOnly"
                                $BackupPlanXml.BasePlan.DiskInfo.DiskInfoCommunication | ForEach-Object {
                                    if ($_.DriveType -eq "Fixed"){
                                        $_.Enabled = "true"
                                        $_.Volumes.VolumeInfoCommunication | ForEach-Object { $_.Enabled = "true"}
                                    }
                                }
                                $BackupPlanXml.BasePlan.DiskInfo.DiskInfoCommunication | ForEach-Object {
                                    if ($_.DriveType -eq "Removable"){
                                        $_.Enabled = "false"
                                        $_.Volumes.VolumeInfoCommunication | ForEach-Object { $_.Enabled = "false"}
                                    }
                                }
                                Import-Configuration -BackupPlanXml $BackupPlanXml -MasterPassword $MasterPassword
                            }else{
                                Write-Host "AddFixedDrivesToIBB option supports only Image-Based backup plans."
                            }
                        }else{
                            "This script requires PowerShell $versionMinimum. Update PowerShell https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell"
                        }
                    }
                    "AddFixedDrivesToFileLevel" {
                        $versionMinimum = [Version]'3.0'
                        if ($versionMinimum -le $PSVersionTable.PSVersion){
                            if ($BackupPlan.Type -eq "Plan") {
                                Get-WmiObject Win32_LogicalDisk | Foreach {$BackupPlan | Edit-MBSBackupPlan -FileLevelParameterSet -ExcludeDirectory ($_.DeviceID+'\')}
                                Get-WmiObject Win32_LogicalDisk | Where {($_.DriveType -eq 3) -and ($_.VolumeName -notlike 'Google Drive*')} | Foreach {
                                    #if (($_.DeviceID+'\') -notin $BackupPlan.Items){
                                        $BackupPlan | Edit-MBSBackupPlan  -FileLevelParameterSet -AddNewFolder ($_.DeviceID+'\')
                                    #}
                                }
                            }else{
                                Write-Host "AddFixedDrivesToFileLevel option supports only File-Level backup plans."
                            }
                        }else{
                            "This script requires PowerShell $versionMinimum. Update PowerShell https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell"
                        }
                    }
                    "DisablePreAction" {
                        $versionMinimum = [Version]'3.0'
                        if ($versionMinimum -le $PSVersionTable.PSVersion){
                            $BackupPlanXml = [xml](Get-Content ($CBB.CBBProgramData+"\"+$BackupPlan.ID+".cbb"))
                                $BackupPlanXml.BasePlan.Actions.Pre.Enabled = "false"
                                $BackupPlanXml.BasePlan.Actions.Pre.CommandLine = ""
                                $BackupPlanXml.BasePlan.Actions.Pre.Arguments = ""
                                Import-Configuration -BackupPlanXml $BackupPlanXml -MasterPassword $MasterPassword
                        }else{
                            "This script requires PowerShell $versionMinimum. Update PowerShell https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell"
                        }
                    }
                    Default {}
                }
            }else{

                if($_ -ne $null){
                    if($_.Type -eq "Plan" -and $FileLevelParameterSet){
                        $Arguments = " editBackupPlan"
                    }elseif ($_.Type -eq "BackupDiskImagePlan" -and $ImageBasedParameterSet) {
                        $Arguments = " editBackupIBBPlan"
                    }elseif ($CommonParameterSet) {
                        switch ($_.Type) {
                            'Plan' {$Arguments = " editBackupPlan"}
                            'BackupDiskImagePlan' {$Arguments = " editBackupIBBPlan"}
                            Default {
                                Write-host "$_ type is not supported by the Cmdlet" -ForegroundColor Red
                                return 
                            }
                        }
                    }else{
                        Write-host "Backup plan """($_.Name)""" is skipped" -ForegroundColor Red 
                        return 
                    }
                }else{
                    if ($FileLevelParameterSet) {
                        $Arguments = " editBackupPlan"
                    }elseif ($ImageBasedParameterSet) {
                        Write-Verbose -Message "Arguments: $Arguments"
                        $Arguments = " editBackupIBBPlan"
                        Write-Verbose -Message "Arguments: $Arguments"
                    }
                }
                
            
                if ($ID){
                    $Arguments += " -id $ID"
                    $Arguments += Set-Arguments  # -Arguments $Arguments
                }else{
                    $Arguments += " -n ""$Name"""
                    $Arguments += Set-Arguments #($Arguments)
                }
                Write-Verbose -Message "Arguments: $Arguments"
                Start-Process -FilePath $CBB.CBBCLIPath -ArgumentList $Arguments  -Wait -NoNewWindow #-WindowStyle Hidden
            }
        }
    }
    
    end {
    }
}

function Start-MBSBackupPlan {
    <#
    .SYNOPSIS
        Run backup plans.
    .DESCRIPTION
        Run backup plans.
    .EXAMPLE
        PS C:\> Start-MBSBackupPlan -Name "Backup VMware"
        Start backup plan by name.
    .EXAMPLE
        PS C:\> Start-MBSBackupPlan -ID ed2e0d37-5ec2-49e1-a381-d2246b3108ec
        Start backup plan by the plan ID.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType Local -PlanType VMware | Start-MBSBackupPlan
        Start VMware backup plans with local backup storages type.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType All -PlanType VMware | Start-MBSBackupPlan
        Start VMware backup plans with all backup storages type.
    .EXAMPLE
        PS C:\>Start-MBSBackupPlan -ID 3a2fde55-9ecd-4940-a75c-d1499b43abda -ForceFull -ForceFullDayOfWeek Friday, Monday
        Run force full on specific day of the week.
    .INPUTS
        System.String[]
        System.String
    .OUTPUTS
        System.String[]
    #>


    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $ID,
        #
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $Name,
        #
        [switch]
        $ForceFull,
        #
        [ValidateSet("Monday", "Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [string[]]
        $ForceFullDayOfWeek,
        #
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)")]
        [SecureString]
        $MasterPassword
    )
    
    begin {
        $CBB = Get-MBSAgent
    }
    
    process {
        if (Get-MBSAgent -ErrorAction SilentlyContinue) {        
            if ($ID){
                $Arguments += "plan -r $ID"
            }else{
                $Arguments += "plan -r ""$Name"""
            }
            
            if($ForceFull){
                if ($ForceFullDayOfWeek){
                    if((get-date).DayOfWeek -in $ForceFullDayOfWeek){
                        $Arguments += " -ForceFull"
                    }
                }else {
                    $Arguments += " -ForceFull"
                }
            }
            if ($MasterPassword){$Arguments += " -mp """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MasterPassword)))+""""}

            Write-Verbose -Message "Arguments: $Arguments"
            Start-Process -FilePath $CBB.CBBCLIPath -ArgumentList $Arguments -NoNewWindow -Wait
        }
    }
    
    end {
    }
}

function Stop-MBSBackupPlan {
    <#
    .SYNOPSIS
        Stop running backup plans.
    .DESCRIPTION
        The Stop-MBSBackupPlan cmdlet stop a backup plan with specified ID or Name.
    .EXAMPLE
        PS C:\> Stop-MBSBackupPlan -Name "Backup VMware"
        Stop running backup plan by name.
    .EXAMPLE
        PS C:\> Stop-MBSBackupPlan -ID ed2e0d37-5ec2-49e1-a381-d2246b3108ec
        Stop running backup plan by the plan ID.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType Local -PlanType VMware | Stop-MBSBackupPlan
        Stop running VMware backup plans with local backup storages type.
    .EXAMPLE
        PS C:\> Get-MBSBackupPlan -StorageType All -PlanType VMware | Stop-MBSBackupPlan
        Stop running VMware backup plans with all backup storages type.
    .INPUTS
        System.String[]
        System.String
    .OUTPUTS
        System.String[]
    #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $ID,
        #
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $Name,
        #
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)")]
        [SecureString]
        $MasterPassword
    )
    
    begin {
        $CBB = Get-MBSAgent
    }
    
    process {
        if (Get-MBSAgent -ErrorAction SilentlyContinue) {
            if ($ID){
                $Arguments += "plan -s $ID"
            }else{
                $Arguments += "plan -s ""$Name"""
            }
            if ($MasterPassword){$Arguments += " -mp """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MasterPassword)))+""""}

            Write-Verbose -Message "Arguments: $Arguments"
            Start-Process -FilePath $CBB.CBBCLIPath -ArgumentList $Arguments -NoNewWindow -Wait
            Start-Process -FilePath $CBB.CBBCLIPath -ArgumentList $Arguments -NoNewWindow -Wait
        }
    }
    
    end {
    }
}

function Get-MBSAgentSettings {
    <#
    .SYNOPSIS
        Get MBS agent settings.
    .DESCRIPTION
        The Get-MBSAgentSettings cmdlet returns PS custom object with MBS agent settings.
    .EXAMPLE
        PS C\:> Get-MBSAgentSettings
        Get MBS agent settings.
    .INPUTS
        None
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    #>

    [CmdletBinding()]
    param (
        
    )
    
    begin {
        
    }
    
    process {
        if (Get-MBSAgent -ErrorAction SilentlyContinue) {
            $CBBProgramData = (Get-MBSAgent).CBBProgramData
            $StorageAccountsArray = @()
            $enginesettings = [xml](Get-Content ("$CBBProgramData\enginesettings.list"))

            $MBSAgentSettings  = New-Object -TypeName psobject
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name MBSUser -Value $enginesettings.EngineSettings.MBSUser
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name MBSFolderPath -Value $enginesettings.EngineSettings.MBSFolderPath
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name EngineVersion -Value $enginesettings.EngineSettings.EngineVersion
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name LogFolder -Value $enginesettings.EngineSettings.LogFolder
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name LoggingLevel -Value $enginesettings.EngineSettings.LoggingLevel
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name MSSQLAlternativeFolder -Value $enginesettings.EngineSettings.MSSQLAlternativeFolder
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name MaximumSimultaneousTransfers -Value $enginesettings.EngineSettings.MaximumSimultaneousTransfers
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name Priority -Value $enginesettings.EngineSettings.Priority
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name DefaultRetentionNumberOfHistoryRecords -Value $enginesettings.EngineSettings.DefaultRetentionNumberOfHistoryRecords
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name PreventSleepMode -Value $enginesettings.EngineSettings.PreventSleepMode
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name CheckFileConsistency -Value $enginesettings.EngineSettings.CheckFileConsistency
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name RetryAttempts -Value $enginesettings.EngineSettings.RetryAttempts
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name RetryInterval -Value $enginesettings.EngineSettings.RetryInterval
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name ChunkSizeKB -Value $enginesettings.EngineSettings.ChunkSizeKB
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name DisableAutoUpdate -Value $enginesettings.EngineSettings.DisableAutoUpdate
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name DefaultRetentionNumberOfVersions -Value $enginesettings.EngineSettings.DefaultRetentionNumberOfVersions
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name DefaultRetentionUseBackupDate -Value $enginesettings.EngineSettings.DefaultRetentionUseBackupDate
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name DefaultRetentionDeleteLastVersion -Value $enginesettings.EngineSettings.DefaultRetentionDeleteLastVersion
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name UseMasterPasswordForCLI -Value $enginesettings.EngineSettings.UseMasterPasswordForCLI


            $Bandwidth  = New-Object -TypeName psobject
            $Bandwidth | Add-Member -MemberType NoteProperty -Name BandwidthLimitEnabled -Value $enginesettings.EngineSettings.Bandwidth.BandwidthLimitEnabled
            $Bandwidth | Add-Member -MemberType NoteProperty -Name BandwidthLimit -Value $enginesettings.EngineSettings.Bandwidth.BandwidthLimit
            $Bandwidth | Add-Member -MemberType NoteProperty -Name BandwidthLocalLimitEnabled -Value $enginesettings.EngineSettings.Bandwidth.BandwidthLocalLimitEnabled
            $Bandwidth | Add-Member -MemberType NoteProperty -Name BandwidthLocalLimit -Value $enginesettings.EngineSettings.Bandwidth.BandwidthLocalLimit
            if($enginesettings.EngineSettings.UseBandwidthSchedule -eq "true"){
                $BandwidthSchedule  = New-Object -TypeName psobject
                $DayOfWeek = @()
                $enginesettings.EngineSettings.BandwidthSchedule.BandwidthSchedule.WeekDays | ForEach-Object {
                    $DayOfWeek += $_.DayOfWeek
                }
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name WeekDays -Value $DayOfWeek
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name DayStartTime -Value $DayStartTime
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name DayFinishTime -Value $DayFinishTime
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name BandwidthLimitEnabled -Value $enginesettings.EngineSettings.BandwidthSchedule.BandwidthSchedule.BandwidthLimitEnabled
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name BandwidthLimit -Value $enginesettings.EngineSettings.BandwidthSchedule.BandwidthSchedule.BandwidthLimit
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name BandwidthLocalLimitEnabled -Value $enginesettings.EngineSettings.BandwidthSchedule.BandwidthSchedule.BandwidthLocalLimitEnabled
                $BandwidthSchedule | Add-Member -MemberType NoteProperty -Name BandwidthLocalLimit -Value $enginesettings.EngineSettings.BandwidthSchedule.BandwidthSchedule.BandwidthLocalLimit
                $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name BandwidthSchedule -Value $BandwidthSchedule
            }
            $MBSAgentSettings | Add-Member -MemberType NoteProperty -Name Bandwidth -Value $Bandwidth
            
            return $MBSAgentSettings
        
        }
    }
    
    end {
        
    }
}

function Set-MBSAgentSettings {
    <#
    .SYNOPSIS
        Change MBS backup agent options.
    .DESCRIPTION
        Change MBS backup agent options.
    .EXAMPLE
        PS C:\> Set-MBSAgentSettings -ThreadCount 10
        Set thread count to 10.
    .EXAMPLE
        PS C:\> Set-MBSAgentSettings -Keep 5 -Logging high
        Change default retention policy to keep 5 versions and set logging level to high.
    .INPUTS
        None
    .OUTPUTS
        System.String[]
    .NOTES
     
    #>

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify backup agent edition.")]
        [ValidateSet("desktop", "baremetal", "mssql", "msexchange", "mssqlexchange", "ultimate", "vmedition")]
        [String]
        $Edition,
        #
        [Parameter(Mandatory=$False, HelpMessage="Bandwidth for a plan. Possible values: u(unlimited), value in kB")]
        [String]
        $Bandwidth,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy type. Possible values: no, auto, manual")]
        [ValidateSet("no", "auto","manual")]
        [String]
        $Proxy,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy address")]
        [String]
        $ProxyAddress,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy port")]
        [Int32][ValidateRange(1,65535)]
        $ProxyPort,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy authentication.")]
        [Nullable[boolean]]
        $ProxyAuthentication,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy domain")]
        [String]
        $ProxyDomain,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy user")]
        [String]
        $ProxyUser,
        #
        [Parameter(Mandatory=$False, HelpMessage="Proxy password")]
        [String]
        $ProxyPassword,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify chunk size in KBs. Possible values: 1024-5242880")]
        [Int32][ValidateRange(1024,5242880)]
        $ChunkSize,
        #
        [Parameter(Mandatory=$False, HelpMessage="Thread count. Possible values: 1-99")]
        [Int32][ValidateRange(1,99)]
        $ThreadCount,
        #
        [Parameter(Mandatory=$False, HelpMessage="Purge versions that are older than period (except lastest version). Possible values: no, 1d(day), 1w(week), 1m(month)")]
        [String]
        $Purge,
        #
        [Parameter(Mandatory=$False, HelpMessage="Specify purge delay. Possible values: no, 1d(day), 1w(week), 1m(month)")]
        [String]
        $DelayPurge,
        #
        [Parameter(Mandatory=$False, HelpMessage="Keep limited number of versions. Possible values: all, number")]
        [String]
        $Keep,
        #
        [Parameter(Mandatory=$False, HelpMessage="Purge history records that are older than value. Possible values: no, 1d(day), 1w(week), 1m(month)")]
        [String]
        $HistoryPurge,
        #
        [Parameter(Mandatory=$False, HelpMessage="Keep limited number of records in history. Possible values: all, number")]
        [String]
        $HistoryLimit,
        #
        [Parameter(Mandatory=$False, HelpMessage="Logging level.")]
        [ValidateSet("no", "low","high","debug")]
        [String]
        $Logging,
        #
        [Parameter(Mandatory=$False, HelpMessage="Change database location. By default database is located in user profile. Database will be moved to specified directory for saving space on system drive or other reasons.")]
        [Alias("DatabaseLocation")]
        [String]
        $RepositoryLocation,
        #
        [Parameter(Mandatory=$False, HelpMessage="Ignore SSL validation.")]
        [Nullable[boolean]]
        $IgnoreSSLValidation,
        #
        [Parameter(Mandatory=$False, HelpMessage="Output format. Possible values: short, full(default)")]
        [ValidateSet("short", "full")]
        [String]
        $Output,
        #
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)")]
        [SecureString]
        $MasterPassword
        
    )
    
    begin {
    }
    
    process {
        if (Get-MBSAgent -ErrorAction SilentlyContinue) {
            $CBB = Get-MBSAgent 
            $Arguments = " option"
            
            if ($Edition){$Arguments += " -edition $Edition"}
            if ($Bandwidth){$Arguments += " -bandwidth $Bandwidth"}
            if ($Proxy){$Arguments += " -proxy $Proxy"}
            if ($ProxyAddress){$Arguments += " -pa $ProxyAddress"}
            if ($ProxyPort){$Arguments += " -pp $ProxyPort"}
            if ($ProxyAuthentication){$Arguments += " -pt $ProxyAuthentication"}
            if ($ProxyDomain){$Arguments += " -pd $ProxyDomain"}
            if ($ProxyUser){$Arguments += " -pu $ProxyUser"}
            if ($ProxyPassword){$Arguments += " -ps $ProxyPassword"}
            if ($ChunkSize){$Arguments += " -cs $ChunkSize"}
            if ($ThreadCount){$Arguments += " -threads $ThreadCount"}
            if ($Purge){$Arguments += " -purge $Purge"}
            if ($DelayPurge){$Arguments += " -delayPurge $DelayPurge"}
            if ($Keep){$Arguments += " -keep $Keep"}
            if ($HistoryPurge){$Arguments += " -hp $HistoryPurge"}
            if ($HistoryLimit){$Arguments += " -hk $HistoryLimit"}
            if ($Logging){$Arguments += " -logging $Logging"}

            if ($RepositoryLocation){$Arguments += " -repositoryLocation $RepositoryLocation"}
            if ($IgnoreSSLValidation -ne $null){
                if ($IgnoreSSLValidation) {
                    $Arguments += " -ignoreSSLValidation yes"
                }else{
                    $Arguments += " -ignoreSSLValidation no"
                }
            }
            if ($output){$Arguments += " -output $output"}
            if ($MasterPassword){$Arguments += " -mp """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MasterPassword)))+""""}
            Write-Verbose -Message "Arguments: $Arguments"
            Start-Process -FilePath $CBB.CBBCLIPath -ArgumentList $Arguments -NoNewWindow -Wait
        }
    }
    
    end {
    }
}

#----------------- Internal Functions ----------------------
function Confirm-MBSAction {
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$True)]
        [String]
        $Operation,
        #
        [Parameter(Mandatory=$True)]
        [String]
        $Target
    )
    
    begin {
        
    }
    
    process {
        Write-Host "Are you sure you want to perform this action?"
        Write-Host "Performing the operation ""$Operation"" on target ""$Target"""
        Write-Host "[Y] Yes [N] No (default is ""N""):" -NoNewline
        $Input = Read-Host 
        if ($Input -eq "Y" -or $Input -eq "y" ){
            return $true
        }else{
            return $false
        }
    }
    
    end {
        
    }
}

#----------------- MBS Utils -------------------------------

function Test-MBSConnection {
    <#
    .SYNOPSIS
        TCP port connection test to MBS servers
    .DESCRIPTION
        TCP port connection test to MBS servers
    .EXAMPLE
        PS C:\> Test-MBSConnection
 
        Running connection test to MBS. It will take up to 5 minutes. Please wait...
        Testing connection to 52.6.7.137 : 443 : OK
        Testing connection to 52.5.40.159 : 443 : OK
        Testing connection to 52.20.40.101 : 443 : OK
        Testing connection to 3.216.171.162 : 443 : OK
        Testing connection to 3.216.236.203 : 443 : OK
        Connection test is completed
    .INPUTS
        None
    .OUTPUTS
        System.String[]
    .NOTES
        Connection test allows you to check connection from your computer to MBS servers. Connection failing indicates firewall misconfiguration.
    #>


    [CmdletBinding()]
    param (
        
    )

    begin {
        $MBSServers = @( 
            ("52.6.7.137","443"),
            ("52.5.40.159","443"),
            ("52.20.40.101","443"),
            ("3.216.171.162","443"),
            ("3.216.236.203","443")
        )

        Write-Host "Running connection test to MBS. It will take up to 5 minutes. Please wait..." 
        Write-HostAndLog -Message "*********************************$env:computername************************" -FilePath tnc.txt -showMessage $False
    }
    
    process {
        function Check-MBSConnectionTestResult ($MBSServer) {
            Write-Host "Testing connection to " $MBSServer[0]":"$MBSServer[1]": " -NoNewline
            $Result = Test-NetConnection $MBSServer[0] -Port $MBSServer[1]
            if ($Result.TcpTestSucceeded){
                Write-Host "OK" -ForegroundColor Green
            } 
            else {
                Write-Host "Fail" -ForegroundColor Red
            }
            Write-HostAndLog -Message $Result -FilePath tnc.txt -showMessage $False
        }
        foreach ($MBSServer in $MBSServers) {
            Check-MBSConnectionTestResult ($MBSServer)
        }
    }
    
    end {
        Write-Host "Connection test is completed"
    }
}

function Import-Configuration {
    [CmdletBinding()]
    param (
        [xml]$BackupPlanXml,
        [Parameter(Mandatory=$False, HelpMessage="Master password. Should be specified if configuration is protected by master password. Use -MasterPassword (ConvertTo-SecureString -string ""Your_Password"" -AsPlainText -Force)")]
        [SecureString]
        $MasterPassword
    )
    
    begin {
        
    }
    
    process {
        $TempFolder = New-Item -Path "$env:TMP" -Name $BackupPlanXml.BasePlan.ID -ItemType "directory" -ErrorAction SilentlyContinue
        $BackupPlanFolder = $env:TMP+"\"+$BackupPlanXml.BasePlan.ID
        $BackupPlanPath = $env:TMP+"\"+$BackupPlanXml.BasePlan.ID+"\"+$BackupPlanXml.BasePlan.ID+".cbb"
        $BackupPlanConfiguration = $env:TMP+"\"+$BackupPlanXml.BasePlan.ID+".cbbconfiguration"
        $Arguments = "importConfig -f "+$BackupPlanConfiguration
        if ($MasterPassword) {
            if ($MasterPassword){$Arguments += " -mp """+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MasterPassword)))+""""}
        }
        $BackupPlanXml.Save($BackupPlanPath)
        Add-Type -Assembly System.IO.Compression.FileSystem
        [System.IO.Compression.ZipFile]::CreateFromDirectory($BackupPlanFolder,
        $BackupPlanConfiguration, [System.IO.Compression.CompressionLevel]::Optimal, $false)
        Write-Verbose -Message "Arguments: $Arguments"
        $ProcessOutput = Start-Process -FilePath (Get-MBSAgent).CBBCLIPath -ArgumentList $Arguments -NoNewWindow -Wait 
        Remove-Item -Path $BackupPlanFolder -Force -Recurse
        Remove-Item -Path $BackupPlanConfiguration -Force -Recurse
    }
    
    end {
        
    }
}

Function Add-MBSFirewallRules {
    <#
    .SYNOPSIS
        Create Firewall rules in Windows for the backup agent (version 0.3)
    .DESCRIPTION
        Checks and creates Firewall rules for backup agent executables to allow inbound and outbound internet connection to storages, MBS portal, etc.
    .EXAMPLE
        Add-MBSFirewallRules
    .INPUTS
        None.
    .OUTPUTS
        None.
    .NOTES
        None.
    #>

    
    [CmdletBinding()]
    param (

    )
    $RulesAddedResult = ProcessMBSFirewallRules -Action "Add"
    If ($RulesAddedResult[0]) {
        $RulesPresent = $RulesAddedResult[2]
        $RulesAddedSuccessfully = $RulesAddedResult[1]
        If ($RulesPresent -ne 0) {
            Write-Host "Firewall rules present - $RulesPresent"
        }
        Write-Host $(If ($RulesAddedSuccessfully -ne 0) {"Firewall rules added successfully - $RulesAddedSuccessfully"} Else {"No new rules created."})
    }
    Else {
        Write-Error $RulesAddedResult[1]
        return
    }
}

Function Remove-MBSFirewallRules {
    <#
    .SYNOPSIS
        Removes Firewall rules in Windows for the backup agent (version 0.2)
    .DESCRIPTION
        Removes previously created (by script or manually) Firewall rules for backup agent executables.
    .EXAMPLE
        Remove-MBSFirewallRules
    .INPUTS
        None.
    .OUTPUTS
        None.
    .NOTES
        None.
    #>

    
    [CmdletBinding()]
    param (

    )
    $RulesRemovedResult = ProcessMBSFirewallRules -Action "Remove"
    If ($RulesRemovedResult[0]) {
        $RulesDeletedSuccessfully = $RulesRemovedResult[1]
        Write-Host $(If ($RulesDeletedSuccessfully -ne 0) {"Firewall rules removed successfully - $RulesDeletedSuccessfully"} Else {"No rules to delete."})
    }
    Else {
        Write-Error $RulesRemovedResult[1]
        return
    }
}

function ProcessMBSFirewallRules {
    Param (
        [Parameter(Mandatory=$true)]
        [string]$Action
    )

    $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
    $IsAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

    if ($IsAdmin) {
        if ($CBB = Get-MBSAgent -ErrorAction SilentlyContinue) {
            $CBBPath = $CBB.CBBPath
            $Exec = $CBB.CBBName,"CBBackupPlan","Cloud.Backup.Scheduler","Cloud.Backup.RM.Service","cbb"
            $Directions = "In","Out"
            $FirewallRules = (New-object -ComObject HNetCfg.FwPolicy2).rules
            $RulesPresent = 0
            $RulesProcessedSuccessfully = 0
            foreach ($ExecValue in $Exec)
            {
                foreach ($DirectionValue in $Directions)
                {
                    $CurrentRulePresent=$false
                    $CurrentRuleName=""
                    $DirectionID = $(If ($DirectionValue -eq "In") {1} ElseIf ($DirectionValue -eq "Out") {2})
                    foreach ($Rule in $FirewallRules) {
                        if (($Rule.ApplicationName -eq "$CBBPath\$ExecValue.exe") -And ($Rule.Direction -eq $DirectionID)) {
                            $RulesPresent++
                            $CurrentRulePresent=$true
                            $CurrentRuleName=$Rule.Name
                            break
                        }
                    }
                    try {
                        if (($CurrentRulePresent) -And ($Action -eq "Remove")) {
                            NetSH AdvFirewall Firewall Delete Rule Name=$CurrentRuleName Dir=$DirectionValue | Out-Null
                            if ($LASTEXITCODE -eq 0) {
                                $RulesProcessedSuccessfully++
                            }
                            else {
                                throw $LASTEXITCODE
                            }
                        }
                        ElseIf ((!$CurrentRulePresent) -And ($Action -eq "Add")) {
                            NetSH AdvFirewall Firewall Add Rule Name="Online Backup - $ExecValue" Program="$CBBPath\$ExecValue.exe" Dir=$DirectionValue Action=Allow Enable=Yes | Out-Null
                            if ($LASTEXITCODE -eq 0) {
                                $RulesProcessedSuccessfully++
                            }
                            else {
                                throw $LASTEXITCODE
                            }
                        }
                    }
                    catch {
                        $description = "ERROR: An error occured - not all Firewall rules have been processed. Exitcode = $LASTEXITCODE"
                        return $false,$description
                    }
                }
            }
        }
        else {
            $description = "ERROR: MSP360 Online backup agent is not installed on this machine."
            return $false,$description
        }
    }
    else {
        $description = "ERROR: Processing Firewall rules requires administrator rights."
        return $false,$description
    }
    return $true,$RulesProcessedSuccessfully,$RulesPresent
}

function Add-WFUMonitoringJob {
    <#
    .SYNOPSIS
        Add status monitoring task to windows task scheduler for Windows Firewall, Windows Defender, Third party antivirus, and Windows Update Services.
    .DESCRIPTION
        Admin permissions are required.
    .EXAMPLE
        Add monitoring task with default options. Specify mandatory parameters only.
 
        PS C:\> .\Add-WFUMonitoringJob.ps1 `
        -JobUserName "Domain\MyUser" `
        -JobUserPwd 'MyUserPassword' `
        -MessageFrom "My_email@gmail.com" `
        -MessageTo "My_email@gmail.com" `
        -MessageSMTPServer "smtp.gmail.com" `
        -MessagePort 587 `
        -MessageUseSSL $true `
        -MessageUserName "My_email@gmail.com" `
        -MessageCredsPassword 'MyEmailPassword'
    .EXAMPLE
        Add monitoring task for Windows Firewall, Windows Defender and Windows Update services only.
 
        PS C:\> .\Add-WFUMonitoringJob.ps1 `
        -JobName "Monitoring Windows Security services" `
        -JobUserName "domain\user" `
        -JobUserPwd 'MyUserPassword' `
        -MessageFrom "My_email@gmail.com" `
        -MessageTo "My_Email@gmail.com" `
        -MessageSubject "Security Alert" `
        -MessageSMTPServer smtp.gmail.com `
        -MessagePort 587 `
        -MessageUseSSL $true `
        -MessageUserName "My_email@gmail.com" `
        -MessageCredsPassword 'MyEmailPassword' `
        -IsFirewallMonitored $true `
        -IsWindowsDefenderMonitored $true `
        -Is3PartyAntivirusMonitored $False `
        -IsWindowsUpdateMonitored $True `
        -WindowsUpdateNotificationLevel 3 `
        -MonitoringJobSchedule (New-ScheduledTaskTrigger -At 07:00:00 -Daily)
    .INPUTS
        None
    .OUTPUTS
        Microsoft.Management.Infrastructure.CimInstance#Root/Microsoft/Windows/TaskScheduler/MSFT_ScheduledTask
    #>

    [CmdletBinding()]
    param (
        # Task scheduler monitoring job name
        [Parameter(Mandatory=$False)]
        [string]$JobName = "Monitor Windows Security services" ,
        # Local admin username.
        [Parameter(Mandatory=$True)]
        [string]$JobUserName,
        # Local admin password
        [Parameter(Mandatory=$True)]
        [string]$JobUserPwd,
        # Sender email address
        [Parameter(Mandatory=$True)]
        [string]$MessageFrom,
        # Recepient email address
        [Parameter(Mandatory=$True)]
        [string]$MessageTo,
        # Email subject
        [Parameter(Mandatory=$False)]
        [string]$MessageSubject = "Security Alert",
        # SMTP server address
        [Parameter(Mandatory=$True)]
        [string]$MessageSMTPServer,
        # SMTP server port
        [Parameter(Mandatory=$True)]
        [int32]$MessagePort,
        # Use SSL?
        [Parameter(Mandatory=$True)]
        [bool]$MessageUseSSL,
        # SMTP server user
        [Parameter(Mandatory=$True)]
        [string]$MessageUserName,
        # SMTP server user password
        [Parameter(Mandatory=$True)]
        [string]$MessageCredsPassword,
        # Set $true to monitor Firewall settings or $false to skip
        [Parameter(Mandatory=$False)]
        [bool]$IsFirewallMonitored = $true,
        # Set $true to monitor Windows Defender settings or $false to skip
        [Parameter(Mandatory=$False)]
        [bool]$IsWindowsDefenderMonitored = $true,
        # Set $true to monitor 3 party antivirus settings or $false to skip
        [Parameter(Mandatory=$False)]
        [bool]$Is3PartyAntivirusMonitored = $true,
        # Set $true to monitor Windows Update service or $false to skip
        [Parameter(Mandatory=$False)]
        [bool]$IsWindowsUpdateMonitored = $true,
        # Sends email if notification level equal or less than the specified number. {0='Not configured'; 1='Never check for updates' ; 2='Check for updates but let me choose whether to download and install them'; 3='Download updates but let me choose whether to install them'; 4='Install updates automatically'}
        [Parameter(Mandatory=$False)]
        [int32]$WindowsUpdateNotificationLevel = 3,
        # Get more about task trigger https://docs.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtasktrigger
        [Parameter(Mandatory=$False)]
        $MonitoringJobSchedule = (New-ScheduledTaskTrigger -At 07:00:00 -Daily)
    )

    
    begin {
        
    }
    
    process {
        $MessageCredsPassword = $MessageCredsPassword | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString
        $Script = "
        `$MessagePwd = '$MessageCredsPassword' | ConvertTo-SecureString
        `$MessageCreds = New-Object System.Management.Automation.PSCredential -ArgumentList $MessageUserName, `$MessagePwd
        `$AutoUpdateNotificationLevels= @{0='Not configured'; 1='Never check for updates' ; 2='Check for updates but let me choose whether to download and install them'; 3='Download updates but let me choose whether to install them'; 4='Install updates automatically'}
        `$FirewallStatus = Get-NetFirewallProfile | Select -property Name, Enabled
        try {`$AVStatus = Get-MpComputerStatus | select -Property RealTimeProtectionEnabled, OnAccessProtectionEnabled, NISEnabled, IoavProtectionEnabled, BehaviorMonitorEnabled, AntivirusEnabled, AntispywareEnabled}
            catch { `$NoAntivirusDetected = `$true }
        try{`$AV3PartyStatus = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | where {`$_.displayName -ne 'Windows Defender'};`$AV3PartyProductState = '{0:x}' -f `$AV3PartyStatus.productState}
            catch{`$No3PartyAntivirusDetected = `$true }
 
        `$AVStatus = Get-MpComputerStatus | select -Property RealTimeProtectionEnabled, OnAccessProtectionEnabled, NISEnabled, IoavProtectionEnabled, BehaviorMonitorEnabled, AntivirusEnabled, AntispywareEnabled
        `$WUStatus = get-service wuauserv | select -Property name, starttype, status
        `$WUStatusLevel = (New-Object -com 'Microsoft.Update.AutoUpdate').Settings.NotificationLevel
 
        if ((`$$IsFirewallMonitored -and (-not `$FirewallStatus[0].Enabled)) -or (`$$IsFirewallMonitored -and (-not `$FirewallStatus[1].Enabled)) -or (`$$IsFirewallMonitored -and (-not `$FirewallStatus[2].Enabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.RealTimeProtectionEnabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.OnAccessProtectionEnabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.NISEnabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.IoavProtectionEnabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.BehaviorMonitorEnabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.AntivirusEnabled)) -or (`$$IsWindowsDefenderMonitored -and (-not `$AVStatus.AntispywareEnabled)) -or (`$$IsWindowsUpdateMonitored -and (-not(`$WUStatus.StartType -ne 'Disabled'))) -or (`$$IsWindowsUpdateMonitored -and (-not(`$WUStatusLevel -gt $WindowsUpdateNotificationLevel))) -or (`$$Is3PartyAntivirusMonitored -and (-not(`$AV3PartyProductState[`$AV3PartyProductState.length - 4] -ne '1'))) -or (`$$Is3PartyAntivirusMonitored -and (-not(`$AV3PartyProductState[`$AV3PartyProductState.length - 2] -ne '0')))){
            if(`$$IsFirewallMonitored){
                `$MessageBody = ""<H3>Windows Firewall Profile Status</H3>""
                if(`$FirewallStatus[0].Enabled){`$MessageBody += ""<b>Domain: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>Domain: </b><font color=red>Disabled</font><br>""}
                if(`$FirewallStatus[1].Enabled){`$MessageBody += ""<b>Private: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>Private: </b><font color=red>Disabled</font><br>""}
                if(`$FirewallStatus[2].Enabled){`$MessageBody += ""<b>Public: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>Public: </b><font color=red>Disabled</font><br>""}
 
            }
            if(`$$IsWindowsDefenderMonitored){
                `$MessageBody += ""<H3>Windows Defender Protection Status</H3>""
                if(-not (`$NoAntivirusDetected)){
                    if(`$AVStatus.RealTimeProtectionEnabled){`$MessageBody += ""<b>RealTimeProtection: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>RealTimeProtection: </b><font color=red>Disabled</font><br>""}
                    if(`$AVStatus.OnAccessProtectionEnabled){`$MessageBody += ""<b>OnAccessProtection: </b><font color=green>Enabled</font><br>""}else{`$MessageBody += ""<b>OnAccessProtection: </b><font color=red>Disabled</font><br>""}
                    if(`$AVStatus.NISEnabled){`$MessageBody += ""<b>NIS: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>NIS: </b><font color=red>Disabled</font><br>""}
                    if(`$AVStatus.IoavProtectionEnabled){`$MessageBody += ""<b>IoavProtection: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>IoavProtection: </b><font color=red>Disabled</font><br>""}
                    if(`$AVStatus.BehaviorMonitorEnabled){`$MessageBody += ""<b>BehaviorMonitor: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>BehaviorMonitor: </b><font color=red>Disabled</font><br>""}
                    if(`$AVStatus.AntivirusEnabled){`$MessageBody += ""<b>Antivirus: </b><font color=green>Enabled</font><br>""}else{`$MessageBody +=""<b>Antivirus: </b><font color=red>Disabled</font><br>""}
                    if(`$AVStatus.AntispywareEnabled){`$MessageBody += ""<b>Antispyware: </b><font color=green>Enabled</font><br>""}else{`$MessageBody += ""<b>Antispyware: </b><font color=red>Disabled</font><br>""}
                }else{
                    `$MessageBody += ""<b>No Antivirus detected</b>""
                }
            }
            if(`$$Is3PartyAntivirusMonitored){
                 
                if(`$AV3PartyStatus){
                    `$MessageBody += ""<H3>""+`$AV3PartyStatus.displayName+"" Protection Status</H3>""
                    if(`$AV3PartyProductState[`$AV3PartyProductState.length - 4] -eq '1'){`$MessageBody += ""<b>Antivirus status: </b><font color=green>Enabled</font><br>""}else{`$MessageBody += ""<b>Antivirus: </b><font color=red>Disabled</font><br>""}
                    if(`$AV3PartyProductState[`$AV3PartyProductState.length - 2] -eq '0'){`$MessageBody += ""<b>Antivirus databases: </b><font color=green>Up to date</font><br>""}else{`$MessageBody += ""<b>Antivirus databases: </b><font color=red>Outdated</font><br>""}
                }else{
                    `$MessageBody += ""<H3>Third Party Antivirus Protection Status</H3>""
                    `$MessageBody += ""<b>No Antivirus detected</b>""
                }
            }
            if(`$$IsWindowsUpdateMonitored ){
                `$MessageBody += ""<H3>Windows Update Service Status</H3>""
                if(`$WUStatus.starttype -ne 'Disabled'){`$MessageBody += ""<b>Start type: </b><font color=green>""+`$WUStatus.starttype+""</font><br>""}else{`$MessageBody +=""<b>Start type: </b><font color=red>Disabled</font><br>""}
                if(`$WUStatusLevel -gt $WindowsUpdateNotificationLevel){`$MessageBody += ""<b>Notification Level: </b><font color=green>""+`$AutoUpdateNotificationLevels[`$WUStatusLevel]+""</font><br>""}else{`$MessageBody +=""<b>Notification Level: </b><font color=red>""+`$AutoUpdateNotificationLevels[`$WUStatusLevel]+""</font><br>""}
            }
             
            Send-MailMessage -From "
+$MessageFrom+" -To "+$MessageTo+" -Subject ""`$env:computername $MessageSubject"" -Body `$MessageBody -SmtpServer "+$MessageSMTPServer+" -UseSsl:$"+$MessageUseSSL+" -Port "+$MessagePort+" -Credential `$MessageCreds -BodyAsHtml}"

        $encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Script))
        $action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument "-NoProfile -WindowStyle Hidden -encodedCommand $encoded"
        if(Get-ScheduledTask -TaskName $JobName -ErrorAction SilentlyContinue) {Unregister-ScheduledTask -TaskName $JobName -Confirm:$false}
        Register-ScheduledTask -Action $action -Trigger $MonitoringJobSchedule -TaskName $JobName -User $JobUserName -password $JobUserPwd
    }
    
    end {
        
    }
}

#----------------- MBS API ---------------------------------
function Set-MBSAPICredential {
    <#
    .SYNOPSIS
    Saves MBS API credentials
 
    .DESCRIPTION
    Saves provided credentials to temp variable or local profile.
     
    .PARAMETER UserName
    API Login name. Generate new one on https://mspbackups.com/Admin/Settings.aspx
     
    .PARAMETER Password
    API Password. Generate new one on https://mspbackups.com/Admin/Settings.aspx
     
    .PARAMETER StoreAs
    Profile name. Specify to save credentials securely to local file. File is stored in %USERPROFILE%\.mbs folder.
     
    .EXAMPLE
    Set-MBSAPICredential -UserName MyUser -Password MyPassword -StoreAs MyProfile
 
    .INPUTS
    None
 
    .OUTPUTS
    None
 
    #>

    

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$true, HelpMessage="API User Name")]
        [string]
        $UserName,
        #
        [Parameter(Mandatory=$true, HelpMessage="API Password")]
        [String]
        $Password,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $StoreAs
    )
    
    begin {
        
    }
    
    process {
        $Global:APICred = New-Object -typename PSCredential -ArgumentList @($UserName,(ConvertTo-SecureString -String $Password -AsPlainText -Force))

        if ($StoreAs) {
            if (-not (Test-Path "$env:USERPROFILE\.mbs")){
                $Folder = New-Item -Path "$env:USERPROFILE" -Name ".mbs" -ItemType "directory" -ErrorAction SilentlyContinue
            }
            $Global:APICred | Select Username,@{Name="Password";Expression = { $_.password | ConvertFrom-SecureString }} | ConvertTo-Json | Out-File "$env:USERPROFILE\.mbs\$StoreAs.json" -Force
        }
    }
    
    end {
        
    }
}

function Get-MBSAPIHeader {
    <#
    .SYNOPSIS
    Get API request header with MBS token
     
    .DESCRIPTION
    Calls POST method to https://api.mspbackups.com/api/Provider/Login
     
    .PARAMETER ProfileName
    Profile name
     
    .EXAMPLE
    Get-MBSAPIHeader -ProfileName $ProfileName
     
    .INPUTS
    None
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
 
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        
    }
    
    process {

        if ($ProfileName){
            $APICredLocal = Get-Content "$env:USERPROFILE\.mbs\$ProfileName.json" | ConvertFrom-Json | Select UserName,@{Name="Password";Expression={ConvertTo-SecureString $_.Password}}
            $APICredLocal = New-Object System.Management.Automation.PSCredential -ArgumentList @($APICredLocal.UserName, $APICredLocal.Password)
            #Select Username,@{Name="Password";Expression={ConvertTo-SecureString $_.Password}}
            
        }else{
            $APICredLocal = $APICred
        }

        $BodyProviderLogin = @{
            UserName = $APICredLocal.GetNetworkCredential().UserName
            Password = $APICredLocal.GetNetworkCredential().Password
        }
        $Login = Invoke-RestMethod -Method 'Post' -Uri (Get-MBSApiUrl).ProviderLogin -Body $BodyProviderLogin
        $headers = @{
            'Authorization' = "Bearer " + $Login.access_token
            'Accept' = "application/json"
        }
        return $headers
    }
    
    end {
        
    }
}

function Get-MBSAPIUser {
    
    <#
    .SYNOPSIS
        Get backup user list.
    .DESCRIPTION
        Calls the GET request to https://api.mspbackups.com/api/Users.
    .EXAMPLE
        PS C:\> Get-MBSAPIUsers | ft
         
        ID Email FirstName LastName NotificationEmails Company Enabled LicenseManagmentMode DestinationList
        -- ----- --------- -------- ------------------ ------- ------- -------------------- -----------
        bf3206df-ad73-4cdc-96ad-d4e3afa66ebc backupuser Alex V2 {} Red Dragon HQ True 2 {@{ID=2f...
        bac8f288-6785-4bd0-897e-9cb859ed336e John@api.com John Down {john@api.com, notification@api.com} ApiTest True 2 {@{ID=48...
    .PARAMETER ID
        MBS User ID. Specify to filter by MBS User ID.
 
    .PARAMETER ProfileName
        Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
 
    .INPUTS
        None
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject
    #>


    

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="User ID")]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        
    }
    
    process {
        if ($ID) {
            $Users = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }else{
            $Users = Invoke-RestMethod -Uri (Get-MBSApiUrl).Users -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $Users
    }
    
    end {
        
    }
}

function Add-MBSAPIUser {
    <#
    .SYNOPSIS
    Create MBS backup user.
     
    .DESCRIPTION
    Calls POST request to https://api.mspbackups.com/api/Users.
     
    .PARAMETER Email
    Backup user login name.
     
    .PARAMETER FirstName
    Backup user first name.
     
    .PARAMETER LastName
    Backup user last name.
     
    .PARAMETER NotificationEmails
    Backup user notification emails.
     
    .PARAMETER Company
    Company name.
     
    .PARAMETER Enabled
    Backup user status. Specify $false or $true.
     
    .PARAMETER Password
    Backup user password.
     
    .PARAMETER DestinationList
    Array of the backup storage destination collection JSON. Get more https://mspbackups.com/Admin/Help/mbs-api-specification/methods/post-apiusers/destinationfornewuser
     
    .PARAMETER SendEmailInstruction
    Send instructions to notification emails for user.
     
    .PARAMETER LicenseManagmentMode
    Licensing mode. Get more https://mspbackups.com/Admin/Help/mbs-api-specification/methods/post-apiusers/usermodetype
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
 
    .EXAMPLE
    $MyDestinationList = @(@{
        AccountID = "7cf9cbfe-504c-43ca-9a61-ef2f69f8ee91"
        Destination = "1f342fb4-0775-4ae8-9c63-a2d5955752b6"
        PackageID = 64130
    },@{
        AccountID = "bdb27298-c831-4be9-ae47-e35a38debacb"
        Destination = "d3f6198b-ab9e-46e6-a1d9-f03f6d731f21"
        PackageID = 64130
    })
    Add-MBSAPIUser -Email TestUser -FirstName "My" -LastName "User" -NotificationEmails User@contoso.com -Company Contoso -Enabled $true -Password (ConvertTo-SecureString -Force -asplaintext 'test') -DestinationList $MyDestinationList -SendEmailInstruction $true -LicenseManagmentMode 0 -ProfileName Profile
 
    Add new MBS backup user.
    .INPUTS
        None
 
    .OUTPUTS
        String. User ID
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Email")]
        [string]$Email,
        [Parameter(Mandatory=$false, HelpMessage="FirstName")]
        [string]$FirstName,
        [Parameter(Mandatory=$false, HelpMessage="LastName")]
        [string]$LastName,
        [Parameter(Mandatory=$false, HelpMessage="NotificationEmails")]
        [string[]]$NotificationEmails,
        [Parameter(Mandatory=$false, HelpMessage="Company")]
        [string]$Company,
        [Parameter(Mandatory=$false, HelpMessage="Enabled")]
        [bool]$Enabled = $true,
        [Parameter(Mandatory=$true, HelpMessage="Password")]
        [ValidateLength(6,100)]
        [Securestring]$Password,
        [Parameter(Mandatory=$false, HelpMessage="DestinationList")]
        [array]$DestinationList,
        [Parameter(Mandatory=$false, HelpMessage="SendEmailInstruction")]
        [bool]$SendEmailInstruction,
        [Parameter(Mandatory=$false, HelpMessage="LicenseManagmentMode")]
        [int]$LicenseManagmentMode,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        $UsersPost = @{
            Email = $Email.Trim()
            FirstName = $FirstName
            LastName = $LastName
            NotificationEmails = $NotificationEmails
            Company = $Company.Trim()
            Enabled = $Enabled
            Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            DestinationList = $DestinationList
            SendEmailInstruction = $SendEmailInstruction
            LicenseManagmentMode = $LicenseManagmentMode
        }
        if (-not $DestinationList){
            $UsersPost.Remove("DestinationList")
        }
        if (-not $NotificationEmails){
            $UsersPost.Remove("NotificationEmails")
        }
        Write-Verbose -Message ($UsersPost|ConvertTo-Json)
        $UserID = Invoke-RestMethod -Uri (Get-MBSApiUrl).Users -Method Post -Headers $headers -Body ($UsersPost|ConvertTo-Json) -ContentType 'application/json'
        return $UserID
    }
    
    end {
        
    }
}

function Edit-MBSAPIUser {
    <#
    .SYNOPSIS
    Updates user properties to new values.
     
    .DESCRIPTION
    Calls POST request to https://api.mspbackups.com/api/Users.
     
    .PARAMETER ID
    MBS Backup user ID.
     
    .PARAMETER Email
    MBS Backup user login name.
     
    .PARAMETER FirstName
    Backup user first name.
     
    .PARAMETER LastName
    Backup user last name.
     
    .PARAMETER NotificationEmails
    Backup user notification emails.
     
    .PARAMETER Company
    Company name.
     
    .PARAMETER Enabled
    Backup user status. Specify $false or $true.
     
    .PARAMETER Password
    Backup user password.
     
    .PARAMETER LicenseManagmentMode
    Licensing mode. Get more https://mspbackups.com/Admin/Help/mbs-api-specification/methods/post-apiusers/usermodetype
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
 
    .EXAMPLE
    Edit-MBSAPIUser -id 7c7044bb-313b-4b1b-900e-76d652246f4d -FirstName "NewFirstName" -LastName "NewLastName" -NotificationEmails NewEmail@contoso.com -Enabled $true -Password (ConvertTo-SecureString -Force -asplaintext 'NewPassword') -LicenseManagmentMode 1 -ProfileName MyProfile
 
    Updates user properties to new values.
    .INPUTS
        System.Management.Automation.PSCustomObject
 
    .OUTPUTS
        String
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="ID", ValueFromPipelineByPropertyName)]
        [string]$ID,
        [Parameter(Mandatory=$false, HelpMessage="Email")]
        [string]$Email,
        [Parameter(Mandatory=$false, HelpMessage="FirstName")]
        [string]$FirstName,
        [Parameter(Mandatory=$false, HelpMessage="LastName")]
        [string]$LastName,
        [Parameter(Mandatory=$false, HelpMessage="NotificationEmails")]
        [string[]]$NotificationEmails,
        [Parameter(Mandatory=$false, HelpMessage="Company")]
        [string]$Company,
        [Parameter(Mandatory=$true, HelpMessage="Enabled")]
        [bool]$Enabled = $true,
        [Parameter(Mandatory=$false, HelpMessage="Password")]
        #[ValidateLength(6,100)]
        [Securestring]$Password,
        [Parameter(Mandatory=$false, HelpMessage="LicenseManagmentMode")]
        [string]$LicenseManagmentMode,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        $UsersPut = @{
            ID = $ID
            Email = $Email.Trim()
            FirstName = $FirstName
            LastName = $LastName
            NotificationEmails = $NotificationEmails
            Company = $Company.Trim()
            Enabled = $Enabled
            Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            LicenseManagmentMode = $LicenseManagmentMode
        }
        if (-not $Company){
            $UsersPut.Remove("Company")
        }
        Write-Verbose -Message ($UsersPut|ConvertTo-Json)
        $UserID = Invoke-RestMethod -Uri (Get-MBSApiUrl).Users -Method PUT -Headers $headers -Body ($UsersPut|ConvertTo-Json) -ContentType 'application/json'
        return $UserID
    }
    
    end {
        
    }
}

function Remove-MBSAPIUser {
    <#
    .SYNOPSIS
    Deletes specified user and all user-related information.
     
    .DESCRIPTION
    Calls DELETE request to https://api.mspbackups.com/api/Users
     
    .PARAMETER ID
    User ID. User Get-MBSAPIUser to list MBS backup users.
     
    .PARAMETER Force
    Force delete. Confirmation is disabled.
     
    .PARAMETER DeleteData
    Deletes specified user and all user-related backup data. Data will be deleted during the day.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Remove-MBSAPIUser -id 7c7044bb-313b-4b1b-900e-76d652246f4d -Force -ProfileName MyProfile
 
    Remove backup user by ID in force mode (no confirmation)
 
    .EXAMPLE
    Remove-MBSAPIUser -id 7c7044bb-313b-4b1b-900e-76d652246f4d -DeleteData -Force -ProfileName MyProfile
 
    Remove backup user and all user-related backup data by ID
     
    .INPUTS
        None
 
    .OUTPUTS
        String
    #>

    

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="User Id", ValueFromPipelineByPropertyName)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="Force delete")]
        [switch]$Force,
        #
        [Parameter(Mandatory=$false, HelpMessage="Deletes specified user and all user-related backup data. Data will be deleted during the day.")]
        [switch]$DeleteData,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        if ($DeleteData){
            if ($Force){
                $User = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$ID) -Method DELETE -Headers $headers -ContentType 'application/json'            
                return $User
            }else{
                if (Confirm-MBSAction -Operation "Remove-MBSAPIUser" -Target "Remove user with ID: $ID and ALL USER-RELATED INFORMATION"){
                    $User = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$ID) -Method DELETE -Headers $headers -ContentType 'application/json'
                    return $User
                }
            }
        }else{
            if ($Force){
                $User = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$ID+"/Account") -Method DELETE -Headers $headers -ContentType 'application/json'            
            }else{
                if (Confirm-MBSAction -Operation "Remove-MBSAPIUser" -Target "Drop user with ID: $ID"){
                    $User = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$ID+"/Account") -Method DELETE -Headers $headers -ContentType 'application/json'
                    return $User
                }
            }
        }

    }
    
    end {
        
    }
}

function Get-MBSAPIUserComputer {
    <#
    .SYNOPSIS
    Lists backed up computers.
     
    .DESCRIPTION
    Calls GET request to api/Users/{userid}/Computers
     
    .PARAMETER ID
    Backup User ID
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIUserComputer -ID 7c7044bb-313b-4b1b-900e-76d652246f4d -ProfileName profile
     
    .INPUTS
    System.Management.Automation.PSCustomObject
 
    .OUTPUTS
    String
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="ID", ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        
    }
    
    process {
        $Computers = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$ID+"/Computers") -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        $Computers | Add-Member -MemberType NoteProperty -Name UserID -Value $ID
        return $Computers
    }
    
    end {
        
    }
}

function Remove-MBSAPIComputerData {
    <#
    .SYNOPSIS
    Deletes specified user computer data from cloud. Data will be deleted during the day.
     
    .DESCRIPTION
    Calls DELETE request to api/Users/{userId}/Computers.
     
    .PARAMETER UserID
    Backup user ID.
     
    .PARAMETER DestinationId
    Cloud destination ID. Use Get-MBSApiStorageAccountDestination to list backup storage destinations.
     
    .PARAMETER ComputerName
    Computer name
     
    .PARAMETER Force
    Force delete. Confirmation is disabled.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Remove-MBSAPIComputerData -UserID 7c7044bb-313b-4b1b-900e-76d652246f4d -DestinationId 1f342fb4-0775-4ae8-9c63-a2d5955752b6 -ComputerName MyComputer -Force -ProfileName MyProfile
     
    Delete backed up to cloud data for specified user ID, Destination and ComputerName
 
    .INPUTS
    System.Management.Automation.PSCustomObject
 
    .OUTPUTS
    String
    #>

    

    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$true, HelpMessage="User ID", ValueFromPipelineByPropertyName)]
        [string]$UserID,
        #
        [Parameter(Mandatory=$true, HelpMessage="Destination Id", ValueFromPipelineByPropertyName)]
        [string]$DestinationId,
        #
        [Parameter(Mandatory=$true, HelpMessage="Computer Name", ValueFromPipelineByPropertyName)]
        [string]$ComputerName,
        #
        [Parameter(Mandatory=$false, HelpMessage="Force delete")]
        [switch]$Force,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        $ComputerDelete = @(
            @{
            DestinationId = $DestinationId
            ComputerName = $ComputerName
            }
        )
        $ComputerDelete
        if ($Force){
            $ComputerData = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$UserID+"/Computers") -Method DELETE -Headers $headers -Body (ConvertTo-Json -InputObject $ComputerDelete) -ContentType 'application/json'          
            return $ComputerData
        }else{
            if (Confirm-MBSAction -Operation "Remove-ComputerData" -Target "Remove computer data for the user with ID: $UserID"){
                $ComputerData = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Users+"/"+$UserID+"/Computers") -Method DELETE -Headers $headers -Body (ConvertTo-Json -InputObject $ComputerDelete) -ContentType 'application/json'
                return $ComputerData
            }
        }
    }
    
    end {
        
    }
}

function Get-MBSAPICompany {
    <#
    .SYNOPSIS
    Get companies list
     
    .DESCRIPTION
    Calls GET request to api/Companies
 
    .PARAMETER ID
    Company ID
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPICompany -ProfileName profile
     
    List all companies
    .EXAMPLE
    Get-MBSAPICompany -ID f3090b26-16c8-418f-a57d-00b744abb869 -ProfileName profile
 
    Id Name StorageLimit LicenseSettings
    -- ---- ------------ ---------------
    f3090b26-16c8-418f-a57d-00b744abb869 Test Company 107374182400 0
 
    Get details for specific company.
 
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Company ID",ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($ID) {
            $Companies = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Companies+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)

        }else{
            $Companies = Invoke-RestMethod -Uri (Get-MBSApiUrl).Companies -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $Companies
    }
    
    end {
        
    }
}

function Add-MBSAPICompany {
    <#
    .SYNOPSIS
    Create MBS company.
     
    .DESCRIPTION
    Calls POST request to api/Companies.
     
    .PARAMETER Name
    Company name
     
    .PARAMETER StorageLimit
    Company backup limit. A negative value indicates the resource is unconstrained by a quota.
     
    .PARAMETER LicenseSettings
    Company license settings: 0 - Custom (Users have custom license settings) 1 - Global Pool(Users activate paid licenses from the global pool automatically) 2 - Company Pool(Users can activate only limited number of paid licenses from the company pool)
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Add-MBSAPICompany -Name Contoso -StorageLimit -1 -LicenseSettings 1 -ProfileName profile
 
    Create company named Contoso with unlimited storage and Global licensing pool.
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Company name",ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$Name,
        [Parameter(Mandatory=$false, HelpMessage="Company backup limit. A negative value indicates the resource is unconstrained by a quota.")]
        [string]$StorageLimit,
        [Parameter(Mandatory=$false, HelpMessage="Company license settings: 0 - Custom (Users have custom license settings) 1 - Global Pool(Users activate paid licenses from the global pool automatically) 2 - Company Pool(Users can activate only limited number of paid licenses from the company pool)")]
        [string]$LicenseSettings,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        $CompaniesPost = @{
            Name = $Name
            StorageLimit = $StorageLimit
            LicenseSettings = $LicenseSettings
        }
        Write-Verbose ($CompaniesPost|ConvertTo-Json)
        $Companies = Invoke-RestMethod -Uri (Get-MBSApiUrl).Companies -Method POST -Headers $headers -Body ($CompaniesPost|ConvertTo-Json) -ContentType 'application/json'
        return $Companies
    }
    
    end {
        
    }
}

function Edit-MBSAPICompany {
    <#
    .SYNOPSIS
    Change MBS company properties.
     
    .DESCRIPTION
    Calls PUT request to api/Companies
     
    .PARAMETER ID
    Company Id. Use Get-MBSAPICompany to list companies ID.
     
    .PARAMETER Name
    Company name
     
    .PARAMETER StorageLimit
    Company backup limit. A negative value indicates the resource is unconstrained by a quota.
     
    .PARAMETER LicenseSettings
    Company license settings: 0 - Custom (Users have custom license settings) 1 - Global Pool(Users activate paid licenses from the global pool automatically) 2 - Company Pool(Users can activate only limited number of paid licenses from the company pool)
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Edit-MBSAPICompany -ID 27fbcbb0-cb0b-40e5-8c4a-bd7faf18ffce -Name "My Contoso" -StorageLimit 100000 -LicenseSettings 2 -ProfileName profile
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, HelpMessage="Company Id",ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$ID,
        [Parameter(Mandatory=$false, HelpMessage="Company name")]
        [string]$Name,
        [Parameter(Mandatory=$false, HelpMessage="Company backup limit. A negative value indicates the resource is unconstrained by a quota.")]
        [string]$StorageLimit,
        [Parameter(Mandatory=$false, HelpMessage="Company license settings: 0 - Custom (Users have custom license settings) 1 - Global Pool(Users activate paid licenses from the global pool automatically) 2 - Company Pool(Users can activate only limited number of paid licenses from the company pool)")]
        [string]$LicenseSettings,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        $CompaniesPut = @{
            ID = $ID
            Name = $Name
            StorageLimit = $StorageLimit
            LicenseSettings = $LicenseSettings
        }
        Write-Verbose ($CompaniesPut|ConvertTo-Json)
        $Companies = Invoke-RestMethod -Uri (Get-MBSApiUrl).Companies -Method PUT -Headers $headers -Body ($CompaniesPut|ConvertTo-Json) -ContentType 'application/json'
        return $Companies
    }
    
    end {
        
    }
}

function Remove-MBSAPICompany {
    <#
    .SYNOPSIS
    Remove MBS company by ID
     
    .DESCRIPTION
    Calls DELETE request to api/Companies
     
    .PARAMETER ID
    Company Id
     
    .PARAMETER Force
    Force delete. Confirmation is disabled.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Remove-MBSAPICompany -id ce786a8f-46a7-4442-b4ab-f2e2f1d9858a -Force -ProfileName MyProfile
 
    Company ce786a8f-46a7-4442-b4ab-f2e2f1d9858a successfully deleted
 
    Remove company by ID in force mode (no confirmation)
 
    .EXAMPLE
    Remove-MBSAPICompany -id ce786a8f-46a7-4442-b4ab-f2e2f1d9858a -ProfileName MyProfile
 
    Are you sure you want to perform this action?
    Performing the operation "Remove-MBSAPICompany" on target "Removing company with ID: ce786a8f-46a7-4442-b4ab-f2e2f1d9858a"
    [Y] Yes [N] No (default is "N"):y
    Company ce786a8f-46a7-4442-b4ab-f2e2f1d9858a successfully deleted
 
    Remove company with confirmation prompt.
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact="High")]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Company Id", ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="Force delete")]
        [switch]$Force,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
    }
    
    process {
        if ($Force){
            $Companies = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Companies+"/"+$ID) -Method DELETE -Headers $headers -ContentType 'application/json'            
            return $Companies
        }else{
            if (Confirm-MBSAction -Operation "Remove-MBSAPICompany" -Target "Removing company with ID: $ID"){
                $Companies = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Companies+"/"+$ID) -Method DELETE -Headers $headers -ContentType 'application/json'
                return $Companies
            }
        }

    }
    
    end {
        
    }
}

function Get-MBSAPIStorageAccount {
    <#
    .SYNOPSIS
    Gets a list of storage accounts
     
    .DESCRIPTION
    Calls the GET api/Accounts API to get a list of Storage Accounts
     
    .PARAMETER ID
    Storage account ID
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIStorageAccount -profilename ao
 
    Get a list of storage accounts
 
    .EXAMPLE
    Get-MBSAPIStorageAccount -ID 7cf9cbfe-504c-43ca-9a61-ef2f69f8ee91 -profilename ao
 
    Get specific storage account details by ID.
 
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
 
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Storage account ID", ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [Alias("AccountID")]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($ID) {
            $StorageAccounts = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Accounts+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
            return $StorageAccounts
        }else{
            $StorageAccounts = Invoke-RestMethod -Uri (Get-MBSApiUrl).Accounts -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $StorageAccounts
    }
    
    end {
        
    }
}

function Get-MBSAPILicense {
    <#
    .SYNOPSIS
    List MBS licenses
     
    .DESCRIPTION
    Calls GET request to api/Licenses
     
    .PARAMETER ID
    License ID
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPILicense -ProfileName profile
 
    List all licenses.
 
    .EXAMPLE
    Get-MBSAPILicense -ID ec315596-ab48-4360-aee4-e725b5746a42 -ProfileName profile
 
    Get license details by specific license ID
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="License ID", ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($ID) {
            $Licenses = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Licenses+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }else{
            $Licenses = Invoke-RestMethod -Uri (Get-MBSApiUrl).Licenses -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $Licenses
    }
    
    end {
        
    }
}

function Get-MBSAPIPackage {
    <#
    .SYNOPSIS
    Get a list of package/storage limits structures that are available to users
     
    .DESCRIPTION
    Calls GET request to api/Packages
     
    .PARAMETER ID
    Package ID
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIPackage -ProfileName profile
 
    List all available packages/storage limits.
 
    .EXAMPLE
    Get-MBSAPIPackage -ID 52277 -ProfileName profile
 
    Get package/storage limit details by specific package ID
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Package ID", ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($ID) {
            $Packages = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Packages+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }else{
            $Packages = Invoke-RestMethod -Uri (Get-MBSApiUrl).Packages -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $Packages
    }
    
    end {
        
    }
}

function Get-MBSAPIBilling {
    <#
    .SYNOPSIS
    Get Billing information for current month
     
    .DESCRIPTION
    Calls GET/PUT request to api/Billing or api/Billing/Details
     
    .PARAMETER UserID
    Specify to filter output by backup user ID.
     
    .PARAMETER CompanyName
    Specify to filter output by backup Company name.
     
    .PARAMETER Date
    Billing date. Date format "yyyy-MM-dd". If empty or not specified, MBS will set current month.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIBilling -ProfileName profile
 
    Get billing details for all users and current month.
    .EXAMPLE
    Get-MBSAPIBilling -UserID bf3206df-ad73-4cdc-96ad-d4e3afa66ebc -ProfileName profile -Date "2020-02-01"
 
    Get billing details for the specified user ID and date.
    .EXAMPLE
    Get-MBSAPIBilling -CompanyName "APITest" -ProfileName profile
 
    Get billing details for the specified company and current month.
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding(DefaultParameterSetName='NoFilterOutput')]
    param (
        #
        [Parameter(Mandatory=$true, HelpMessage="UserID", ValueFromPipelineByPropertyName, ValueFromPipeline=$true, ParameterSetName='UserBillingDetails')]
        [string]$UserID,
        #
        [Parameter(Mandatory=$true, HelpMessage="Company Name", ValueFromPipelineByPropertyName, ValueFromPipeline=$true, ParameterSetName='CompanyBillingDetails')]
        [string]$CompanyName,
        #
        [Parameter(Mandatory=$false, HelpMessage="Date", ParameterSetName='UserBillingDetails')]
        [Parameter(Mandatory=$false, HelpMessage="Date", ParameterSetName='CompanyBillingDetails')]
        [string]$Date,
        #
        [Parameter(Mandatory=$false, HelpMessage="Common parameter", ParameterSetName='NoFilterOutput')]
        [switch]$NoFilterOutput=$true,
        #
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($UserID) {
            $UserPUT = @{
                UserID = $UserID
                Date = $Date
            }
            if (-not $Date){
                $UserPUT.Remove("Date")
            }
            Write-Verbose ($UserPUT|ConvertTo-Json)
            $Billing = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Billing +'/Details') -Method PUT -Body ($UserPUT|ConvertTo-Json) -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -ContentType 'application/json'
        }elseif ($CompanyName) {
            $CompanyPUT = @{
                CompanyName = $CompanyName
                Date = $Date
            }
            if (-not $Date){
                $CompanyPUT.Remove("Date")
            }
            Write-Verbose ($CompanyPUT|ConvertTo-Json)
            $Billing = Invoke-RestMethod -Uri (Get-MBSApiUrl).Billing -Method PUT -Body ($CompanyPUT|ConvertTo-Json) -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -ContentType 'application/json'
        }elseif ($NoFilterOutput) {
            $Billing = Invoke-RestMethod -Uri (Get-MBSApiUrl).Billing -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }else{
            Write-host "Incorrect parameters."
        }
        return $Billing
    }

    end {
        
    }
}

function Get-MBSAPIBuild {
    <#
    .SYNOPSIS
    Get a list of available backup agent downloads.
     
    .DESCRIPTION
    Calls the GET api/Builds API to get a list of all available agent downloads.
     
    .PARAMETER Type
    Build operating system type
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIBuild -ProfileName profile
 
    List all available backup agents.
 
    .EXAMPLE
    Get-MBSAPIBuild -Type Ubuntu -ProfileName profile
 
    Get available build for Ubuntu operating system only
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$False, HelpMessage="Build Operation System type.")]
        [ValidateSet("Ubuntu", "Windows","VM_Edition","RedHat","macOS")]
        [string]
        $Type,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        $Builds = Invoke-RestMethod -Uri (Get-MBSApiUrl).Builds -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        switch ($Type) {
            {$_ -in "Ubuntu","Windows","macOS"} {return $Builds|where {$_.Type -eq $Type}}
            "VM_Edition" {return $Builds|where {$_.Type -eq "Virtual Machine Edition"}}
            "RedHat" {return $Builds|where {$_.Type -eq "Red Hat, Fedora, CentOS, SUSE, Oracle Linux"}}
            Default {return $Builds}
        }
    }
    
    end {
        
    }
}

function Get-MBSAPIAdministrator {
    <#
    .SYNOPSIS
    List MBS account administrators
     
    .DESCRIPTION
    Calls GET request to api/Administrators.
     
    .PARAMETER AdminID
    Admin ID.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
 
    .EXAMPLE
    Get-MBSAPIAdministrator -ProfileName profile
     
    .EXAMPLE
    Get-MBSAPIAdministrator -ID 008410b2-e1f7-47f9-b35e-a7d13b74b516 -ProfileName profile
 
    Get administrator details with specific ID.
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        #
        [Parameter(Mandatory=$false, HelpMessage="Administrator ID", ValueFromPipelineByPropertyName, ValueFromPipeline=$true)]
        [Alias("ID")]
        [string]$AdminID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($ID) {
            $Administrators = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Administrators+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }else{
            $Administrators = Invoke-RestMethod -Uri (Get-MBSApiUrl).Administrators -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $Administrators
    }
    
    end {
        
    }
}

function Get-MBSAPIMonitoring {
    <#
    .SYNOPSIS
    Returns a list of monitoring structures that are available to users
     
    .DESCRIPTION
    Calls GET reqest to api/Monitoring
     
    .PARAMETER ID
    User ID
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIMonitoring -profile profile | FT
 
    Get monitored backup plans and format output as a table.
 
    .EXAMPLE
    Get-MBSAPIMonitoring -ID bf3206df-ad73-4cdc-96ad-d4e3afa66ebc -profile profile | FT
 
    Get backup plans statuses for the specified user ID and format output as a table.
     
    .INPUTS
    System.Management.Automation.PSCustomObject
    String
 
    .OUTPUTS
    System.Management.Automation.PSCustomObject
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, HelpMessage="User ID", ValueFromPipelineByPropertyName)]
        [string]$ID,
        #
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]
        $ProfileName
    )
    
    begin {
       
    }
    
    process {
        if ($ID) {
            $Monitoring = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Monitoring+"/"+$ID) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }else{
            $Monitoring = Invoke-RestMethod -Uri (Get-MBSApiUrl).Monitoring -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        return $Monitoring
    }
    
    end {
        
    }
}

# ------ Andrey O BEGIN ----
function Remove-NullProperties {
    [cmdletbinding()]
    param(
        # Object to remove null values from
        [parameter(ValueFromPipeline,Mandatory)]
        [object[]]$InputObject,
        #By default, remove empty strings (""), specify -LeaveEmptyStrings to leave them.
        [switch]$LeaveEmptyStrings
    )
    process {
        foreach ($obj in $InputObject) {
            $AllProperties = $obj.psobject.properties.Name
            $NonNulls = $AllProperties |
                where-object {$null -ne $obj.$PSItem} |
                where-object {$LeaveEmptyStrings.IsPresent -or -not [string]::IsNullOrEmpty($obj.$PSItem)}
            $obj | Select-Object -Property $NonNulls
        }
    }
} 

function Remove-MBSAPIAdministrator {
    <#
    .SYNOPSIS
    Removes an Administrator from MBS
     
    .DESCRIPTION
    Call the DELETE api/Administrators/{id} API to delete an administrator
     
    .PARAMETER AdminID
    ID of the admin to be deleted. Use Get-MBSAPIAdmin to determine
     
    .PARAMETER Force
    Bypass confirmation prompt
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Remove-MBSAPIAdministrator -AdminID 0b7e0a79-78e9-493e-af72-764f21960b05 -Force -ProfileName ao
     
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Admin ID")]
        [string]$AdminID,
        [Parameter(Mandatory=$false, HelpMessage="Bypass confirmation")]
        [switch]$Force,
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]$ProfileName
    )
    begin {
    }
    
    process {
        $AdministratorID = $False
        if($Force){
            $AdministratorID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Administrators + '/' + "$AdminID") -Method Delete -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        else {
            if(Confirm-MBSAction -operation "Remove-MBSAPIAdministrator" -target "Remove administrator with id $AdminID") {
                $AdministratorID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Administrators + '/' + "$AdminID") -Method Delete -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)    
            }
        }
        return $AdministratorID
    }
    
    end {
        
    }
}

function Edit-MBSAPIAdministrator {
    <#
    .SYNOPSIS
    Changes properties of an existing MBS admin
     
    .DESCRIPTION
    Calls the PUT api/Administrators API to edit properties of an existing MBS administrator
     
    .PARAMETER AdminID
    ID of the admin that you are editing. Use Get-MBSAPIAdministrator to determine
     
    .PARAMETER FirstName
    First Name
     
    .PARAMETER LastName
    Last name
     
    .PARAMETER Companies
    List of companies the admin should have access to
     
    .PARAMETER Enabled
    Whether the admin is to be enabled.
     
    .PARAMETER Password
    The administrator's password.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .PARAMETER PermissionsModels
    JSON permissions for the administrator. Valid fields can be found here: https://api.mspbackups.com/Help/ResourceModel?modelName=PermissionsModels Example can be found here: https://api.mspbackups.com/Help/Api/POST-api-Administrators
     
    .EXAMPLE
    Edit-MBSAPIAdministrator -ProfileName ao -AdminID 0b7e0a79-78e9-493e-af72-764f21960b05 -password (ConvertTo-SecureString -force -asplaintext 'Changed') -FirstName admin -LastName adminson -Enabled $true -PermissionsModels $perm
     
 
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Admin ID")]
        [string]$AdminID,
        [Parameter(Mandatory=$false, HelpMessage="FirstName")]
        [string]$FirstName,
        [Parameter(Mandatory=$false, HelpMessage="LastName")]
        [string]$LastName,
        [Parameter(Mandatory=$false, HelpMessage="Company")]
        [string[]]$Companies,
        [Parameter(Mandatory=$false, HelpMessage="Enabled")]
        [bool]$Enabled = $true,
        [Parameter(Mandatory=$false, HelpMessage="Password")]
        [SecureString]$Password,
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]$ProfileName,
        [Parameter(Mandatory=$true, HelpMessage="The Permission set for this administrator")]
        [string]
        $PermissionsModels
    )
    begin {
        
    }
    
    process {
        $AdminPut = New-Object -TypeName PSCustomObject -Property ([ordered]@{
            adminID = $AdminID
            InitialPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            FirstName = $FirstName
            LastName = $LastName
            PermissionsModels = $PermissionsModels | ConvertFrom-Json
            Companies = $Companies
            Enabled = $Enabled
            })
        if (-not $AdminPut.Companies) {
            $AdminPut.PSObject.Properties.remove('Companies')
        }
        $AdministratorID = Invoke-RestMethod -Uri (Get-MBSApiUrl).Administrators -Method Put -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($AdminPut|ConvertTo-Json) -ContentType 'application/json'
        return $AdministratorID
    }
    
    end {
        
    }
}

function Request-MBSAPIBuild {
    <#
    .SYNOPSIS
    Requests a new backup agent build
     
    .DESCRIPTION
    Calls the POST api/Builds/RequestCustomBuilds API to request a new build according to specifications
     
    .PARAMETER BuildType
    Build type Custom / Sandbox. Sandbox is recommended for new releases. 0 is for custom, 1 is for sandbox.
     
    .PARAMETER BuildEditions
    Type of endpoint to backup -- refer to full relevant mapping here: https://api.mspbackups.com/Help/ResourceModel?modelName=BuildEdition
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Request-MBSAPIBuild -ProfileName ao -BuildType 0 -BuildEditions (0,1,2,3,4)
     
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="BuildType")]
        [int]$BuildType,
        [Parameter(Mandatory=$true, HelpMessage="BuildEditions")]
        [int[]]$BuildEditions,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    }
    process {
        $headers = Get-MBSAPIHeader -ProfileName $ProfileName
        $CustomBuildPOST = [pscustomobject][ordered]@{
            Type = $BuildType
            Editions = $BuildEditions 
        }
        $CustomBuildInvocation=Invoke-RestMethod -Uri ((Get-MBSApiUrl).Builds+'/RequestCustomBuilds') -Method Post -Headers $headers -Body ($CustomBuildPOST | ConvertTo-Json) -ContentType 'application/json'        
        return $CustomBuildInvocation
    }
    end {
    }
}

function Add-MBSAPIAdministrator {
    <#
    .SYNOPSIS
    Creates an Administrator for MBS
     
    .DESCRIPTION
    Calls the POST api/Administrators API to create a new administrator according to the specified parameters.
 
    .PARAMETER Email
    Email address of the administrator
     
    .PARAMETER FirstName
    First name of the administrator
     
    .PARAMETER LastName
    Last name of the administrator
     
    .PARAMETER Companies
    List of companies the adminstrator will have access to.
     
    .PARAMETER Enabled
    Whether the administrator should be enabled after creation
     
    .PARAMETER Password
    Password
     
    .PARAMETER SendEmailInstruction
    Whether or not to send instructions to the new administrator
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .PARAMETER PermissionsModels
    JSON for administrator permissions. Valid fields can be found here: https://api.mspbackups.com/Help/ResourceModel?modelName=PermissionsModels Example can be found here: https://api.mspbackups.com/Help/Api/POST-api-Administrators
     
    .EXAMPLE
    $PermissionModels = '{
    "Users": 1,
    "StorageLimit": 0,
    "Notification": 0,
    "OnlineAccess": 0,
    "Licenses": 0,
    "Billing": 0,
    "Monitiring": 0,
    "RemoteDeploy": 1,
    "RemoteManagment": 0,
    "HelpMarketing": 0,
    "AuditLog": 0,
    "PSA": 0,
    "Administrators": 0,
    "Rebranding": 0,
    "Storage": 0,
    "ADS": 0,
    "LicenseBuy": 0,
    "LicenseActivate": 0,
    "StorageUsage": 1,
    "CapacityReport": 0,
    "GoogleApps": 0,
    "Dashboard": 0
    }'
    Add-MBSAPIAdministrator -Email 'QQQ@test.com' -password (ConvertTo-SecureString -Force -asplaintext 'test') -SendEmailInstruction $false -FirstName admin -LastName adminson -Enabled $true -PermissionsModels $PermissionModels -ProfileName profile
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Email")]
        [string]$Email,
        [Parameter(Mandatory=$false, HelpMessage="FirstName")]
        [string]$FirstName,
        [Parameter(Mandatory=$false, HelpMessage="LastName")]
        [string]$LastName,
        [Parameter(Mandatory=$false, HelpMessage="Company")]
        [string[]]$Companies,
        [Parameter(Mandatory=$false, HelpMessage="Enabled")]
        [bool]$Enabled = $true,
        [Parameter(Mandatory=$true, HelpMessage="Password")]
        [SecureString]$Password,
        [Parameter(Mandatory=$false, HelpMessage="Send Email Instruction")]
        [bool]$SendEmailInstruction,
        [Parameter(Mandatory=$false, HelpMessage="The profile name, which must be unique.")]
        [string]$ProfileName,
        [Parameter(Mandatory=$true, HelpMessage="The Permission set for this administrator")]
        [string]
        $PermissionsModels
    )
    begin {
        
    }
    process {
        $AdminPost = New-Object -TypeName PSCustomObject -Property ([ordered]@{
            Email = $Email.trim()
            InitialPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
            SendInstruction = $SendEmailInstruction
            FirstName = $FirstName
            LastName = $LastName
            PermissionsModels = $PermissionsModels | ConvertFrom-Json
            Companies = $Companies
            Enabled = $Enabled
            })
        if ($AdminPost.Companies -eq $null) {
            $AdminPost.PSObject.Properties.remove('Companies')
        }
        Write-Verbose -Message ($AdminPost|ConvertTo-Json)
        $AdministratorID = Invoke-RestMethod -Uri (Get-MBSApiUrl).Administrators -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($AdminPost|ConvertTo-Json) -ContentType 'application/json'
        return $AdministratorID
    }
    end {
    }
}

function Get-MBSAPIFilteredBilling {
    <#
    .SYNOPSIS
    Gets a filter billing report
     
    .DESCRIPTION
    Calls the PUT api/Billing API to get a filtered billing report with the option to specify a company or date.
     
    .PARAMETER CompanyName
    Name of the company
     
    .PARAMETER Date
    Date from which the report would start.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIFilteredBilling -ProfileName ao -Date (Get-Date -year 2020 -month 1 -Format s)
    Get-MBSAPIFilteredBilling -ProfileName ao -Company 'test'
     
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, HelpMessage="The company name")]
        [string]$CompanyName,
        [Parameter(Mandatory=$false, HelpMessage="Date range")]
        [string]$Date,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    }
    process {
        $FilteredBillingPut = New-Object -TypeName PSCustomObject -Property ([ordered]@{
            CompanyName = $CompanyName
            Date = $Date    
        })
        $FilteredBillingPut = Remove-NullProperties ($FilteredBillingPut)
        #$FilteredBillingPut
        #if($CompanyName -or $Date) {
        # $FilteredBilling = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Billing) -Method Put -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($FilteredBillingPut | ConvertTo-Json) -ContentType 'application/json'
        #}
        #else {
        # $FilteredBilling = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Billing) -Method Put -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -ContentType 'application/json'
        #}
        #$FilteredBillingPut
        $FilteredBilling = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Billing) -Method Put -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($FilteredBillingPut | ConvertTo-Json) -ContentType 'application/json'
        return $FilteredBilling
    }
    end {
    }
}

function Get-MBSAPIUserBackupDestination {
    <#
    .SYNOPSIS
    Gets a list of backup destinations
     
    .DESCRIPTION
    Calls the GET api/Destinations/{userEmail} API to get a list of user backup destinations.
     
    .PARAMETER userEmail
    Email of the user for which to query backup destinations. If none is specified, returns backup destinations for all users.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Get-MBSAPIUserBackupDestination -ProfileName ao -userEmail test@test.com
 
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, HelpMessage="Email of the user")]
        [string]$userEmail,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {

    }
    process {
        $AvailalbeStorageDestinations = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Destinations + '/' + $userEmail) -Method Get -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)     
        return $AvailalbeStorageDestinations
    }
    end {
    }
}
function Add-MBSAPIUserBackupDestination {
    <#
    .SYNOPSIS
    Add a backup destination to a user
     
    .DESCRIPTION
    Calls the POST api/Destinations API to add a backup destination to a user
     
    .PARAMETER UserID
    ID of the user to which a backup destination is being added. Use Get-MBSAPIUser to determine
     
    .PARAMETER AccountID
    The ID of the storage account that is to be added. Use Get-MBSAPIStorageAccount to determine.
     
    .PARAMETER Destination
    ID of the destination to be added. Use Get-MBSAPIStorageAccountDestination to determine.
     
    .PARAMETER PackageID
    ID of the storage limit (package) that is to be applied.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Add-MBSAPIUserBackupDestination -ProfileName ao -accountid 27bb3fcb-dc04-4a29-ac57-4d679809a2ba -Destination 'test-mbsapi' -UserID e472840f-e01f-40e0-95fc-b28882a28cfe -PackageID 64028
     
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="User for thie destination")]
        [string]$UserID,   
        [Parameter(Mandatory=$true, HelpMessage="Storage Account ID")]
        [string]$AccountID,   
        [Parameter(Mandatory=$true, HelpMessage="Destination ID")]
        [string]$Destination,   
        [Parameter(Mandatory=$true, HelpMessage="Storage Limit Package ID")]
        [string]$PackageID,   
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    }
    process {
        $StorageDestinationPost = [ordered]@{
            UserID=$UserID
            AccountID=$AccountID
            Destination=$Destination
            PackageID=$PackageID
        }
        $StorageDestinationID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Destinations) -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($StorageDestinationPost | ConvertTo-Json) -ContentType 'application/json'
        return $StorageDestinationID
    }
}

function Add-MBSAPIStorageAccount {
    <#
    .SYNOPSIS
    Add a Storage account to MBS
     
    .DESCRIPTION
    Calls the POST api/Accounts API to create a new storage account
     
    .PARAMETER DisplayName
    Display name for your storage account
     
    .PARAMETER Type
    Storage Type either as a numeric [0-24] or in a human-readable format such as 'Amazon S3'. Consult with https://api.mspbackups.com/Help/ResourceModel?modelName=AccountType
     
    .PARAMETER AccountSettings
    Accounts settings in a JSON string. You can find the required fields for the JSON here: https://api.mspbackups.com/Help/ResourceModel?modelName=Settings
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Add-MBSAPIStorageAccount -DisplayName 'New storage' -Type 'AmazonS3' -AccountSettings '{"AmazonS3":{"AccessKey": "******","SecretKey": "*****","isGovCloud": false}}' -profilename ao
 
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Display Name")]
        [string]$DisplayName,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Type")]
        [string]$Type,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Settings")]
        [string]$AccountSettings,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    }
    process {
        #Storage Type can actually be passed as both [0-24] and in a human-readable format such as 'Amazon S3. Consult with https://api.mspbackups.com/Help/ResourceModel?modelName=AccountType'
        $StorageAccountPost = [ordered]@{
            DisplayName = $DisplayName
            Type = $Type
            AccountSettings = $AccountSettings | ConvertFrom-Json
        }
        $StorageAccountPost | ConvertTo-Json
        $StorageDestinationID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Accounts) -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($StorageAccountPost | ConvertTo-Json) -ContentType 'application/json'
        return $StorageDestinationID
    }
    end {
    }
}

function Edit-MBSAPIStorageAccount {
    <#
    .SYNOPSIS
    Edit a Storage account
     
    .DESCRIPTION
    Calls the PUT api/Accounts API to edit an existing storage account.
     
    .PARAMETER AccountID
    ID of the storage account to edit. Use Get-MBSStorageAccount to determine.
     
    .PARAMETER DisplayName
    Display Name for the storage account
     
    .PARAMETER Type
    Storage Type either as a numeric [0-24] or in a human-readable format such as 'Amazon S3'. Consult with https://api.mspbackups.com/Help/ResourceModel?modelName=AccountType
     
    .PARAMETER AccountSettings
    Accounts settings in a JSON string. You can find the required fields for the JSON here: https://api.mspbackups.com/Help/ResourceModel?modelName=Settings
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Edit-MBSAPIStorageAccount -AccountID '2789654d-68a5-436b-a286-acbc4c22d26f' -DisplayName 'qwerty' -Type 'AmazonS3' -AccountSettings '{"AmazonS3":{"AccessKey": "****","SecretKey": "*****","isGovCloud": false}}' -ProfileName ao
 
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Storage Account ID")]
        [string]$AccountID,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Display Name")]
        [string]$DisplayName,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Type")]
        [string]$Type,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Settings JSON")]
        [string]$AccountSettings,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    }
    process {
        #Storage Type can actually be passed as both [0-24] and in a human-readable format such as 'Amazon S3'. Consult with https://api.mspbackups.com/Help/ResourceModel?modelName=AccountType
        $StorageDestinationPut = [ordered]@{
            AccountID = $AccountID
            DisplayName = $DisplayName
            Type = $Type
            AccountSettings = $AccountSettings | ConvertFrom-Json
        }
        $StorageAccountID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Accounts) -Method Put -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($StorageDestinationPut | ConvertTo-Json) -ContentType 'application/json'
        return $StorageAccountID
    }
    end {
    }
}

function Add-MBSAPIPackage {
    <#
    .SYNOPSIS
    Add a storage limit (package)
     
    .DESCRIPTION
    Calls the POST api/Packages API to create a new storage limit according to specified parameters
     
    .PARAMETER Name
    Name for this package.
     
    .PARAMETER Description
    Description for this package.
     
    .PARAMETER StorageLimit
    Storage Limit in GB.
     
    .PARAMETER isGlacierRestoreLimit
    Deprecated parameter.
     
    .PARAMETER RestoreLimit
    Restore limit for this package -- how much data can the customer restore. Value in GB
     
    .PARAMETER Cost
    Cost in $
     
    .PARAMETER GlacierRestoreType
    Standard=0, Bulk=1, Expedited=2, Don't restore from Glacier=3
     
    .PARAMETER UseRestoreLimit
    Enforece the RestoreLimit value
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Add-MBSAPIPackage -ProfileName ao -cost 0 -Description 'test' -name 'Test' -StorageLimit 420420 -isGlacierRestoreLimit $false
     
    .NOTES
    General notes
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, HelpMessage="Package name")]
        [string]$Name,   
        [Parameter(Mandatory=$false, HelpMessage="Package Description")]
        [string]$Description,   
        [Parameter(Mandatory=$true, HelpMessage="Storage Limit (in Gb)")]
        [float]$StorageLimit,   
        [Parameter(Mandatory=$true, HelpMessage="isGlacierRestoreLimit")]
        [bool]$isGlacierRestoreLimit,
        [Parameter(Mandatory=$false, HelpMessage="Restore Limit (in Gb)")]
        [nullable[float]]$RestoreLimit=$null,    
        [Parameter(Mandatory=$true, HelpMessage="Cost")]
        [float]$Cost, 
        [Parameter(Mandatory=$false, HelpMessage="GlacierRestoreType")]
        [string]$GlacierRestoreType=$null,
        [Parameter(Mandatory=$false, HelpMessage="Enforce restore limit")]
        [nullable[bool]]$UseRestoreLimit=$false, 
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    }
    process {
        $PackagePost = New-Object -typename PSCustomObject -property @{
            Name = $Name
            Description = $Description
            StorageLimit = $StorageLimit
            isGlacierRestoreLimit = $isGlacierRestoreLimit
            RestoreLimit = $RestoreLimit
            Cost = $Cost
            GlacierRestoreType = $GlacierRestoreType
            UseRestoreLimit = $UseRestoreLimit
        }
        $PackagePost = Remove-NullProperties($PackagePost)
        $PackageID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Packages) -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($PackagePost | ConvertTo-Json) -ContentType 'application/json'
        return $PackageID
    }
    end {

    }
}
  
function Edit-MBSAPIPackage {
    <#
    .SYNOPSIS
    Edit an existing Storage Limit (package)
     
    .DESCRIPTION
    Calls the PUT api/Packages API to edit an existing storage limit (package).
     
    .PARAMETER ID
    ID of the package to edit.
     
    .PARAMETER Name
    Name for this package.
     
    .PARAMETER Description
    Description for this package.
     
    .PARAMETER StorageLimit
    Storage Limit in GB.
     
    .PARAMETER isGlacierRestoreLimit
    Deprecated parameter
     
    .PARAMETER RestoreLimit
    Restore limit for this package -- how much data can the customer restore. Value in GB
     
    .PARAMETER Cost
    Cost in $
     
    .PARAMETER GlacierRestoreType
    Standard=0, Bulk=1, Expedited=2, Don't restore from Glacier=3
     
    .PARAMETER UseRestoreLimit
    Enforece the RestoreLimit value
     
    .PARAMETER Enabled
    Whether this storage limit is currently enabled.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Edit-MBSAPIPackage -ProfileName ao -id 64028 -cost 0 -Description 'test' -Enabled $false -name 'Test' -StorageLimit 420420 -isGlacierRestoreLimit $false
     
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, HelpMessage="Package ID")]
        [string]$ID,  
        [Parameter(Mandatory=$true, HelpMessage="Package name")]
        [string]$Name,   
        [Parameter(Mandatory=$false, HelpMessage="Package Description")]
        [string]$Description=$null,   
        [Parameter(Mandatory=$false, HelpMessage="Storage Limit (in Gb)")]
        [nullable[float]]$StorageLimit=$null,   
        [Parameter(Mandatory=$false, HelpMessage="isGlacierRestoreLimit")]
        [bool]$isGlacierRestoreLimit=$false,
        [Parameter(Mandatory=$false, HelpMessage="Restore Limit (in Gb)")]
        [nullable[float]]$RestoreLimit=$null,    
        [Parameter(Mandatory=$false, HelpMessage="Cost")]
        [nullable[float]]$Cost=$null, 
        [Parameter(Mandatory=$false, HelpMessage="GlacierRestoreType")]
        [string]$GlacierRestoreType=$null,
        [Parameter(Mandatory=$false, HelpMessage="Storage Limit (in Gb)")]
        [nullable[bool]]$UseRestoreLimit=$null, 
        [Parameter(Mandatory=$false, HelpMessage="Storage Limit (in Gb)")]
        [bool]$Enabled=$true, 
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        $PackageRaw = New-Object -TypeName PSCustomObject -Property ([ordered]@{
            ID = $ID
            Name = $Name
            isGlacierRestoreLimit = $isGlacierRestoreLimit
            Enabled = $Enabled

            Description = $Description
            StorageLimit = $StorageLimit
            RestoreLimit = $RestoreLimit
            Cost = $Cost
            GlacierRestoreType = $GlacierRestoreType
            UseRestoreLimit = $UseRestoreLimit
        })
        $PackagePut = Remove-NullProperties($PackageRaw)
    }
    process {
        $PackageID = Invoke-RestMethod -Uri ((Get-MBSApiUrl).Packages) -Method Put -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -Body ($PackagePut | ConvertTo-Json) -ContentType 'application/json'
        return $PackageID
    }
    end {

    }
}

function Remove-MBSAPIPackage {
    <#
    .SYNOPSIS
    Removes a Storage limit (package) from your account.
     
    .DESCRIPTION
    Calls the DELETE api/Packages/{id} API to remove a package from your account.
     
    .PARAMETER PackageID
    ID of the package you wish to remove. Use Get-MBSAPIPackages to determine
     
    .PARAMETER Force
    Bypass confirmation prompt for removal operation
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Remove-MBSAPIPackage -ProfileName ao -PackageID 64028 -Force
 
    #>

    
    param(
        [Parameter(Mandatory=$true, HelpMessage="Package ID")]
        [string]$PackageID,
        [Parameter(Mandatory=$false, HelpMessage="Bypass confirmation")]
        [switch]$Force,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    ) 
    begin {

    }
    process {
        if($Force) {
            return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Packages +'/' + "$PackageID") -Method Delete -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)
        }
        else {
            if(Confirm-MBSAction -operation "Remove-MBSAPIPackage" -target "Remove storage limit with id $PackageID. This will allow users to backup more data than you have previously limited them to") {
                return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Packages +'/' + "$PackageID") -Method Delete -Headers (Get-MBSAPIHeader -ProfileName $ProfileName)    
            }
        }

    }
    end {

    }
}
function Release-MBSAPILicense {
    <#
    .SYNOPSIS
    Release a license's association with a specified user.
     
    .DESCRIPTION
    Calls the POST api/Licenses/Release API to remove the association of a license to a user. This action also removes the license from the computer it is assigned to.
     
    .PARAMETER LicenseID
    ID of the license to release. Use Get-MBSAPILicenses to determine.
     
    .PARAMETER UserID
    ID of the user the license is associated with. Use Get-MBSAPIUser to determine.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Release-MBSAPILicense -ProfileName ao -LicenseID 8fc593d1-bb74-4a52-a644-0a574967df83 -UserID e472840f-e01f-40e0-95fc-b28882a28cfe
     
    #>

    
    param(
        [Parameter(Mandatory=$true, HelpMessage="License ID")]
        [string]$LicenseID,
        [Parameter(Mandatory=$true, HelpMessage="User ID")]
        [string]$UserID,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    } 
    process { 
        $ReleaseLicensePost = @{
            LicenseID=$LicenseID
            UserID=$UserID
        }
        return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Licenses +'/Release') -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -body ($ReleaseLicensePost | ConvertTo-Json) -ContentType 'application/json'
    } 
    end {
        
    }
}

function Grant-MBSAPILicense {
    <#
    .SYNOPSIS
    Grants a license to a specified user
     
    .DESCRIPTION
    Calls the POST api/Licenses/Grant API to grant a specified user a license from the appropriate license pool (determined by MBS user settings)
     
    .PARAMETER LicenseID
    ID of the license to grant. Use Get-MBSAPILicenses to determine.
     
    .PARAMETER UserID
    ID of the user to which the license needs to be granted. Use Get-MBSAPIUser to determine.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Grant-MBSAPILicense -ProfileName ao -LicenseID 8fc593d1-bb74-4a52-a644-0a574967df83 -UserID e472840f-e01f-40e0-95fc-b28882a28cfe
 
    #>

    
    param(
        [Parameter(Mandatory=$true, HelpMessage="License ID")]
        [string]$LicenseID,
        [Parameter(Mandatory=$true, HelpMessage="User ID")]
        [string]$UserID,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    } 
    process { 
        $GrantLicensePost = @{
            LicenseID=$LicenseID
            UserID=$UserID
        }
        return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Licenses +'/Grant') -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -body ($GrantLicensePost | ConvertTo-Json) -ContentType 'application/json'
    } 
    end {
        
    }
}

function Revoke-MBSAPILicense {
    <#
    .SYNOPSIS
    Removes the association of a license to a specified computer
     
    .DESCRIPTION
    Calls the POST api/Licenses/Revoke API to detach a license form the computer it is currently applied to. The license is moved back to the license pool it was taken from. In case Global Pool is used, user association is also removed. If a user has a custom pool specified, the license retains the attachment to that user's pool. Learn more about pools and license management here: https://help.mspbackups.com/administration/licenses/manage-licenses
     
    .PARAMETER LicenseID
    The ID of the license to revoke. Use Get-MBSAPILicenses to determine this parameter.
     
    .PARAMETER UserID
    The ID of the user that the license is attached to.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Revoke-MBSAPILicense -ProfileName ao -LicenseID 8fc593d1-bb74-4a52-a644-0a574967df83 -UserID e472840f-e01f-40e0-95fc-b28882a28cfe
 
    #>

    
    param(
        [Parameter(Mandatory=$true, HelpMessage="License ID")]
        [string]$LicenseID,
        [Parameter(Mandatory=$true, HelpMessage="User ID")]
        [string]$UserID,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {
        
    } 
    process { 
        $RevokeLicensePost = @{
            LicenseID=$LicenseID
            UserID=$UserID
        }
        return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Licenses +'/Revoke') -Method Post -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -body ($RevokeLicensePost | ConvertTo-Json) -ContentType 'application/json'
    } 
    end {
        
    }
}
function Get-MBSApiStorageAccountDestination {
    <#
    .SYNOPSIS
    Gets available destinations for a specified storage account
     
    .DESCRIPTION
    Calls the GET api/Accounts/{id} API to get a list of destinations in a specified storage account
     
    .PARAMETER AccountID
    The ID of the storage account in question. Use Get-MBSAPIStorageAccount to find this ID.
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)n
     
    .EXAMPLE
    Get-MBSApiStorageAccountDestination -ProfileName ao -AccountID 27bb3fcb-dc04-4a29-ac57-4d679809a2ba
 
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Storage Account ID")]
        [string]$AccountID,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )
    begin {

    }   
    process {
        $Destinations = (Invoke-RestMethod -uri ((Get-MBSApiUrl).Accounts + '/' + $AccountID) -headers (Get-MBSAPIHeader -ProfileName $ProfileName) -method Get).Destinations
        return $Destinations
    }   
    end{

    }  
}
function Add-MBSApiStorageAccountDestination {
    <#
    .SYNOPSIS
    Adds an existing location on your storage account as a destination available in MBS
     
    .DESCRIPTION
    Calls the POST api/Accounts/AddDestination API to add a location (bucket etc.) that already exists on your storage as a destination in MBS. This will allow you to then target backups to this destination
     
    .PARAMETER AccountID
    AccountID for the storage account where the location you are adding is. Use Get-MBSAPIStorageAccount to find out the AccountID.
     
    .PARAMETER Destination
    Actual destination identifier on the storage(bucket name, etc.)
     
    .PARAMETER DestinationDisplayName
    A display name for your storage in MBS
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Add-MBSApiStorageAccountDestination -AccountID 27bb3fcb-dc04-4a29-ac57-4d679809a2ba -Destination 'test-mbsapi' -DestinationDisplayName 'Test' -ProfileName ao
     
    #>

    
    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Storage Account ID")]
        [string]$AccountID,
        [Parameter(Mandatory=$true, HelpMessage="Actual destination identifier on the storage(bucket name, etc.)")]
        [string]$Destination,
        [Parameter(Mandatory=$true, HelpMessage="Destination display name")]
        [string]$DestinationDisplayName,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )    
    begin {
        $AddDestinationPost = New-Object -TypeName PSObject -property (@{
            AccountID=$AccountID
            Destination=$Destination
            DestinationDisplayName=$DestinationDisplayName
        })
    }
    process {
        $DestinationID = Invoke-RestMethod -uri ((Get-MBSAPIUrl).Accounts + "/AddDestination") -body ($AddDestinationPost | ConvertTo-Json) -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -method POST -ContentType 'application/json'
        return $DestinationID
    }
    end{

    }
}
function Edit-MBSApiStorageAccountDestination {
    <#
    .SYNOPSIS
    Edit a destination for a specified storage account.
     
    .DESCRIPTION
    Performs the PUT api/Accounts/EditDestination API call to edit an existing destination that belongs to one of your storage accounts.
     
    .PARAMETER DestinationID
    The ID of the destination you want to edit. You may obtain this ID via Get-MBSAPIStorageAccountDestination
 
    .PARAMETER AccountID
    The ID of the storage account this destination belongs to. You may obtain this via Get-MBSAPIStorageAccount
 
    .PARAMETER Destination
    Actual destination identifier on the storage(bucket name, etc.)
 
    .PARAMETER DestinationDisplayName
    The display name of the destination in the MBS portal (and in the online backup GUI)
     
    .PARAMETER ProfileName
    Profile name used with MSP360 PowerShell for MBS API (set via Set-MBSApiCredential)
     
    .EXAMPLE
    Edit-MBSApiStorageAccountDestination -ProfileName ao -destinationid e770933d-848f-4fdf-b24f-01aebd4e1405 -AccountID 27bb3fcb-dc04-4a29-ac57-4d679809a2ba -Destination 'test-mbsapi' -DestinationDisplayName 'new name'
    #>

    #
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Destination ID")]
        [string]$DestinationID,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account ID")]
        [string]$AccountID,
        [Parameter(Mandatory=$true, HelpMessage="Actual destination identifier on the storage(bucket name, etc.)")]
        [string]$Destination,
        [Parameter(Mandatory=$true, HelpMessage="Destination display name")]
        [string]$DestinationDisplayName,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )    
    begin {
        
    }
    process {
        $EditDestinationPut = New-Object -TypeName PSObject -property (@{
            DestinationID=$DestinationID
            AccountID=$AccountID
            Destination=$Destination
            DestinationDisplayName=$DestinationDisplayName
        })
        $DestinationID = Invoke-RestMethod -uri ((Get-MBSAPIUrl).Accounts + "/EditDestination") -body ($EditDestinationPut | ConvertTo-Json) -Headers (Get-MBSAPIHeader -ProfileName $ProfileName) -method Put -ContentType 'application/json'
        return $DestinationID
    }
    end{

    }
}
function Remove-MBSAPIStorageAccountDestination {
<#
.SYNOPSIS
This cmdlet removed a backup destination from one of your storage accounts.
 
.DESCRIPTION
This function invokes the PUT api/Accounts/RemoveDestination API call to remove a backup destination from a storage account.
 
.PARAMETER DestinationID
The ID of the destination you want to delete. You may obtain this ID via Get-MBSAPIStorageAccountDestination
 
.PARAMETER AccountID
The ID of the storage account this destination belongs to. You may obtain this via Get-MBSAPIStorageAccount
 
.PARAMETER Destination
Actual destination identifier on the storage(bucket name, etc.)
 
.PARAMETER DestinationDisplayName
The display name of the destination in the MBS portal (and in the online backup GUI)
 
.PARAMETER Force
Bypass confirmation prompt
 
.PARAMETER ProfileName
Profile name to use for API connection
 
.EXAMPLE
Remove-MBSAPIStorageAccountDestination -DestinationID "e770933d-848f-4fdf-b24f-01aebd4e1405" -accountid "27bb3fcb-dc04-4a29-ac57-4d679809a2ba" -Destination "test-mbsapi" -ProfileName ao -Force
 
#>

    #
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Storage Account Destination ID")]
        [string]$DestinationID,
        [Parameter(Mandatory=$true, HelpMessage="Storage Account ID")]
        [string]$AccountID,
        [Parameter(Mandatory=$true, HelpMessage="Actual destination identifier on the storage(bucket name, etc.)")]
        [string]$Destination,
        [Parameter(Mandatory=$false, HelpMessage="Destination display name")]
        [string]$DestinationDisplayName,
        [Parameter(Mandatory=$false, HelpMessage="Bypass confirmation")]
        [switch]$Force,
        [Parameter(Mandatory=$false, HelpMessage="The profile name")]
        [string]$ProfileName
    )      
    begin {
        
    } 
    process {
        $RemoveDestinationPut = New-Object -TypeName PSObject -property ([ordered]@{
            DestinationID=$DestinationID
            AccountID=$AccountID
            Destination=$Destination
            DestinationDisplayName=$DestinationDisplayName
        })
        $RemoveDestinationPut = Remove-NullProperties ($RemoveDestinationPut)
        if ($Force) {
            return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Accounts+"/RemoveDestination") -Headers (Get-MBSAPIHeader -ProfileName $profilename) -body ($RemoveDestinationPut | ConvertTo-Json) -ContentType 'application/json' -Method Put
        }
        else {
            if(Confirm-MBSAction -operation "Remove-MBSAPIStorageAccountDestionation" -target "Destination $Destination will be removed from storage account $AccountID") {
                return Invoke-RestMethod -Uri ((Get-MBSApiUrl).Accounts+"/RemoveDestination") -Headers (Get-MBSAPIHeader -ProfileName $profilename) -body ($RemoveDestinationPut | ConvertTo-Json) -ContentType 'application/json' -Method Put    
            }
        }
    }
    end {

    }
}

# ------ Andrey O END -----

Export-ModuleMember -Function Install-MBSAgent
Set-Alias Uninstall-MBSAgent Remove-MBSAgent
Export-ModuleMember -Function Remove-MBSAgent -Alias Uninstall-MBSAgent
Set-Alias gma Get-MBSAgent
Export-ModuleMember -Function Get-MBSAgent -Alias gma
Export-ModuleMember -Function Import-MBSUsers
Export-ModuleMember -Function Get-MBSApiUrl
Export-ModuleMember -Function Edit-MBSBackupPlan
Export-ModuleMember -Function Get-MBSBackupPlan
Export-ModuleMember -Function Get-MBSRestorePlan
Export-ModuleMember -Function Get-MBSConsistencyCheckPlan
Export-ModuleMember -Function Get-MBSStorageAccount
Export-ModuleMember -Function Start-MBSBackupPlan
Export-ModuleMember -Function Stop-MBSBackupPlan
Export-ModuleMember -Function Get-MBSAgentSettings
Export-ModuleMember -Function Set-MBSAgentSettings
#---------------------- Tools --------------------------------------------
Export-ModuleMember -Function Test-MBSConnection
Set-Alias amfr Add-MBSFirewallRules
Export-ModuleMember -Function Add-MBSFirewallRules -Alias amfr
Set-Alias rmfr Remove-MBSFirewallRules
Export-ModuleMember -Function Remove-MBSFirewallRules -Alias rmfr
Export-ModuleMember -Function Add-WFUMonitoringJob
#---------------------- API ----------------------------------------------
Export-ModuleMember -Function Set-MBSAPICredential
#
Export-ModuleMember -Function Get-MBSAPIUser
Export-ModuleMember -Function Add-MBSAPIUser
Export-ModuleMember -Function Edit-MBSAPIUser
Export-ModuleMember -Function Remove-MBSAPIUser
#
Export-ModuleMember -Function Get-MBSAPIUserComputer
Export-ModuleMember -Function Remove-MBSAPIComputerData
#
Export-ModuleMember -Function Get-MBSAPICompany
Export-ModuleMember -Function Add-MBSAPICompany
Export-ModuleMember -Function Edit-MBSAPICompany
Export-ModuleMember -Function Remove-MBSAPICompany
#
Export-ModuleMember -Function Get-MBSAPIStorageAccount
#
Export-ModuleMember -Function Get-MBSAPILicense
Export-ModuleMember -Function Get-MBSAPIPackage
Export-ModuleMember -Function Get-MBSAPIBilling
Export-ModuleMember -Function Get-MBSAPIBuild
Export-ModuleMember -Function Get-MBSAPIAdministrator
Export-ModuleMember -Function Get-MBSAPIMonitoring 

Export-ModuleMember -function Remove-MBSAPIAdministrator
Export-ModuleMember -function Edit-MBSAPIAdministrator
Export-ModuleMember -function Request-MBSAPIBuild
Export-ModuleMember -function Add-MBSAPIAdministrator
Export-ModuleMember -function Get-MBSAPIAvailableBuild
Export-ModuleMember -function Get-MBSAPIFilteredBilling
Export-ModuleMember -function Get-MBSAPIUserBackupDestination
Export-ModuleMember -function Add-MBSAPIUserBackupDestination
Export-ModuleMember -function Get-MBSAPIStorageAccount
Export-ModuleMember -function Add-MBSAPIStorageAccount
Export-ModuleMember -function Edit-MBSAPIStorageAccount

Set-Alias -Name Add-MBSAPIStorageLimit Add-MBSAPIPackage
Export-ModuleMember -function Add-MBSAPIPackage -Alias Add-MBSAPIStorageLimit
Set-Alias -Name Edit-MBSAPIStorageLimit Edit-MBSAPIPackage
Export-ModuleMember -function Edit-MBSAPIPackage -Alias Edit-MBSAPIStorageLimit
Set-Alias Remove-MBSAPIStorageLimit Remove-MBSAPIPackage
Export-ModuleMember -function Remove-MBSAPIPackage -Alias Remove-MBSAPIStorageLimit


Export-ModuleMember -function Release-MBSAPILicense
Export-ModuleMember -function Grant-MBSAPILicense
Export-ModuleMember -function Revoke-MBSAPILicense
Export-ModuleMember -function Get-MBSApiStorageAccountDestination
Export-ModuleMember -function Add-MBSApiStorageAccountDestination
Export-ModuleMember -function Edit-MBSApiStorageAccountDestination
Export-ModuleMember -function Remove-MBSAPIStorageAccountDestination