使用 Powershell 删除不存在的网络适配器

Using Powershell to remove non present network adapters

我正在尝试通过 PowerShell 自动执行一些我必须执行的耗时任务来制作新的 VM 模板,其中之一是从 VM 中删除所有 NIC 并清理设备管理器不存在的设备。

从 VM 中删除 NIC 后,我尝试使用以下代码片段来清理设备管理器,它们执行相同的操作。

wmic nic where "(servicename is null)" delete

gwmi win32_networkadapter | ?{$_.ServiceName -eq $null} | rwmi

在这两种情况下,我都收到错误 "Provider is not capable of the attempted operation"。查看 WMI-Activity 的事件日志似乎没有帮助:ResultCode = 0x80041024;可能的原因 = 未知。

有没有人能够做类似的事情来删除不存在的设备或能够发现上述命令的问题?

编辑: 我试过使用 DevCon 删除设备,但它似乎只适用于现有设备。我现在正在梳理注册表以查看是否有一个特定的键或一组键,如果删除这些键会从设备管理器中删除 NIC。

此注册表项包含注册表中计算机的所有硬件设置:
HKEY_LOCAL_MACHINE\system\currentcontrolset\enum

首先通过 WMI 查询当前和启用的网络适配器并获取它们的 PNPDeviceId。该值将告诉您网络适配器位于哪个子项中。

接下来查询每个子项的注册表并找到所有适配器。解析完整的注册表项以减少到与 PNPDeviceId 值相同的长度;大致 PCI\VEN_80AD&DEV_15A2&SUBSYS_062D1028&REV_02&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'"
}

对之前脚本的一些改动。

# 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
}

这个困扰了我一段时间,我想出了更多的手动方法,但它有效,所以希望这会帮助其他人:

1) 首先确保您要清除的设备列表是正确的:

Get-PnpDevice -class net | ? Status -eq Unknown | Select FriendlyName,InstanceId

2) 如果您对 Get-NetAdapters 的列表感到满意,您将要开始 Kaibosh,运行 以下内容:

$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*")!

感谢this page. I improved that script a bit and published it through my repo here: removeGhosts.ps1

,我设法解决了类似的问题

在这个版本中删除所有隐藏的网络设备可以像这样完成:

$ removeGhosts.ps1 -narrowbyclass Net

这将在删除之前要求对每个设备进行确认,-Force 选项可以抑制此行为。如果没有任何选项,脚本将删除所有隐藏的设备,这听起来像是提问者也感兴趣的东西。