Disclaimer: This information is provided as-is for the benefit of the Community. Please contact Sophos Professional Services if you require assistance with your specific environment.
Overview
This article describes how to create a PowerShell script to simplify and automate the management of tamper protection settings for devices in Sophos Central. This tool is particularly useful for large-scale environments, where manually toggling tamper protection for numerous devices would be time-consuming and prone to error.
Applies to the following Sophos products and versions.
Sophos Central Endpoint Windows
Sophos Central Endpoint Windows Server
Key Features
- Automated Tamper Protection Management: Easily toggle tamper protection settings for Sophos Central devices.
- Legacy OS Support: Ensures smooth upgrade processes for legacy operating systems.
- Custom Reporting: Generates comprehensive reports of tamper activity.
- User-Friendly Interface: Menu-driven interface for ease of use.
- Authentication Handling: Securely manages API authentication and token refresh.
- Error Handling: Robustly catches and reports errors during API interactions and report generation.
- Device Selection Flexibility: Target endpoints, servers, or all Windows devices within Sophos Central.
- Bulk Operations: Reduces time and effort for tamper protection modifications.
- Detailed Reporting: Provides post-operation reports detailing actions taken on each device.
Preparing the Script
Ensure PowerShell 5.1 or higher is installed and you have access to the Sophos Central API. Gather the necessary API credentials (Client ID and Secret) for authentication.
Risks and Considerations
- API Usage: Improper use of the API can lead to disruptions. Understand the implications of tamper protection modifications.
- Execution Policy: Changing the execution policy can expose your system to security risks. Use the 'Unrestricted' policy judiciously.
- Testing: Always test the script in a controlled environment before use in production.
Ideal Usage Scenario
The toolkit is suited for scenarios requiring bulk modifications of tamper protection, such as before an OS upgrade across multiple legacy systems. It ensures accurate and efficient execution of tamper activities, minimizing manual effort and error.
<# .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
Instruction to prepare the script.
- Login to your current Sophos Central
- Follow the document below to create an API Credential with “Service Principal Super Admin” role.
URL: API Credential Management - Make a note of the Client ID and Secret.
- Create a new text document anywhere.
- Copy the code above and paste it.
- Save the file as with an extension “.ps1”.
Instructions to run the script.
- Login to any windows endpoint or server.
- Open command prompt as Administrator.
- Type command PowerShell and press enter.
- Navigate to a location where the script is saved.
- Change Execution Policy (if necessary):
- The default PowerShell execution policy might prevent the script from running. To temporarily allow the execution of the script, open PowerShell as an administrator and run:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine
- The default PowerShell execution policy might prevent the script from running. To temporarily allow the execution of the script, open PowerShell as an administrator and run:
- Run the script with it is name as seen in the screenshot below
- Follow the prompts to authenticate, select devices, and modify tamper protection settings.
Current Limitations
- The script does not support custom imports of device lists. Selection is based on device type or ID from Sophos Central API.
Disclaimer
[edited by: Qoosh at 4:56 PM (GMT -8) on 5 Jan 2024]