隐藏设备

隐藏设备

突然间,我的鼠标在使用了 6 年后出现在“安全删除硬件”列表中。我想知道为什么这种现象突然在一夜之间发生?从发生这种情况之前到现在,Windows 版本没有更新。

我已经探索并研究过这些解决方案:对于 regedit 解决方案,该值为160,将其减少为 则154没有任何作用。

我也看到了 BAT 文件替代方案。

最初的问题:

在此处输入图片描述

鼠标的属性没有策略选项卡,因此没有可供试用的“快速删除”选项。

在此处输入图片描述

运行rundll32.exe shell32.dll,Control_RunDLL hotplug.dll也没有显示鼠标设备。

在此处输入图片描述

答案1

如果你已经看过这个问题,您知道您必须Capabilities从注册表中的设备更改密钥。

您在该密钥中输入的十六进制数定义了该设备的“功能”。这里您可以看到什么数字定义了每个“能力”。

我以前也遇到过同样的问题,我发现本文,但对我来说没用。在我调整了一些键之后,我终于让它工作了。我分享了我的解决方案,它对我来说很有效,希望这对你有用。


隐藏设备

如果你想隐藏来自“安全删除硬件”的设备:

在你做任何事情之前,请确保创建还原点,或备份您要编辑的注册表项。以防万一。

  1. 在设备管理器的“事件”选项卡中查找您的设备 ID。您只需要VID_XXXX&PID_XXXX部分。

    图片1

  2. 在 中找到该 ID HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\

    图片2

  3. 打开该密钥,您将找到另一个文件夹,进入那里并将密钥更改Capabilities60 十六进制

    图片3

    如果有更多文件夹,请进入每个文件夹并Capabilities以相同的方式更改密钥。

此后,如果您打开“安全删除硬件”列表,您会注意到该设备不再存在。

图片4

该菜单将一直保留,直到您重新启动电脑。然而, HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB 重启后恢复。如果您想使该更改永久生效,您必须在任务计划程序中创建一个任务,以便在每次启动电脑时应用该更改。


使其永久化

  1. 您仍打开着注册表编辑器吗?导出您编辑的密钥,将其保存在某处。

    图片5

  2. .reg使用记事本打开导出的文件,然后删除除Capabilities密钥之外的所有内容。它必须是这样的(就我而言):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_0458&PID_5010\5&2fecf0fe&0&4]
