Skip to content

Instantly share code, notes, and snippets.

@CristiSalva999
Forked from jcary741/badlenovo.ps1
Last active October 28, 2025 18:59
Show Gist options
  • Select an option

  • Save CristiSalva999/5a3c8c10aff1ced44ce3e4f99ef36933 to your computer and use it in GitHub Desktop.

Select an option

Save CristiSalva999/5a3c8c10aff1ced44ce3e4f99ef36933 to your computer and use it in GitHub Desktop.
Removal script for Tobii and Nahimic software on Lenovo Legion devices
# Version: 0.1 (2025-01-18)
# License: MIT, use at your own risk
#
# This script disables the Lenovo-installed "Tobii experience" software and "nahimic" software.
# Tested on a Lenovo Legion Pro 5 (82WM) with Windows 11 24H2.
# Run it with `powershell.exe -noprofile -executionPolicy Bypass -File badlenovo.ps1`
# Following this script, you should be able to uninstall the "Tobii experience" app from the control panel (appwiz.cpl)
#
# After major updates, you may need to re-run this script.
# Disable services (may be re-enabled on reboot)
Get-Service -Name "Tobii*" | Stop-Service -Force
Get-Service -Name "Tobii*" | Set-Service -StartupType Disabled
Get-Service -Name "Nahimic*" | Stop-Service -Force
Get-Service -Name "Nahimic*" | Set-Service -StartupType Disabled
# Get the service exe paths
$services = Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -like "Tobii*" -or $_.Name -like "Nahimic*"} | Select-Object PathName
$services = $services.PathName -split "`n" | ForEach-Object { $_.Replace('"', '').Trim() }
$services = $services -replace '\.exe.*', '.exe'
## use icacls to deny access to the service exes, so that they can't be started
$services | ForEach-Object {
$servicePath = $_
$acl = Get-Acl $servicePath
$denyEveryone = New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone", "FullControl", "Deny")
$denySystem = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "Deny")
$acl.SetAccessRule($denyEveryone)
$acl.SetAccessRule($denySystem)
Set-Acl $servicePath $acl
}
# Find "devices" that are installed by the Tobii or nahimic software and disable them
$devices = Get-PnpDevice | Where-Object {$_.FriendlyName -like "Tobii*" -or $_.FriendlyName -like "Nahimic*"} | Select-Object FriendlyName,InstanceId
$devices | ForEach-Object {
$device = $_
$instanceId = $device.InstanceId
$friendlyName = $device.FriendlyName
Disable-PnpDevice -InstanceId $instanceId -Confirm:$false
Write-Host "Disabled device: $friendlyName"
}
# Version: 0.1 (2025-01-18)
# License: MIT, use at your own risk
#
# This script disables the Lenovo-installed "Tobii experience" software and "nahimic" software.
# Tested on a Lenovo Legion Pro 5 (82WM) with Windows 11 24H2.
# Run it with `powershell.exe -noprofile -executionPolicy Bypass -File badlenovo.ps1`
# Following this script, you should be able to uninstall the "Tobii experience" app from the control panel (appwiz.cpl)
#
# After major updates, you may need to re-run this script.
# Disable services (may be re-enabled on reboot)
Get-Service -Name "Tobii*" | Stop-Service -Force
Get-Service -Name "Tobii*" | Set-Service -StartupType Disabled
Get-Service -Name "Nahimic*" | Stop-Service -Force
Get-Service -Name "Nahimic*" | Set-Service -StartupType Disabled
# Disable specific Tobii services that might not be caught by wildcard
$specificServices = @("TobiiService", "Tobii EyeX", "TobiiExperience")
foreach ($serviceName in $specificServices) {
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($service) {
Write-Host "Disabling specific service: $serviceName"
Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue
Set-Service -Name $serviceName -StartupType Disabled -ErrorAction SilentlyContinue
}
}
# Disable SpitCamera services permanently
Write-Host "Disabling SpitCamera services permanently..."
$spitcamServices = @("SpitCameraEventService", "SpitCamSrv")
foreach ($serviceName in $spitcamServices) {
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($service) {
Write-Host "Disabling SpitCamera service: $serviceName"
Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue
Set-Service -Name $serviceName -StartupType Disabled -ErrorAction SilentlyContinue
# Also disable in registry to prevent re-enabling
try {
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$serviceName"
if (Test-Path $regPath) {
Set-ItemProperty -Path $regPath -Name "Start" -Value 4 -Type DWord
Write-Host "Disabled $serviceName in registry"
}
}
catch {
Write-Host "Failed to disable $serviceName in registry: $($_.Exception.Message)"
}
}
}
# Get the service exe paths
$services = Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -like "Tobii*" -or $_.Name -like "Nahimic*" -or $_.Name -like "*SpitCam*"} | Select-Object PathName
$services = $services.PathName -split "`n" | ForEach-Object { $_.Replace('"', '').Trim() }
$services = $services -replace '\.exe.*', '.exe'
# Add SpitCamSrv.exe path specifically
$spitcamPath = "C:\WINDOWS\System32\SpitCamSrv.exe"
if (Test-Path $spitcamPath) {
$services += $spitcamPath
}
## use icacls to deny access to the service exes, so that they can't be started
$services | ForEach-Object {
$servicePath = $_
if ($servicePath -and (Test-Path $servicePath)) {
Write-Host "Blocking access to service executable: $servicePath"
try {
$acl = Get-Acl $servicePath
$denyEveryone = New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone", "FullControl", "Deny")
$denySystem = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "Deny")
$denyUsers = New-Object System.Security.AccessControl.FileSystemAccessRule("Users", "FullControl", "Deny")
$acl.SetAccessRule($denyEveryone)
$acl.SetAccessRule($denySystem)
$acl.SetAccessRule($denyUsers)
Set-Acl -Path $servicePath -AclObject $acl
Write-Host "Successfully blocked access to: $servicePath"
}
catch {
Write-Host "Failed to block access to: $servicePath - $($_.Exception.Message)"
}
}
}
# Terminate specific processes that might still be running
Write-Host "Terminating Tobii, Nahimic and SpitCamera processes..."
$processesToKill = @("splitcamsrv", "SpitCamSrv", "Tobii", "Nahimic", "TobiiExperience", "TobiiService", "Tobii.Service")
foreach ($processName in $processesToKill) {
$processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
if ($processes) {
$processes | ForEach-Object {
Write-Host "Terminating process: $($_.ProcessName) (PID: $($_.Id))"
try {
Stop-Process -Id $_.Id -Force
Write-Host "Successfully terminated: $($_.ProcessName)"
}
catch {
Write-Host "Failed to terminate: $($_.ProcessName) - $($_.Exception.Message)"
}
}
}
}
# Block specific SpitCamera executables by denying access to their files
Write-Host "Blocking access to SpitCamera executables..."
$spitcamPaths = @(
"C:\WINDOWS\System32\SpitCamSrv.exe"
)
foreach ($path in $spitcamPaths) {
if (Test-Path $path) {
Write-Host "Blocking access to SpitCamera: $path"
try {
$acl = Get-Acl $path
$denyEveryone = New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone", "FullControl", "Deny")
$denySystem = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "Deny")
$denyUsers = New-Object System.Security.AccessControl.FileSystemAccessRule("Users", "FullControl", "Deny")
$acl.SetAccessRule($denyEveryone)
$acl.SetAccessRule($denySystem)
$acl.SetAccessRule($denyUsers)
Set-Acl -Path $path -AclObject $acl
Write-Host "Successfully blocked access to SpitCamera: $path"
}
catch {
Write-Host "Failed to block access to SpitCamera: $path - $($_.Exception.Message)"
}
}
}
# Block specific Tobii executables by denying access to their files
Write-Host "Blocking access to Tobii executables..."
$tobiiPaths = @(
"C:\Program Files\Tobii\Tobii EyeX\Tobii.Service.exe",
"C:\Program Files\Tobii\Tobii EyeX\*",
"C:\Program Files (x86)\Tobii\*"
)
foreach ($pathPattern in $tobiiPaths) {
try {
# Handle wildcard paths by expanding them first
if ($pathPattern.Contains("*")) {
$expandedPaths = Get-ChildItem -Path $pathPattern -Force -ErrorAction SilentlyContinue
if ($expandedPaths) {
foreach ($expandedPath in $expandedPaths) {
$path = $expandedPath.FullName
Write-Host "Blocking access to: $path"
try {
$acl = Get-Acl $path
$denyEveryone = New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone", "FullControl", "Deny")
$denySystem = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "Deny")
$denyUsers = New-Object System.Security.AccessControl.FileSystemAccessRule("Users", "FullControl", "Deny")
$acl.SetAccessRule($denyEveryone)
$acl.SetAccessRule($denySystem)
$acl.SetAccessRule($denyUsers)
Set-Acl -Path $path -AclObject $acl
Write-Host "Successfully blocked access to: $path"
}
catch {
Write-Host "Failed to block access to: $path - $($_.Exception.Message)"
}
}
}
} else {
# Handle single file paths
if (Test-Path $pathPattern) {
Write-Host "Blocking access to: $pathPattern"
try {
$acl = Get-Acl $pathPattern
$denyEveryone = New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone", "FullControl", "Deny")
$denySystem = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "Deny")
$denyUsers = New-Object System.Security.AccessControl.FileSystemAccessRule("Users", "FullControl", "Deny")
$acl.SetAccessRule($denyEveryone)
$acl.SetAccessRule($denySystem)
$acl.SetAccessRule($denyUsers)
Set-Acl -Path $pathPattern -AclObject $acl
Write-Host "Successfully blocked access to: $pathPattern"
}
catch {
Write-Host "Failed to block access to: $pathPattern - $($_.Exception.Message)"
}
}
}
}
catch {
Write-Host "Error processing path pattern: $pathPattern - $($_.Exception.Message)"
}
}
# Block SpitCamera executable with firewall rules
Write-Host "Creating firewall rules to block SpitCamera executable..."
try {
# Block SpitCamSrv.exe from accessing network
New-NetFirewallRule -DisplayName "Block SpitCamSrv.exe" -Direction Outbound -Program "C:\WINDOWS\System32\SpitCamSrv.exe" -Action Block -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName "Block SpitCamSrv.exe Inbound" -Direction Inbound -Program "C:\WINDOWS\System32\SpitCamSrv.exe" -Action Block -ErrorAction SilentlyContinue
Write-Host "Successfully created firewall rules to block SpitCamSrv.exe"
}
catch {
Write-Host "Failed to create SpitCamera firewall rules: $($_.Exception.Message)"
}
# Block Tobii port 49350 with firewall rules
Write-Host "Creating firewall rules to block Tobii port 49350..."
try {
# Block inbound traffic on port 49350
New-NetFirewallRule -DisplayName "Block Tobii Inbound 49350" -Direction Inbound -Protocol TCP -LocalPort 49350 -Action Block -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName "Block Tobii Inbound UDP 49350" -Direction Inbound -Protocol UDP -LocalPort 49350 -Action Block -ErrorAction SilentlyContinue
# Block outbound traffic on port 49350
New-NetFirewallRule -DisplayName "Block Tobii Outbound 49350" -Direction Outbound -Protocol TCP -RemotePort 49350 -Action Block -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName "Block Tobii Outbound UDP 49350" -Direction Outbound -Protocol UDP -RemotePort 49350 -Action Block -ErrorAction SilentlyContinue
Write-Host "Successfully created firewall rules to block port 49350"
}
catch {
Write-Host "Failed to create firewall rules: $($_.Exception.Message)"
}
# First, remove devices from the system completely using PowerShell
Write-Host "Finding and removing Tobii and Nahimic devices..."
# Get all PnP devices that match our criteria
$devicesToRemove = Get-PnpDevice | Where-Object {
$_.FriendlyName -like "*Tobii*" -or
$_.FriendlyName -like "*Nahimic*" -or
$_.HardwareID -like "*Tobii*" -or
$_.HardwareID -like "*Nahimic*"
}
# Remove each device
$devicesToRemove | ForEach-Object {
$device = $_
$instanceId = $device.InstanceId
$friendlyName = $device.FriendlyName
Write-Host "Removing device: $friendlyName (Instance ID: $instanceId)"
try {
# Use pnputil to remove the device
$result = & pnputil /remove-device $instanceId 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "Successfully removed device: $friendlyName"
} else {
Write-Host "Failed to remove device: $friendlyName - $result"
}
}
catch {
Write-Host "Error removing device: $friendlyName - $($_.Exception.Message)"
}
}
# Find remaining "devices" that are installed by the Tobii or nahimic software and disable them
$remainingDevices = Get-PnpDevice | Where-Object {$_.FriendlyName -like "Tobii*" -or $_.FriendlyName -like "Nahimic*"} | Select-Object FriendlyName,InstanceId
$remainingDevices | ForEach-Object {
$device = $_
$instanceId = $device.InstanceId
$friendlyName = $device.FriendlyName
Disable-PnpDevice -InstanceId $instanceId -Confirm:$false
Write-Host "Disabled remaining device: $friendlyName"
}
# Final registry modifications to permanently disable SpitCamera services
Write-Host "Making final registry modifications to permanently disable SpitCamera..."
try {
# Disable SpitCamera services in registry with multiple methods
$spitcamServices = @("SpitCameraEventService", "SpitCamSrv")
foreach ($serviceName in $spitcamServices) {
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$serviceName"
if (Test-Path $regPath) {
# Set Start value to 4 (Disabled)
Set-ItemProperty -Path $regPath -Name "Start" -Value 4 -Type DWord -Force
# Set Type to 1 (Kernel Driver) to make it harder to restart
Set-ItemProperty -Path $regPath -Name "Type" -Value 1 -Type DWord -Force
# Add a custom flag to mark as permanently disabled
Set-ItemProperty -Path $regPath -Name "DisabledByScript" -Value 1 -Type DWord -Force
Write-Host "Permanently disabled $serviceName in registry"
}
}
# Create a registry key to prevent SpitCamera from being reinstalled
$preventKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
if (!(Test-Path $preventKey)) {
New-Item -Path $preventKey -Force | Out-Null
}
Set-ItemProperty -Path $preventKey -Name "DisableSpitCamera" -Value 1 -Type DWord -Force
Write-Host "Created registry key to prevent SpitCamera reinstallation"
Write-Host "Registry modifications completed successfully"
}
catch {
Write-Host "Failed to make registry modifications: $($_.Exception.Message)"
}
# Clean up all data files and folders created by these programs
Write-Host "Cleaning up all data files and folders created by Tobii, Nahimic, and SpitCamera..."
# Define specific locations to clean (avoiding wildcards that can cause slowdowns)
$cleanupLocations = @(
# Current user locations
"$env:USERPROFILE\AppData\Local\Tobii",
"$env:USERPROFILE\AppData\Local\Nahimic",
"$env:USERPROFILE\AppData\Local\SpitCam",
"$env:USERPROFILE\AppData\Roaming\Tobii",
"$env:USERPROFILE\AppData\Roaming\Nahimic",
"$env:USERPROFILE\AppData\Roaming\SpitCam",
"$env:USERPROFILE\Documents\Tobii",
"$env:USERPROFILE\Documents\Nahimic",
"$env:USERPROFILE\Documents\SpitCam",
"$env:USERPROFILE\.tobii",
# Program Files locations
"C:\Program Files\Tobii",
"C:\Program Files\Nahimic",
"C:\Program Files\SpitCam",
"C:\Program Files (x86)\Tobii",
"C:\Program Files (x86)\Nahimic",
"C:\Program Files (x86)\SpitCam",
# ProgramData locations
"C:\ProgramData\Tobii",
"C:\ProgramData\Nahimic",
"C:\ProgramData\SpitCam",
# System locations
"C:\Windows\System32\Tobii",
"C:\Windows\System32\Nahimic",
"C:\Windows\System32\SpitCam",
"C:\Windows\SysWOW64\Tobii",
"C:\Windows\SysWOW64\Nahimic",
"C:\Windows\SysWOW64\SpitCam"
)
$totalRemoved = 0
# Clean up each specific location
foreach ($location in $cleanupLocations) {
if (Test-Path $location) {
Write-Host "Cleaning: $location"
try {
$items = Get-ChildItem -Path $location -Recurse -Force -ErrorAction SilentlyContinue
if ($items) {
foreach ($item in $items) {
try {
if ($item.PSIsContainer) {
Remove-Item -Path $item.FullName -Recurse -Force -ErrorAction SilentlyContinue
Write-Host " Removed folder: $($item.Name)"
} else {
Remove-Item -Path $item.FullName -Force -ErrorAction SilentlyContinue
Write-Host " Removed file: $($item.Name)"
}
$totalRemoved++
}
catch {
Write-Host " Could not remove: $($item.Name)"
}
}
}
}
catch {
Write-Host " Error accessing: $location"
}
}
}
Write-Host "Cleaned $totalRemoved items from specific locations"
# Clean up registry data and user settings (specific paths only)
Write-Host "Cleaning up registry entries..."
$specificRegistryPaths = @(
"HKCU:\Software\Tobii",
"HKCU:\Software\Nahimic",
"HKCU:\Software\SpitCam",
"HKLM:\SOFTWARE\Tobii",
"HKLM:\SOFTWARE\Nahimic",
"HKLM:\SOFTWARE\SpitCam",
"HKLM:\SOFTWARE\WOW6432Node\Tobii",
"HKLM:\SOFTWARE\WOW6432Node\Nahimic",
"HKLM:\SOFTWARE\WOW6432Node\SpitCam"
)
$registryRemoved = 0
foreach ($regPath in $specificRegistryPaths) {
if (Test-Path $regPath) {
try {
Remove-Item -Path $regPath -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Removed registry key: $regPath"
$registryRemoved++
}
catch {
Write-Host "Could not remove registry key: $regPath"
}
}
}
Write-Host "Removed $registryRemoved registry keys"
# Clean up temporary files and cache (specific paths only)
Write-Host "Cleaning up temporary files..."
$tempPaths = @(
"$env:TEMP\Tobii",
"$env:TEMP\Nahimic",
"$env:TEMP\SpitCam",
"C:\Windows\Temp\Tobii",
"C:\Windows\Temp\Nahimic",
"C:\Windows\Temp\SpitCam"
)
$tempRemoved = 0
foreach ($tempPath in $tempPaths) {
if (Test-Path $tempPath) {
try {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Removed temp folder: $tempPath"
$tempRemoved++
}
catch {
Write-Host "Could not remove temp folder: $tempPath"
}
}
}
Write-Host "Removed $tempRemoved temp folders"
# Search for specific driver and installer files
Write-Host "Searching for driver and installer files..."
$specificFiles = @(
"C:\Windows\INF\oem150.inf",
"C:\Drivers\Tobii\Tobii.LenovoYX80.Offline.Installer_*.msi",
"C:\Windows\INF\Tobii Interaction Engine\*"
)
foreach ($filePath in $specificFiles) {
try {
$foundFiles = Get-ChildItem -Path $filePath -Force -ErrorAction SilentlyContinue
if ($foundFiles) {
foreach ($file in $foundFiles) {
try {
Remove-Item -Path $file.FullName -Force -ErrorAction SilentlyContinue
Write-Host "Removed driver/installer file: $($file.FullName)"
}
catch {
Write-Host "Could not remove driver/installer file: $($file.FullName) - $($_.Exception.Message)"
}
}
}
}
catch {
# File doesn't exist, continue
}
}
# Quick cleanup of any remaining specific files (no wildcard searches)
Write-Host "Performing final cleanup of specific files..."
$specificFilesToRemove = @(
"$env:USERPROFILE\.tobii",
"$env:USERPROFILE\.tobii\tobii.tsc.id",
"C:\Users\Administrator\.tobii",
"C:\Users\Administrator\.tobii\tobii.tsc.id"
)
$finalRemoved = 0
foreach ($filePath in $specificFilesToRemove) {
if (Test-Path $filePath) {
try {
Remove-Item -Path $filePath -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Removed: $filePath"
$finalRemoved++
}
catch {
Write-Host "Could not remove: $filePath"
}
}
}
Write-Host "Final cleanup completed. Removed $finalRemoved additional items"
Write-Host ""
Write-Host "================================================"
Write-Host " CLEANUP COMPLETED SUCCESSFULLY!"
Write-Host "================================================"
Write-Host ""
Write-Host "Summary of actions performed:"
Write-Host "✓ Disabled all Tobii, Nahimic, and SpitCamera services"
Write-Host "✓ Terminated all running processes"
Write-Host "✓ Blocked access to all executable files"
Write-Host "✓ Created firewall rules to prevent network access"
Write-Host "✓ Cleaned up all data files and folders"
Write-Host "✓ Removed registry entries and user settings"
Write-Host "✓ Deleted temporary files and cache"
Write-Host "✓ Removed driver and installer files"
Write-Host ""
Write-Host "Total items removed: $($totalRemoved + $registryRemoved + $tempRemoved + $finalRemoved)"
Write-Host ""
Write-Host "IMPORTANT: Please restart your computer now to ensure"
Write-Host "all changes take effect and services stay disabled."
Write-Host ""
Write-Host "Script execution completed at: $(Get-Date)"
Write-Host "================================================"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment