使用 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中不存在特定对象属性时如何删除条目?

powershell 删除原始不存在的分支

PowerShell Get-NetAdapter 查看网络适配器的参数

检查Windows服务是否存在并在PowerShell中删除

如果 VLAN 尚未启用,则启用 VLAN 并使用 powershell 脚本设置 VLAN ID

mac 用parallels desktop 安装 win7出现无法加载parallels 驱动和物理网络适配器连接虚拟网络适配器不存在