"Capabilities"=dword:00000060
  1. 将其保存在某个地方,就我而言,我将它保存在文件夹中C:\hide\hide.reg

  2. 打开任务计划程序,并创建新的基本任务

    • 按您想要的方式命名。
    • 开始任务当计算机启动时
    • 该行动是启动一个程序
      • 程序或脚本:regedit

      • 参数:/S "<location of your reg file>"

        (就我而言应该是/S "C:\hide\hide.reg"

        此命令将.reg文件合并到注册表中。

  3. 创建任务后,打开其属性,然后更改安全选项,应该是这样的:

    图片6

    • 无论用户是否登录都运行
    • 不存储密码
    • 以最高权限运行

现在,每次您启动 PC 时,在登录之前,此任务都会运行,并从“安全删除硬件”列表中隐藏您的设备。

重新启动您的电脑,“安全删除硬件”图标应该就消失了。

在此处输入图片描述

不用担心,它可以像往常一样用于普通 USB 和其他设备!


但...

只要你不会断开连接或改变你的设备,即使您的 PC 已关闭。如果您这样做,Windows 将重新注册该设备,它将再次出现在“安全删除硬件”列表中。您需要再次执行所有这些步骤。

答案2

Safely Remove Hardware and Eject Media我通过以下方法解决了任务栏中出现不正确的设备的问题:


SetDeviceProperties_NonRemovableFingerprintScanners.verbose.ps1

If ($True) {
  #
  # Disable the 'Safely Remove Hardware and Eject Media' capability for target Plug and Play (PnP) devices
  #
  # Set the class/friendlyname of devices to update
  $PnP_Class = "Biometric";
  $PnP_FriendlyName = "*Fingerprint*";
  # Set the list of capabilities to remove (additional "capabilities bits" listed at the bottom of this script)
  $RemoveCapabilities = @()
  $RemoveCapabilities += 0x00000002;    # CM_DEVCAP_EJECTSUPPORTED  (flags the device as ejectable)
  $RemoveCapabilities += 0x00000004;    # CM_DEVCAP_REMOVABLE       (flags the device as removable)
  # Get the list of devices to remove capabilities from
  Get-PnpDevice -Class "${PnP_Class}" -FriendlyName "${PnP_FriendlyName}" -Status 'OK' -EA:0 | ForEach-Object {
    $InstanceId = (${_}.InstanceId);
    $RegEdit = @{
      Path="Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\${InstanceId}";
      Name="Capabilities";
      Type="DWord";
      Description="Defines the capabilities for a given device. Citation [ https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/um/cfgmgr32.h#L1067-L1076 ]";
    };
    # ------------------------------
    # Parse each device in question
    Write-Host "------------------------------------------------------------";
    If ((Test-Path -Path (${RegEdit}.Path)) -Eq $True) {
      $GetEachItemProp = (Get-ItemPropertyValue -LiteralPath (${RegEdit}.Path) -Name (${RegEdit}.Name) -ErrorAction ("Stop"));
      ${RegEdit}.Value = $GetEachItemProp;
      # Bitwise slice off any instances of the Capability to-remove
      ${RemoveCapabilities} | ForEach-Object {
        # Note that the bitwise AND will be zero if the value doesn't include the value to remove - it will only modify values which require an update.
        ${RegEdit}.Value = ((${RegEdit}.Value) - ((${RegEdit}.Value) -band ${_}));
      }
      If ((${GetEachItemProp}) -Eq (${RegEdit}.Value)) {
        Write-Host "`nInfo:  (Skipped) Registry key `"$(${RegEdit}.Path)`"'s property `"$(${RegEdit}.Name)`" is already set to value `"$(${RegEdit}.Value)`"`n";
      } Else {
        Write-Host "`nInfo:  Setting Registry key `"$(${RegEdit}.Path)`"'s property `"$(${RegEdit}.Name)`" to value `"$(${RegEdit}.Value)`"...`n";
        Set-ItemProperty -LiteralPath (${RegEdit}.Path) -Name (${RegEdit}.Name) -Value (${RegEdit}.Value);
      }
      Write-Host "`nInfo:  Confirming value for Registry key `"$(${RegEdit}.Path)`"'s property `"$(${RegEdit}.Name)`"...";
      Get-ItemProperty -LiteralPath (${RegEdit}.Path) -Name (${RegEdit}.Name);
      # ------------------------------
      # Repeat this process for the parent device
      Write-Host "------------------------------------------------------------";
      $ParentInstanceId = (Get-PnpDeviceProperty -KeyName 'DEVPKEY_Device_Parent' -InstanceId "${InstanceId}" | Select-Object -ExpandProperty "Data" -EA:0);
      $RegEditParent = @{
        Path="Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\${ParentInstanceId}";
        Name="Capabilities";
        Type="DWord";
        Description="Defines the capabilities for a given device. Citation [ https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/um/cfgmgr32.h#L1067-L1076 ]";
      };
      If ((Test-Path -Path (${RegEditParent}.Path)) -Eq $True) {
        $GetEachParentItemProp = (Get-ItemPropertyValue -LiteralPath (${RegEditParent}.Path) -Name (${RegEditParent}.Name) -ErrorAction ("Stop"));
        ${RegEditParent}.Value = $GetEachItemProp;
        # Bitwise slice off any instances of the Capability to-remove
        ${RemoveCapabilities} | ForEach-Object {
          # Note that the bitwise AND will be zero if the value doesn't include the value to remove - it will only modify values which require an update.
          ${RegEditParent}.Value = ((${RegEditParent}.Value) - ((${RegEditParent}.Value) -band ${_}));
        }
        If ((${GetEachParentItemProp}) -Eq (${RegEditParent}.Value)) {
          Write-Host "`nInfo:  (Skipped) Registry key `"$(${RegEditParent}.Path)`"'s property `"$(${RegEditParent}.Name)`" is already set to value `"$(${RegEditParent}.Value)`"`n";
        } Else {
          Write-Host "`nInfo:  Setting Registry key `"$(${RegEditParent}.Path)`"'s property `"$(${RegEditParent}.Name)`" to value `"$(${RegEditParent}.Value)`"...`n";
          Set-ItemProperty -LiteralPath (${RegEditParent}.Path) -Name (${RegEditParent}.Name) -Value (${RegEditParent}.Value);
        }
        Write-Host "`nInfo:  Confirming value for Registry key `"$(${RegEditParent}.Path)`"'s property `"$(${RegEditParent}.Name)`"...";
        Get-ItemProperty -LiteralPath (${RegEditParent}.Path) -Name (${RegEditParent}.Name);
      } Else {
        Write-Host "`nInfo:  (Skipped) Registry key `"$(${RegEditParent}.Path)`" not found to exist`n";
      }
      # End of parent device handling
      # ------------------------------
    } Else {
      Write-Host "`nInfo:  (Skipped) Registry key `"$(${RegEdit}.Path)`" not found to exist`n";
    }
  }
}

请注意,变量$PnP_Class$PnP_FriendlyName(在脚本顶部)应根据具体情况进行设置,以确保脚本仅针对不可移动/弹出的设备


这是上述脚本的精简版本(旨在实现自动化 - 通过任务计划程序运行)

SetDeviceProperties_NonRemovableFingerprintScanners.ps1

If ($True) {
  Get-PnpDevice -Class 'Biometric' -FriendlyName '*Fingerprint*' -Status 'OK' -EA:0 | ForEach-Object {
    $InstanceId = (${_}.InstanceId);
    $RegEdit = @{ Path="Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\${InstanceId}"; Name="Capabilities"; };
    If ((Test-Path -Path (${RegEdit}.Path)) -Eq $True) {
      $GetEachItemProp = (Get-ItemPropertyValue -LiteralPath (${RegEdit}.Path) -Name (${RegEdit}.Name) -ErrorAction ("Stop"));
      ${RegEdit}.Value = ($GetEachItemProp);
      $(0x00000002, 0x00000004) | ForEach-Object {
        ${RegEdit}.Value = ((${Regedit}.Value) - ((${Regedit}.Value) -band ${_}));
      }
      If ((${GetEachItemProp}) -NE (${RegEdit}.Value)) {
        Set-ItemProperty -LiteralPath (${RegEdit}.Path) -Name (${RegEdit}.Name) -Value (${RegEdit}.Value);
      }
      $ParentInstanceId = (Get-PnpDeviceProperty -KeyName 'DEVPKEY_Device_Parent' -InstanceId "${InstanceId}" | Select-Object -ExpandProperty "Data" -EA:0);
      $RegEditParent = @{ Path="Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\${ParentInstanceId}"; Name="Capabilities"; };
      If ((Test-Path -Path (${RegEditParent}.Path)) -Eq $True) {
        $GetEachParentItemProp = (Get-ItemPropertyValue -LiteralPath (${RegEditParent}.Path) -Name (${RegEditParent}.Name) -ErrorAction ("Stop"));
        ${RegEditParent}.Value = $GetEachItemProp;
        $(0x00000002, 0x00000004) | ForEach-Object {
          ${RegEditParent}.Value = ((${RegEditParent}.Value) - ((${RegEditParent}.Value) -band ${_}));
        }
        If ((${GetEachParentItemProp}) -NE (${RegEditParent}.Value)) {
          Set-ItemProperty -LiteralPath (${RegEditParent}.Path) -Name (${RegEditParent}.Name) -Value (${RegEditParent}.Value);
        }
      }
    }
  }
}

以下是上述脚本的一般工作流程...

  1. 使用 PowerShellGet-PnpDevicecmdlet 来定位您希望不再显示为可移动/可弹出媒体的设备。对于每个PnpDevice获取的设备:

  2. 将设备的InstanceId属性附加到静态 USB 设备注册表路径上,例如:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\${InstanceId}

  3. 执行Bitwise AND-band)在设备的Capability价值和每个不需要的功能之间(即CM_DEVCAP_EJECTSUPPORTED0x2) 和CM_DEVCAP_REMOVABLE( )),然后从该值0x4中减去由此得出的结果值。-bandCapability

    • 如果Capability做过包含0x20x4,则-band结果值将包含要从 中减去的准确差分,以Capability仅删除不需要的功能。

    • 如果Capability没有包含 或0x20x4-band的结果为0,并且我们不会减去任何内容(例如,不进行任何更改)

      • 上述脚本还采用这个最终减去的值并将其与原始Capability值进行比较,以查看是否实际上应该执行注册表更新(如果不是,则跳过它)
  4. 对每个设备的父设备(及其关联的InstanceId)重复步骤 2 和 3

    • ⚠️ 这种行为很“有趣”,因为父设备可以包含Capability0x20x4这将导致子设备继续显示为可弹出/可移除

    • 使用 PowerShellGet-PnpDevicePropertycmdlet 针对每个设备(来自步骤 2)以及InstanceIdKeyNameDEVPKEY_Device_Parent并扩展属性Data(从返回的对象)
      • Data字段将产生InstanceId父元素(例如 USB 底座)的,这需要以与原始设备本身相同的方式执行步骤 2 和 3

