使用 Powershell 删除不存在的网络适配器
Posted
技术标签:
【中文标题】使用 Powershell 删除不存在的网络适配器【英文标题】:Using Powershell to remove non present network adapters 【发布时间】:2015-07-02 17:35:25 【问题描述】:我正在尝试通过 PowerShell 自动执行一些耗时的任务,我必须执行这些任务来制作新的 VM 模板,其中之一是从 VM 中删除所有 NIC 并清理不存在的设备管理器设备。 从 VM 中删除 NIC 后,我尝试使用以下代码 sn-ps 来清理设备管理器。
wmic nic where "(servicename is null)" delete
gwmi win32_networkadapter | ?$_.ServiceName -eq $null | rwmi
在这两种情况下,我都会收到错误“提供程序无法进行尝试的操作”。查看 WMI-Activity 的事件日志似乎没有帮助:ResultCode = 0x80041024;可能的原因 = 未知。
有没有人能够做类似的事情来删除不存在的设备或能够找到上述命令的问题?
编辑:我尝试使用 DevCon 删除设备,但它似乎只适用于现有设备。我现在正在梳理注册表,看看是否有一个特定的键或一组键,如果删除它会从设备管理器中删除 NIC。
【问题讨论】:
我不相信powershell支持这个功能,你只能禁用设备,不能安装/卸载设备驱动程序。不过,总有一些不错的旧命令行工具可以从 powershell 调用:support.microsoft.com/en-us/kb/311272 感谢知识库。我希望能够使用内置命令行而不是其他工具,但我想我必须尝试使用 DevCon。 尝试使用 DevCon 并遇到错误(删除失败),在一些论坛上阅读并看到 DevCon 仅适用于当前设备。 【参考方案1】:这个问题困扰了我一段时间,我想出了更多的手动方法,但它确实有效,所以希望这对其他人有帮助:
1) 首先确保您要清除的设备列表是正确的:
Get-PnpDevice -class net | ? Status -eq Unknown | Select FriendlyName,InstanceId
2) 如果您对即将使用 Kaibosh 的 Get-NetAdapter 列表感到满意,请运行以下命令:
$Devs = Get-PnpDevice -class net | ? Status -eq Unknown | Select FriendlyName,InstanceId
ForEach ($Dev in $Devs)
Write-Host "Removing $($Dev.FriendlyName)" -ForegroundColor Cyan
$RemoveKey = "HKLM:\SYSTEM\CurrentControlSet\Enum\$($Dev.InstanceId)"
Get-Item $RemoveKey | Select-Object -ExpandProperty Property | % Remove-ItemProperty -Path $RemoveKey -Name $_ -Verbose
Write-Host "Done. Please restart!" -ForegroundColor Green
注意:您在步骤 1 中的适配器列表必须仅包含您要清除的适配器。如果您有额外内容,请相应调整过滤器(?Status -eq XXX,例如:?FriendlyName -like "Broadcom*")!
【讨论】:
不删除属性“HKLM:\SYSTEM\CurrentControlSet\Enum”需要 NT AUTHORITY\SYSTEM 权限吗? @tormentum:脚本似乎运行良好,但如果只有一台网络设备的状态为未知,我会遇到一些问题。在这种情况下,ForEach 循环的行为似乎有所不同。你知道吗,为什么? @Aleph0:要强制 Powershell 管道成为一个数组,即使只有一个元素,也可以用 @( ... ) 包围管道:$Devs = @(Get-PnpDevice -class net | ? Status -eq Unknown | Select FriendlyName,InstanceId)
@KatieStafford:非常感谢您的评论,我会尽快尝试。【参考方案2】:
感谢this page,我设法解决了类似的问题。我稍微改进了该脚本并通过我的仓库发布了它:removeGhosts.ps1
在这个版本中删除所有隐藏的网络设备可以这样完成:
$ removeGhosts.ps1 -narrowbyclass Net
这将在删除之前要求确认每个设备,-Force
选项可以抑制此行为。如果没有任何选项,脚本将删除所有隐藏的设备,这听起来像是提问者也感兴趣的东西。
【讨论】:
我浏览了这个脚本并试了一下。它似乎工作得很好,尽管它有很多无法抑制的输出。在我可以在我的脚本中使用它之前,我必须把它全部敲掉,并且主要代码似乎是某种形式的 C。 好主意,我应该添加一些详细程度。【参考方案3】:此注册表项包含注册表中机器的所有硬件设置:HKEY_LOCAL_MACHINE\system\currentcontrolset\enum 首先通过 WMI 查询当前和启用的网络适配器并获取它们的 PNPDeviceId。此值将告诉您网络适配器位于哪个子项中。 接下来查询每个子项的注册表并找到所有适配器。解析完整的注册表项以减少到与 PNPDeviceId 值相同的长度;大致是 PCI\VEN_80AD&DEV_15A2&SUBSYS_062D1028&REV_02\2&11483669&0&C9。 比较这两个列表并找到任何孤立的注册表项。找到后,通过枚举系统帐户删除注册表项将从设备管理器中删除网络适配器。我使用 PSExec.exe 作为系统帐户运行 reg delete 命令。这里有一些代码来执行我刚才解释的操作。
# Declare variables
[string]$regIds = "";
[string]$Orphans = "";
[array]$SubKeys = @();
[array]$RegKeys = @();
# Query the present and enabled Network Adapters for the PNPDeviceId value
[array]$PNPDeviceIds = (gwmi Win32_NetworkAdapter -Filter "NetEnabled = true").PNPDeviceId;
for ($i = 0; $i -lt $PNPDeviceIds.Count; $i++)
if ($SubKeys -NotContains $($PNPDeviceIds[$i].Split('\')[0] + "\" + $PNPDeviceIds[$i].Split('\')[1]))
$SubKeys += $($PNPDeviceIds[$i].Split('\')[0] + "\" + $PNPDeviceIds[$i].Split('\')[1]);
# Query the registry for all of the adapters
foreach ($SubKey in $SubKeys)
[array]$Keys = reg query "hklm\system\currentcontrolset\enum\$SubKey"
$Keys = $Keys[1..$($Keys.Count -1)];
$RegKeys += $Keys;
# Parse the Keys
for ($i = 0; $i -lt $RegKeys.Count; $i++) $regIds += "," + $($RegKeys[$i].Split('\')[4..6] -join '\');
$regIds = $regIds.TrimStart(",");
# Compare the registry to the present devices
for ($i = 0; $i -lt $regIds.Split(',').Count; $i++)
if ($PNPDeviceIds -NotContains $regIds.Split(',')[$i])
$Orphans += "," + $regIds.Split(',')[$i];
if ($Orphans.Length -gt 0) $Orphans = $Orphans.TrimStart(",");
# Delete the non-present devices
foreach ($Orphan in $Orphans)
psexec.exe -s powershell.exe "reg delete 'hklm\system\currentcontrolset\enum\$Orphan'"
【讨论】:
我收到一个错误:psexec.exe:术语“psexec.exe”未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。检查名称的拼写,如果包含路径,请验证路径是否正确并重试。 您需要将来自 PSTools download 的 psexec.exe 放在与您执行脚本的文件夹相同的文件夹中。或者干脆把它放到 C:\Windows\System32 文件夹中。【参考方案4】:previos 脚本的一些更改。
# Declare variables
[string]$regIds = "";
[string]$Orphan = "";
[array]$Orphans = @();
[array]$SubKeys = @();
[array]$RegKeys = @();
# Query the present and enabled Network Adapters for the PNPDeviceId value
[array]$PNPDeviceIds = (gwmi Win32_NetworkAdapter -Filter "NetEnabled = true").PNPDeviceId;
for ($i = 0; $i -lt $PNPDeviceIds.Count; $i++)
if ($SubKeys -NotContains $($PNPDeviceIds[$i].Split('\')[0] + "\" + $PNPDeviceIds[$i].Split('\')[1]))
$SubKeys += $($PNPDeviceIds[$i].Split('\')[0] + "\" + $PNPDeviceIds[$i].Split('\')[1])
# Query the registry for all of the adapters
foreach ($SubKey in $SubKeys)
[array]$Keys = reg query "hklm\system\currentcontrolset\enum\$SubKey"
$Keys = $Keys[1..$($Keys.Count -1)];
$RegKeys += $Keys
# Parse the Keys
for ($i = 0; $i -lt $RegKeys.Count; $i++)
$regIds += "," + $($RegKeys[$i].Split('\')[4..6] -join '\');
$regIds = $regIds.TrimStart(",")
# Compare the registry to the present devices
for ($i = 0; $i -lt $regIds.Split(',').Count; $i++)
if ($PNPDeviceIds -NotContains $regIds.Split(',')[$i])
$Orphan += "," + $regIds.Split(',')[$i]
if ($Orphan.Length -gt 0)
$Orphan = $Orphan.TrimStart(",")
# Debug: Write-Host "Orphan.Lenght = "$Orphan.Length
# Parse into Objects
for ($i = 0; $i -lt $Orphan.Split(',').Count; $i++)
$Orphans += $Orphan.Split(',')[$i]
# Debug: Write-Host "Orphans = $Orphans Orphans.Lenght = "$Orphans.Length
$Orphan = ""
# Delete the non-present devices
foreach ($Orphan in $Orphans)
$Orphan = "HKLM:\System\CurrentControlSet\Enum\" + $Orphan
Write-Host "You must have Full Rights and You should be Owner" - ForegroundColor Black -BackgroundColor White
Write-Host "Deleting KEY: " -NoNewline
Write-Host $Orphan -ForegroundColor Yellow -NoNewline
If (Test-Path -Path $Orphan)
Remove-Item -Path $Orphan -Force -Recurse -Confirm:$false -ErrorAction SilentlyContinue
if (Test-Path -Path $Orphan)
Write-Host " UnSuccsessfully!" -ForegroundColor Red
Write-Host $Error[0] -ForegroundColor Cyan
else
Write-Host " Succsessfully!" -ForegroundColor Green
else
Write-Host " Error! Path does not exist." -ForegroundColor Red
else
Write-Host "Unused Network Adapters not be found." -ForegroundColor Yellow
【讨论】:
欢迎来到 SO。您能否为您更改的脚本提供相同的信息,好吗?什么比 Hive 已经发布的脚本更好/不同。谢谢。 再一次,除非我们也更改权限,否则我们将没有对该注册表位置的任何权限,因此 Hive 说使用 psexec -s。所以,这个脚本不起作用。我没有阅读足够的内容来看看它是否有用。 不要使用!该脚本有一行 gwmi Win32_NetworkAdapter -Filter "NetEnabled = true" 这将导致删除此处未返回的任何内容的注册表项,但会删除 WAN 微型端口适配器、Microsoft 内核调试网络适配器以及其他不应该的内容删除。所以,这个解决方案是在丢弃可能不应该的东西,而不仅仅是被移除的隐藏的“幽灵”设备。以上是关于使用 Powershell 删除不存在的网络适配器的主要内容,如果未能解决你的问题,请参考以下文章
PowerShell Get-NetAdapter 查看网络适配器的参数
检查Windows服务是否存在并在PowerShell中删除
如果 VLAN 尚未启用,则启用 VLAN 并使用 powershell 脚本设置 VLAN ID
mac 用parallels desktop 安装 win7出现无法加载parallels 驱动和物理网络适配器连接虚拟网络适配器不存在