突然间,我的鼠标在使用了 6 年后出现在“安全删除硬件”列表中。我想知道为什么这种现象突然在一夜之间发生?从发生这种情况之前到现在,Windows 版本没有更新。
我已经探索并研究过这些解决方案:对于 regedit 解决方案,该值为160
,将其减少为 则154
没有任何作用。
我也看到了 BAT 文件替代方案。
最初的问题:
鼠标的属性没有策略选项卡,因此没有可供试用的“快速删除”选项。
运行rundll32.exe shell32.dll,Control_RunDLL hotplug.dll
也没有显示鼠标设备。
答案1
如果你已经看过这个问题,您知道您必须Capabilities
从注册表中的设备更改密钥。
您在该密钥中输入的十六进制数定义了该设备的“功能”。这里您可以看到什么数字定义了每个“能力”。
我以前也遇到过同样的问题,我发现本文,但对我来说没用。在我调整了一些键之后,我终于让它工作了。我分享了我的解决方案,它对我来说很有效,希望这对你有用。
隐藏设备
如果你想隐藏来自“安全删除硬件”的设备:
在你做任何事情之前,请确保创建还原点,或备份您要编辑的注册表项。以防万一。
在设备管理器的“事件”选项卡中查找您的设备 ID。您只需要
VID_XXXX&PID_XXXX
部分。在 中找到该 ID
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\
。打开该密钥,您将找到另一个文件夹,进入那里并将密钥更改
Capabilities
为60 十六进制。如果有更多文件夹,请进入每个文件夹并
Capabilities
以相同的方式更改密钥。
此后,如果您打开“安全删除硬件”列表,您会注意到该设备不再存在。
该菜单将一直保留,直到您重新启动电脑。然而, HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB
重启后恢复。如果您想使该更改永久生效,您必须在任务计划程序中创建一个任务,以便在每次启动电脑时应用该更改。
使其永久化
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_0458&PID_5010\5&2fecf0fe&0&4]
"Capabilities"=dword:00000060
将其保存在某个地方,就我而言,我将它保存在文件夹中
C:\hide\hide.reg
打开任务计划程序,并创建新的基本任务:
- 按您想要的方式命名。
- 开始任务当计算机启动时。
- 该行动是启动一个程序。
程序或脚本:
regedit
参数:
/S "<location of your reg file>"
(就我而言应该是
/S "C:\hide\hide.reg"
)此命令将
.reg
文件合并到注册表中。
创建任务后,打开其属性,然后更改安全选项,应该是这样的:
- 无论用户是否登录都运行
- 不存储密码
- 以最高权限运行
现在,每次您启动 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);
}
}
}
}
}
以下是上述脚本的一般工作流程...
使用 PowerShell
Get-PnpDevice
cmdlet 来定位您希望不再显示为可移动/可弹出媒体的设备。对于每个PnpDevice
获取的设备:将设备的
InstanceId
属性附加到静态 USB 设备注册表路径上,例如:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\${InstanceId}
执行
Bitwise AND
(-band
)在设备的Capability
价值和每个不需要的功能之间(即CM_DEVCAP_EJECTSUPPORTED
(0x2
) 和CM_DEVCAP_REMOVABLE
( )),然后从该值0x4
中减去由此得出的结果值。-band
Capability
如果
Capability
值做过包含0x2
或0x4
,则-band
结果值将包含要从 中减去的准确差分,以Capability
仅删除不需要的功能。如果
Capability
值没有包含 或0x2
,0x4
则-band
的结果为0
,并且我们不会减去任何内容(例如,不进行任何更改)- 上述脚本还采用这个最终减去的值并将其与原始
Capability
值进行比较,以查看是否实际上应该执行注册表更新(如果不是,则跳过它)
- 上述脚本还采用这个最终减去的值并将其与原始
对每个设备的父设备(及其关联的
InstanceId
)重复步骤 2 和 3-
⚠️ 这种行为很“有趣”,因为父设备可以包含
Capability
或0x2
,0x4
这将导致子设备继续显示为可弹出/可移除 - 使用 PowerShell
Get-PnpDeviceProperty
cmdlet 针对每个设备(来自步骤 2)以及InstanceId
KeyNameDEVPKEY_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
在任务计划程序中创建新任务
- 新基本任务
- 登录时
- 选择启动程序
对于程序输入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,他的回答给了我很大的启发和帮助。