This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Remove Sophos Endpoint Agent from a Device without Tamper Protection

Dears,

I am facing an issue with uninstalling Sophos Endpoint Agent in order to reinstall it again.

In Sophos Central Dashboard, there is a laptop that is totally not protected while Sophos agent but not updated yet (logged in remotely to the device).

The latest version is 2023.2.0.47 while the agent version in that laptop is 2023.1.3.5.

The laptop is using Windows 10 Pro 22H2.

When I try to uninstall Sophos Endpoint Agent, it is asking for Tamper protection password.

However, in Central Dashboard is not showing the device at all and even cannot find it in Recover Tamper protection password.

Please help me solve this issue.

Thank you,



This thread was automatically locked due to age.
  • The default view of the device page in Sophos Central will list only the recently online devices. 
    Please make sure to select the all to list all the devices.


    If your machine is still not detected, it may probably have been deleted. 

    You can recover the tamper protection passwords of devices that were deleted.
    https://doc.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Reports/RecoverTamperProtectionPasswords/index.html


    To recover passwords, do as follows:

    1. Go to Logs & Reports.
    2. In Reports, under Endpoint & Server Protection, click Recover Tamper Protection passwords. You see a list of deleted devices.
    3. Find the device you want.
    4. In the Password(s) column, click View password details. This shows you the password (and previous passwords).

    Do let us know how it goes, If still unable to find the device in Recover Tamper Protection reports, We can use API

    Ismail Jaweed Ahmed (Ismail) 
    Senior Professional Service Engineer

  • Dear Ismail,

    Thank you for your fast response.

    Unfortunately, the device cannot find it in device page (I already chosen All instead of Recently online or Not online recently).

    Also, it is not found in Reports -> Endpoint & Server Protection -> Recover Tamper Protection Passwords.

    Thank you,

  • We can try using API, I have a custom Powershell script created. 

    save the code as PowerShell script and remember to change the execution policy before running 

    To change the execution poilcy, use the below code in the PowerShell

    Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine

    and then try running the script
    Please make sure to create API credentials and store the credentials securely. 
    While creating the API Credentials, it may ask to choose Role, Please select "Service Principal Super Admin"

    <#
    .SYNOPSIS
    SophosTamperToolkit - A script for comprehensive management of tamper protection on Sophos Endpoints.
    
    .DESCRIPTION
    The SophosTamperToolkit script is designed for the efficient management of tamper protection across a range of operating systems in Sophos Endpoint environments. Its key functionalities include:
    1. Authenticating with the Sophos Central API.
    2. Listing endpoints and servers, including legacy systems, and providing their tamper protection status.
    3. Allowing the user to select specific endpoints or servers for modifying tamper protection.
    4. Offering the choice to select individual systems or all systems within the chosen category.
    5. Disabling or enabling tamper protection on the selected systems, based on user input.
    6. Generating a comprehensive report detailing the actions performed, with the option to include tamper protection passwords if needed.
    
    .NOTES
    Version:        1.0
    Author:         Ismail Jaweed Ahmed
    Creation Date:  22/12/2023
    Dependencies:   Requires PowerShell 5.1 or higher and access to the Sophos Central API.
    
    .EXAMPLE
    PS> .\SophosTamperToolkit.ps1
    # This command runs the SophosTamperToolkit script.
    
    #>
    
    
    
    function art{
    
    write-host "
          #####    ####    #####    ##  ##    ####     #####          
         ##       ##  ##   ##  ##   ##  ##   ##  ##   ##              
          ####    ##  ##   #####    ######   ##  ##    ####           
             ##   ##  ##   ##       ##  ##   ##  ##       ##          
         #####     ####    ##       ##  ##    ####    #####           
    " -ForegroundColor white -BackgroundColor Blue
    write-host "                   Cybersecurity Delivered.                       " -ForegroundColor Red -BackgroundColor Black
    Write-Host " "
    Write-Host "------------------------------------------------------------------" -ForegroundColor Red
    Write-Host "        Sophos Central API TamperProtection toolkit               "-ForegroundColor White
    Write-Host "------------------------------------------------------------------" -ForegroundColor Red
    }
    
    # Introduction and Information Display
    function DisplayIntro {
        Clear-Host
        art
        Write-Host "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - NOTE - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" -ForegroundColor Yellow -BackgroundColor Black
        Write-Host "Welcome to the Sophos Central API TamperProtection Toolkit                         " -ForegroundColor Cyan
        Write-Host "This script interacts with Sophos Central API to manage tamper protection.         " -ForegroundColor Cyan
        Write-Host "It requires API credentials for authentication and operation.                      " -ForegroundColor Cyan
        Write-Host "It requires API credentials for authentication and operation.                      " -ForegroundColor Cyan
        Write-Host "Please ensure you have the necessary permissions and understand the risks involved." -ForegroundColor Cyan
        Write-Host "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" -ForegroundColor Yellow -BackgroundColor Black
        Write-Host ""
        Write-Host "Press CTRL+C to exit." -ForegroundColor Red -BackgroundColor Black
        pause 
        
    }
    
    
    function Gettime {
    
        $global:time = Get-Date
    }
    
    function GetClientIDandSecret {
    Clear-Host
    art
        Write-Host "Please provide the API Credentials of the Sophos Central"
        $global:clientid = Read-Host "Enter Client ID"
        $global:clientsecret = Read-Host "Enter Client Secret"
    }
    
    function GetAuthToken {
    
        $body = "grant_type=client_credentials&scope=token&client_id=$global:clientid&client_secret=$global:clientsecret"
        $headers = @{"Content-Type" = "application/x-www-form-urlencoded"}
        Sleep 1
        Write-Host "Authenticating to API Gateway.." -ForegroundColor Yellow
        try {
            $response = Invoke-RestMethod -Uri 'https://id.sophos.com/api/v2/oauth2/token' -Method 'POST' -Headers $headers -Body $body
            $global:token = $response.access_token
            $global:time = Get-Date
            Write-Host "Authentication Successful." -ForegroundColor Green
        } catch {
            Write-Host "Authentication Failed." -ForegroundColor Red
            Write-Host "Read the Error Code and Message" -ForegroundColor Yellow
            Write-Error $_
            Write-Host "`nPlease try again..." -ForegroundColor Cyan
            pause
            CheckandDoAuth
        }
    }
    
    function GetDataRegion {
    
        Write-Host "Collecting Data Region Details.." -ForegroundColor Yellow
        $headers = @{"Authorization" = "Bearer $global:token"}
        $gdrresponse = Invoke-RestMethod 'https://api.central.sophos.com/whoami/v1' -Method 'GET' -Headers $headers
        $global:TenantId = $gdrresponse.id
        $global:dataregion = $gdrresponse.apiHosts.dataRegion
        Write-Host "Data Region Details Collected Successfully." -ForegroundColor Green
    }
    
    function CheckandDoAuth {
    Clear-Host
    art
        if ($global:time -eq $null) {
            Write-Host "No authentication found"
            Write-Host "Proceeding to Authenticate"
            GetClientIDandSecret
            GetAuthToken
            GetDataRegion
        } else {
            $currtime = Get-Date
            $timedifference = ($currtime - $global:time).TotalSeconds
            if ($timedifference -gt 3600) {
                Write-Host "Authentication expired"
                GetClientIDandSecret
                GetAuthToken
                GetDataRegion
            } else {
                Write-Host "The previous authentication is still valid."
            }
        }
    }
    
    function GetEndpoints {
    Clear-Host
    art
        if (-not ($global:dataregion -and $global:token -and $global:TenantId)) {
            Write-Host "Required data not available. Please authenticate first." -ForegroundColor Red
            return
        }
    
        $url = "$($global:dataregion)/endpoint/v1/endpoints?pageSize=500&pageTotal=true&view=full"
        $headers = @{
            "Authorization" = "Bearer $($global:token)"
            "X-Tenant-ID" = $global:TenantId
            "Accept" = "application/json"
        }
    
        try {
            $global:epresponse = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
        } catch {
            Write-Host "Failed to retrieve endpoints: $($_.Exception.Message)" -ForegroundColor Red
        }
    }
    
    function IsLegacyOS($osName) {
    
        $legacyOSList = @("Windows Server 2012", "Windows Server 2008", "Windows SBS 2011", "Windows 8.1", "Windows 7", "Windows 10")
        foreach ($legacyOS in $legacyOSList) {
            if ($osName -like "$legacyOS*") {
                return $true
            }
        }
        return $false
    }
    
    function HandleLegacyOSMachines([string]$machineType) {
    
        if (-not $machineType) {
            Write-Host "Machine type not specified in HandleLegacyOSMachines."
            return
        }
    
        $legacyMachines = $global:epresponse.items | Where-Object {
            $_.type -eq $machineType -and (& IsLegacyOS $_.os.name)
        }
    
        if ($legacyMachines.Count -eq 0) {
            Write-Host "No legacy OS $machineType found." -ForegroundColor Red
            pause
            clear-host
            return ShowMenu
            
        }
    
        HandleMachineTamperProtectionLogic -machines $legacyMachines -machineType $machineType
    }
    
    
    # Function to handle machine tamper protection (endpoints/servers)
    function HandleMachineTamperProtection([string]$machineType) {
    
        if (-not $machineType) {
            Write-Host "Machine type not specified in HandleMachineTamperProtection."
            return
        }
    
        $machines = $global:epresponse.items | Where-Object { $_.type -eq $machineType }
    
        if ($machines.Count -eq 0) {
            Write-Host "No $machineType found." -ForegroundColor Red
            pause
            return ShowMenu
            clear-host
            
        }
    
        HandleMachineTamperProtectionLogic -machines $machines -machineType $machineType
    }
    
    
    function HandleMachineTamperProtectionLogic([object[]]$machines, [string]$machineType) {
        if (-not $machineType) {
            Write-Host "Machine type not specified in HandleMachineTamperProtectionLogic."
            return
        }
    
        $selectionChoice = Read-Host "Do you want to select specific $machineType or apply to all? Enter 'specific' or 'all'"
    
        if ($selectionChoice.ToLower() -eq 'specific') {
            $selectedMachines = SelectSpecificMachines $machines
        } elseif ($selectionChoice.ToLower() -eq 'all') {
            $selectedMachines = $machines
        } else {
            Write-Host "Invalid choice. Please enter 'specific' or 'all'."
            return
        }
    
        if ($selectedMachines) {
            $actionChoice = Read-Host "Do you want to 'turn on' or 'turn off' tamper protection for the selected $machineType? (Enter 'on' or 'off')"
            
    $actions = @()
    foreach ($machine in $selectedMachines) {
        $actionResult = ChangeTamperProtection $machine.id ($actionChoice -eq "on")
        $object = New-Object PSObject -Property @{
            ID = $machine.id
            Action = $actionResult
        }
        $actions += $object
    }
            GenerateAndDisplayReport $selectedMachines $actions
        } else {
            Write-Host "No $machineType(s) selected for tamper protection."
        }
    }
    
    
    # Function to select specific machines
    function SelectSpecificMachines($machines) {
    
        $index = 1
        $machineMap = @{}
        foreach ($machine in $machines) {
            Write-Host "$index. Hostname: $($machine.hostname), OS: $($machine.os.name), ID: $($machine.id)"
            $machineMap[$index.ToString()] = $machine
            $index++
        }
    
        $selectedIndexes = Read-Host "Enter the numbers of the machines to select (comma-separated)"
        $selectedMachines = @()
    
        foreach ($indexString in $selectedIndexes -split ',') {
            $trimmedIndex = $indexString.Trim()
            if ($machineMap.ContainsKey($trimmedIndex)) {
                $selectedMachines += $machineMap[$trimmedIndex]
            } else {
                Write-Host "Index $trimmedIndex not found"
            }
        }
    
        Write-Host "Selected machines count: $($selectedMachines.Count)"
        return $selectedMachines
    }
    
    
    # Function to generate and display report
    function GenerateAndDisplayReport($machines, $actions) {
        $includePassword = Read-Host "Would you like to include the tamper password in the report? (yes/no)"
        $reportData = @()
    
        foreach ($machine in $machines) {
            $action = ($actions | Where-Object { $_.ID -eq $machine.id }).Action
            $reportEntry = [PSCustomObject]@{
                Hostname = $machine.hostname
                OS = $machine.os.name
                ID = $machine.id
                ActionTaken = $action
            }
    
            if ($includePassword -eq 'yes') {
                $password = RetrieveTamperPassword $machine.id
                $reportEntry | Add-Member -NotePropertyName "TamperPassword" -NotePropertyValue $password
            }
    
            $reportData += $reportEntry
        }
    
        $reportPath = "$(Get-Location)\TamperProtectionReport.csv"
        $reportData | Export-Csv -Path $reportPath -NoTypeInformation -Force
        Write-Host "Report generated at: $reportPath"
        pause
        return ShowMenu
    }
    
    
    
    # Function to retrieve tamper password (Placeholder)
    function RetrieveTamperPassword($endpointId) {
    
        # Ensure required global variables are available
        if (-not ($global:dataregion -and $global:token -and $global:TenantId)) {
            Write-Host "Required data is not available (data region, token, tenant ID). Please authenticate first." -ForegroundColor Red
            return
        }
    
        # Construct the endpoint URL with the endpoint ID
        $url = "$($global:dataregion)/endpoint/v1/endpoints/$endpointId/tamper-protection"
    
        # Prepare the headers
        $headers = @{
            "Authorization" = "Bearer $($global:token)"
            "X-Tenant-ID" = $global:TenantId
            "Accept" = "application/json"
        }
    
        # Make the GET request
        try {
            $response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
            return $response.password
        }
        catch {
            Write-Host "Failed to retrieve tamper protection password for endpoint ID: $endpointId. Error: $($_.Exception.Message)" -ForegroundColor Red
        }
    }
    
    
    # Function to turn on/off tamper protection (API Call)
    function ChangeTamperProtection($endpointId, $enable) {
        $url = "$($global:dataregion)/endpoint/v1/endpoints/$endpointId/tamper-protection"
        $headers = @{
            "Authorization" = "Bearer $($global:token)"
            "X-Tenant-ID" = $global:TenantId
            "Accept" = "application/json"
        }
        $body = @{ "enabled" = $enable } | ConvertTo-Json
    
        try {
            $response = Invoke-RestMethod -Uri $url -Method Post -Headers $headers -Body $body -ContentType "application/json"
            if ($enable) {
                Write-Host "Tamper protection turned on for endpoint ID: $endpointId"
                return "Turned On"
            } else {
                Write-Host "Tamper protection turned off for endpoint ID: $endpointId"
                return "Turned Off"
            }
        }
        catch {
            Write-Host "Failed to change tamper protection for endpoint ID: $endpointId. Error: $($_.Exception.Message)" -ForegroundColor Red
            return "Failed"
        }
    }
    
    # Choose between endpoints and servers, and handle tamper protection
    function ShowMenu {
    Clear-Host
    art
        while ($true) {
            Write-Host "========== Main Menu ============" -ForegroundColor Green -BackgroundColor Black
            Write-host " "
            Write-Host "Select an option:"
            Write-Host "1. Work with endpoints" -ForegroundColor White -BackgroundColor Black
            Write-Host "2. Work with servers" -ForegroundColor White -BackgroundColor Black
            Write-Host "3. Work with legacy OS endpoints" -ForegroundColor White -BackgroundColor Black
            Write-Host "4. Work with legacy OS servers" -ForegroundColor White -BackgroundColor Black
            Write-Host "5. Exit" -ForegroundColor Red -BackgroundColor Black
            Write-Host "================================" -ForegroundColor Green -BackgroundColor Black
            $choice = Read-Host "Enter your choice (1-5)"
            switch ($choice) {
                "1" { HandleMachineTamperProtection "computer" }
                "2" { HandleMachineTamperProtection "server" }
                "3" { HandleLegacyOSMachines "computer" }
                "4" { HandleLegacyOSMachines "server" }
                "5" { Write-Host "Exiting script."; return }
                default { Write-Host "Invalid choice. Please enter a number between 1 and 5." }
            }
        }
    }
    
    
    
    
    
    # Main Script Execution
    DisplayIntro
    CheckandDoAuth  # Authenticate and set up
    GetEndpoints    # Fetch Endpoint Data
    ShowMenu       # Display the menu and handle user choices
    
    


    Request you to try this and let me know. 

    Ismail Jaweed Ahmed (Ismail) 
    Senior Professional Service Engineer

  • and if that does not work either, You can follow the instructions in the link below to recover a tamper protected machine if all other methods are not viable.

    https://support.sophos.com/support/s/article/KB-000036125?language=en_US#Central:~:text=Do%20the%20following%20recovery%20steps%20if%20all%20other%20methods%20are%20not%C2%A0viable.

    Ismail Jaweed Ahmed (Ismail) 
    Senior Professional Service Engineer

  • Dear Ismail,

    Sorry for the late response but none of the above suggestions were working so we had to format the laptop and then reinstall Sophos agent.

    Now, it is working smoothly without any problem.

    Thank you,