答案3

更简单的方法:将此行粘贴到记事本中(三次单击并按 ctrl+c,然后按 ctrl+v):

reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Applets\SysTray" /f /v "Services" /t reg_dword /d 29

在记事本的第二行写入:

systray

您希望将 systray 放在单独的行上,因为它实际上是 Windows 中的一个命令,它会导致系统托盘刷新,检查您输入的那些注册表值,这些值每次重新启动都会被删除,因此:

保存名为 hide_sr_icons.cmd 的文件您现在可以运行它来立即隐藏图标,并将其放入 shell:startup 中以便它在您的帐户启动时运行。或 shell:common startup 以便它为所有用户运行。

请注意,它会一直隐藏图标,而不仅仅是鼠标图标。但是,鉴于 Windows 10/11 中 USB 驱动器的默认设置是快速删除,它不再是一个重要的图标。如果需要,您仍然可以在设备和打印机面板中访问相同的功能。

答案4

有点晚了,但是我编写了一个 powershell 脚本,它只是将 Capabilities DWORD 更改为 0x80,因此从托盘图标中删除了该设备。

function Restart-Explorer {

    $explorer = Get-Process explorer
    Stop-Process -Name explorer -Force

    Write-Host "Restart explorer" -ForegroundColor Yellow

}

function Update-RegistryKey {
    param (
        [string]$Path,
        [string]$Name,
        [int]$ExpectedValue, 
        [string]$Type = 'DWORD'  
    )

    # Ensure the registry path exists
    if (-not (Test-Path $Path)) {
        Write-Host "Registry path does not exist: $Path"
        return
    }

    $currentValue = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue

    if ($currentValue -and ($currentValue.$Name -ne $ExpectedValue)) {
        Set-ItemProperty -Path $Path -Name $Name -Value $ExpectedValue -Type $Type
        Write-Host "Updated registry key '$Name' at '$Path' to '$ExpectedValue'." -ForegroundColor Green
        Restart-Explorer
    } elseif (-not $currentValue) {
        New-ItemProperty -Path $Path -Name $Name -Value $ExpectedValue -PropertyType $Type -Force
        Write-Host "Created and set new registry key '$Name' at '$Path' to '$ExpectedValue'."
    } else {
        Write-Host "Registry key '$Name' at '$Path' already matches the expected value."
    }
}


$ACTION = {
    $changeType = switch ($EventArgs.NewEvent.EventType) {
        1 {"Configuration changed"} 
        2 {"Device Arrived"}         # Device connected
        3 {"Device Removed"}     
        4 {"Device Docked"}         
        default {"Unknown Change"}
    }

    $time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    if ($changeType -eq "Device Arrived") {
        $qDevices = Get-WmiObject -Query "SELECT * FROM Win32_PnPEntity WHERE Description LIKE '%Billboard%'"

        foreach ($device in $qDevices) {
            $deviceInfo = "Device ID: $($device.DeviceID), Description: $($device.Description), Name: $($device.Name), Manufacturer: $($device.Manufacturer)"
            Write-Host "${time}: $changeType - $deviceInfo"
            Update-RegistryKey -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\$($device.DeviceID)" -Name "Capabilities" -ExpectedValue 128
            
        }
    }     
}

# Clear existing subscriptions if present
if (Get-EventSubscriber -SourceIdentifier deviceChange -ErrorAction SilentlyContinue) {
    Unregister-Event -SourceIdentifier deviceChange
}

Register-WmiEvent -Class 'Win32_DeviceChangeEvent' -SourceIdentifier deviceChange -Action $ACTION
Write-Host "deviceChange Service ready!" -ForegroundColor DarkYellow

在任务计划程序中创建新任务

  1. 新基本任务
  2. 登录时
  3. 选择启动程序

对于程序输入powershell.exe,对于参数使用-NoExit -WindowStyle Hidden -ExecutionPolicy Unrestricted -File "D:\Path_to_Script.ps1"

确保任务以最高权限运行。

更改设备组

只需将一个附加OR Description LIKE '%Mouse%'到:

$qDevices = Get-WmiObject -Query "SELECT * FROM Win32_PnPEntity WHERE Description LIKE '%Billboard%' OR Description LIKE '%Mouse%'"

通常,FriendlyName 中的所有内容都可以用作描述。

结论

虽然这个助手远非完美,但它仍然有效,即使设备拔下并重新连接。

感谢@moxwel,他的回答给了我很大的启发和帮助。

相关内容