简介:面向 Windows Server 2016 系统部署与运维人员的 Intel 网卡驱动合集,针对 I217-LM/V、I218-LM/V、I219-LM/V 等常见千兆以太网控制芯片,解决系统重装、服务器迁移或驱动缺失后网卡无法识别、网络连接异常等问题,也可用于旧机型驱动升级与兼容性排查。压缩包共 110 个文件,约 29.02MB,包含 exe 安装程序、htm 帮助与安装向导页面、css 样式文件、gif/png 界面示意图、pdf 说明文档及 txt 版本信息等;安装程序负责驱动部署,网页与图示便于查看操作指引,文档则记录版本与适配说明,目录组织相对完整。已有 7935 人学习下载,说明该驱动包在同类旧平台维护场景中具有较高参考价值。读者可获得与 Intel Network Connections Software 26.3 对应的驱动安装入口、适配型号清单和界面化操作提示,便于在无网络环境下离线部署,并依据文档快速核对硬件型号与系统版本,减少反复搜索驱动的时间。
1. Windows Server 2016 网卡驱动认不出,多半不是驱动坏了
机房上架一台二手机架机,系统盘是前面的人做好的 Windows Server 2016 镜像,开机能进桌面,设备管理器里却躺着一个带黄色叹号的“以太网控制器”,四个网口一个都不亮。这种情况十有八九不是系统坏了,而是 Windows Server 2016 网卡驱动这一环没接上:Server 版镜像自带的驱动库比同代客户端系统保守得多,不少服务器 Intel 网卡、尤其是板载千兆和后期才铺开的万兆芯片,根本不在内置 inf 列表里。
接下来要解决的问题很具体:手上有一台认不出网卡的 2016,或者要批量装十几台,怎么从硬件 ID 一路走到驱动注入、再走到“装上了但不通”的排查。刚接触的人可以按章节顺序照做,做过几轮的可以直接跳到第 5 章看那几条翻车记录。
2. 先定芯片再找驱动:从硬件 ID 反查 inf 的支持范围
驱动这活儿最容易犯的错,是拿到一台机器就直接搜“某某型号 驱动”,下载一个 exe 双击下一步。服务器场景下这么干,轻则装上管理套件把系统搞脏,重则装错分支导致网口时通时断。正确的顺序是先拿到硬件 ID,确认这颗芯片的 DEV 号,再去驱动包里比对 inf 的匹配段——这一步做扎实,后面能省掉一大半返工。
2.1 无网环境里把 PCI 硬件 ID 读出来
机器没网,图形界面反而最快:设备管理器里找到带叹号的那个设备,右键属性 → 详细信息 → 属性下拉选“硬件 Id”,会看到类似PCI\VEN_8086&DEV_1533&SUBSYS_00008086&REV_03这样一串。这四段分别对应厂商、设备、子系统、版本号,是后面所有判断的依据。
如果要批量做或者要留档,PowerShell 更合适。Server 2016 自带 PnpDevice 模块,下面这段能把所有状态异常的网络设备连同硬件 ID 一次导出:
# 列出所有处于 Error / Unknown 状态的网络类设备 Get-PnpDevice -Class Net -Status Error,Unknown | Select-Object FriendlyName, Status, InstanceId | Format-List # 逐个取硬件 ID,用于和 inf 比对 Get-PnpDevice -Class Net -Status Error | ForEach-Object { $ids = (Get-PnpDeviceProperty -InstanceId $_.InstanceId ` -KeyName 'DEVPKEY_Device_HardwareIds').Data [pscustomobject]@{ Name = $_.FriendlyName HwIds = ($ids -join ' | ') } } | Format-List-Status支持 Error、Unknown、OK、Degraded 等取值,这里只捞异常设备,避免把已经正常的网口混进来。DEVPKEY_Device_HardwareIds返回的是一个字符串数组,通常包含一条带 SUBSYS 的完整 ID 和一条精简 ID,用-join拼起来是为了日志里一行能看全。
如果系统压根进不去,PE 里又没有可用的查询工具,还有一个笨但有效的办法:找一个 Linux 启动盘进 Live 环境,执行lspci -nn | grep -i ethernet,方括号里就是[8086:1533]这样的厂商号和设备号,十六进制,直接拿去比对。
2.2 读懂 VEN/DEV 三段,判断该找哪个驱动分支
VEN_8086是厂商代码,DEV_xxxx才是真正决定用哪个驱动的字段。同一个厂商下面有几十颗芯片,驱动包也是按芯片族分的,认错 DEV 号就会下错包。下面这张表是我在机房里最常撞见的几颗,DEV 号以设备管理器实际读数为准,不同 stepping 可能有细微差别:
| 芯片族 | 典型 DEV ID | Server 2016 内置 | 常见驱动分支 |
|---|---|---|---|
| 板载千兆 I219-LM | 15B8 / 15BD | 多数不内置 | 客户端网卡驱动包,需手动指定 |
| 千兆四口 I350 | 1521 | 内置 | 一般免装,装也只装 inf |
| 千兆 I210 | 1533 | 内置 | 同上 |
| 万兆双口 82599ES | 10FB | 内置 | 免装,重点在光模块 |
| 万兆 X710 | 1572 | 部分版本不内置 | 服务器网卡驱动包,按 Winx64 目录取 |
表格里“内置”这一列的含义是:装完系统无需额外操作,设备管理器里已经正常识别。判断方法很简单,装完系统先看一眼,认得出的就别折腾,认不出的再按 DEV 号去找对应分支。我见过有人给一块已经正常的 I350 又装了一遍厂商套件,结果 PROSet 服务和 Hyper-V 的虚拟交换服务抢网卡控制权,重启后管理口失联,只能进带外管理救回来。
还有一层容易忽略:驱动包的 inf 里写的是“装饰器 + 架构”,比如NTamd64.10.0...14393或NTamd64.10.0...16299。Server 2016 的内核版本是 10.0.14393,只能匹配小于等于这个版本号的装饰器。面向更高版本客户端系统打包的驱动,在 2016 上会直接报“找不到兼容的驱动程序”,第 5 章第一条会展开讲。
2.3 驱动包的三种形态,服务器上怎么选
同一个芯片,厂商一般会放出三种东西,选错了不是装不上,就是装出一堆用不着的后台服务:
| 形态 | 内容 | 适用场景 | 我的取舍 |
|---|---|---|---|
| 完整安装包(exe/zip) | 驱动 + 管理套件 + 团队工具 + 诊断服务 | 需要做网卡绑定、抓包诊断 | 服务器上一般不装,非必要不开服务 |
| 纯 inf 目录 | Winx64 下若干 inf/sys/cat | 批量装机、离线注入 | 首选,dism 和 pnputil 都能吃 |
| OEM 定制包 | 厂商整机厂重新打包,含机型校验 | 原厂整机、要过保修 | 整机场景优先,避免兼容性扯皮 |
选纯 inf 目录有个前提:目录结构要完整,inf 引用的 sys 和 cat 必须同级或在其子目录里,缺一个文件 dism 就会在提交阶段报错,而且报的错往往指向一个不相干的行号。我一般先把整个 Winx64 目录原样拷到本地磁盘再操作,不从压缩包里直接挂载路径。
3. 离线注入:DISM 挂载、pnputil 与应答文件三条路
批量装机和单机装机的做法不一样。单机可以进系统后手动指定 inf,批量就得把驱动提前塞进安装介质,否则每台机器都要重复一遍“进系统、插 U 盘、装驱动、再配网”的循环。这一章给三条路径,按“介质级 → 系统级 → 无人值守级”排列,实际项目里往往三条都用上。
3.1 用 DISM 把 inf 打进 boot.wim 和 install.wim
boot.wim 决定安装界面能不能认出网卡(要走网络部署就必须解决),install.wim 决定装完之后系统里有没有驱动。两个都要处理,只做后者的话,装机过程中到“正在准备设备”那一步可能卡很久甚至失败。
:: 建挂载点,路径别带空格 mkdir C:\mnt\boot mkdir C:\mnt\install :: 挂载 boot.wim,index 2 通常是 Setup 环境 dism /Mount-Wim /WimFile:D:\sources\boot.wim /Index:2 /MountDir:C:\mnt\boot :: 注入整个驱动目录,/Recurse 会遍历子目录 dism /Image:C:\mnt\boot /Add-Driver /Driver:E:\drv\Winx64 /Recurse :: 卸载并提交改动,漏掉 /Commit 等于白干 dism /Unmount-Wim /MountDir:C:\mnt\boot /Commit/Index:2这个值不能想当然,先用dism /Get-WimInfo /WimFile:D:\sources\boot.wim确认,有的介质只有 1 个索引,有的有 3 个。/Recurse是必须的,驱动包一般按芯片族分子目录,不递归只会扫到最外层。/ForceUnsigned不建议加,它会把签名校验绕过去,装完系统在启用安全启动的机器上可能直接起不来。
install.wim 往往有多个索引(标准版、数据中心版、带体验版),逐个处理比较稳:
$wim = 'D:\sources\install.wim' Get-WindowsImage -ImagePath $wim | ForEach-Object { $idx = $_.ImageIndex Write-Host "处理索引 $idx ..." Mount-WindowsImage -ImagePath $wim -Index $idx -Path C:\mnt\install Add-WindowsDriver -Path C:\mnt\install -Driver E:\drv\Winx64 -Recurse Dismount-WindowsImage -Path C:\mnt\install -Save }Dismount-WindowsImage -Save对应命令行里的/Commit,忘了这个参数,挂载目录里改的东西全部丢弃,而且下一次挂载会报“该映像已挂载”。真遇到残留挂载,用Get-WindowsImage -Mounted查,再Dismount-WindowsImage -Discard清掉。
注入完成后,建议做一次验证而不是直接拿去装机:Get-WindowsDriver -Path C:\mnt\install | Where-Object { $_.ProviderName -notlike 'Microsoft*' },能看到刚打进去的第三方驱动列表和版本号,条数和目录里的 inf 数量对得上才算成功。
3.2 pnputil 在线安装与驱动库保留
系统已经跑起来了,只差驱动,这时候不必重做介质,用 pnputil 把 inf 加进驱动库最省事。Server 2016 的 pnputil 支持新版语法,也兼容旧参数:
# 新版语法:把目录下所有 inf 加入驱动库并尝试安装 pnputil /add-driver E:\drv\Winx64\*.inf /install /subdirs # 如果提示参数无法识别,退回旧语法 # pnputil -i -a E:\drv\Winx64\*.inf # 列出驱动库里的第三方包,拿到 oemXX.inf 编号 pnputil /enum-drivers/install表示加入之后立刻对匹配的设备执行安装,不加这个参数只是把包放进驱动库、设备管理器里仍然需要手动“更新驱动程序”。/subdirs让 pnputil 递归子目录,和 dism 的/Recurse作用一致。执行完一定要跑/enum-drivers,输出里的Published Name就是oem12.inf这类编号,后面排查和回滚全靠它。
一个实操细节:pnputil 对通配符的处理在不同版本上表现不一致,*.inf在某些补丁级别下只处理第一个匹配项。稳妥的写法是在 PowerShell 里自己遍历:
Get-ChildItem E:\drv\Winx64 -Filter *.inf -Recurse | ForEach-Object { Write-Host "安装 $($_.FullName)" pnputil /add-driver $_.FullName /install }这样每条命令的输出都能对上具体文件,哪个包失败一眼看得出来,不用在一大片输出里翻。
3.3 无人值守应答文件里加一道最基本的保障
介质注入解决的是“系统自带”,应答文件解决的是“装完第一次开机就有网”。在windowsPE阶段挂驱动路径,安装程序会在分区前把驱动加载进临时环境:
<settings pass="windowsPE"> <component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> <DriverPaths> <PathAndCredentials wcm:action="add" wcm:keyValue="1"> <Path>E:\drv\Winx64</Path> </PathAndCredentials> </DriverPaths> </component> </settings>wcm:keyValue在多条路径时必须唯一,重复了会静默只取一条。Path写的是安装介质在 WinPE 下挂载后的盘符,U 盘和虚拟光驱的盘符不固定,这一点最容易出错,稳妥做法是把驱动目录直接放进 ISO 根目录,然后用相对固定的盘符引用,或者在windowsPE阶段先用脚本枚举。
再补一层保障:在镜像里放一个SetupComplete.cmd,系统装完、首次登录前自动跑一遍 pnputil,把那些“注入没生效”的漏网设备补上。这个脚本里不要写重启命令,也不要弹交互,安安静静装完写个日志就行:
@echo off pnputil /add-driver C:\drv\Winx64\*.inf /install /subdirs >> C:\Windows\Temp\nicdrv.log 2>&14. 装上了却不通:链路、签名、绑定的排查顺序
设备管理器里叹号消失、网口灯亮起,只说明驱动加载成功,离“能通”还有一段距离。这个阶段最容易乱,有人上来就换驱动版本,有人直接重装系统,实际上按链路层 → 系统层 → 虚拟化层的顺序看,绝大多数问题五分钟内能定位。
4.1 先看链路层,别急着换驱动
第一步永远是看协商结果,而不是看驱动版本:
# 网卡状态、速率、MAC Get-NetAdapter | Format-Table Name, InterfaceDescription, Status, LinkSpeed, MacAddress -AutoSize # 高级属性,速率双工、巨型帧、VLAN 都在这 Get-NetAdapterAdvancedProperty -Name 'Ethernet' | Format-Table DisplayName, DisplayValue -AutoSizeLinkSpeed显示1 Gbps而交换机侧是万兆,说明协商没上去,重点查光模块和线缆,不是驱动。Status为Disconnected但灯亮,通常是交叉线序或者对端端口被 shutdown。高级属性里的显示名是驱动自带的,不同厂商叫法不一样,有的叫Speed & Duplex,有的叫链路速度,所以先用Get-列出真实名称,再用Set-去改:
Set-NetAdapterAdvancedProperty -Name 'Ethernet' ` -DisplayName 'Speed & Duplex' -DisplayValue '10 Gbps Full Duplex'万兆光口还有个纯硬件问题:SFP+ 模块有厂商编码校验,第三方模块插上去链路起不来,系统里看什么都是正常的,就是LinkSpeed一直为空。这种情况换原厂模块最快,改驱动参数绕过去不值当,也不稳定。
4.2 签名、oemXX.inf 与回退路径
驱动装上但设备反复重启后失效,先看签名和重复安装。用pnputil /enum-drivers找同一个 DEV 号是否对应了多个 oem 包,两个版本的 inf 抢一个设备,表现就是时好时坏:
# 导出所有第三方驱动包,重点看 Provider / Class / Version Get-WindowsDriver -Online -All | Where-Object { $_.ClassName -eq 'Net' } | Select-Object Driver, ProviderName, Version, Date | Sort-Object ProviderName, Version | Format-Table -AutoSize发现重复的旧包,按编号删除,/uninstall会连带卸载设备上的驱动,/force用于设备正在使用时的强制删除:
pnputil /delete-driver oem12.inf /uninstall /force删完必须重启,否则驱动文件还挂在内存里,下次开机又会被重新关联。回退的优先顺序是:设备管理器里的“回退驱动程序” →pnputil /delete-driver删新装包 → 系统还原点。第三条在服务器上经常没有,因为很多人装完系统第一件事就是关系统保护,所以前两条要练熟。
签名这块,Server 2016 默认强制驱动签名,未签名或签名链不完整的包会被拒绝加载,事件日志里能看到代码完整性相关的记录。测试环境可以用bcdedit /set testsigning on临时放开,但启用安全启动的机器上这个开关无效,而且生产环境开它等于把整机信任链拆了,我不建议在任何对外提供服务的机器上这么干。
4.3 LBFO 团队和 Hyper-V 虚拟交换机的抢占
多口网卡最常见的需求是做绑定。Server 2016 有两套机制:传统的 LBFO 团队,和 Hyper-V 用的 SET(内嵌团队)。两者对同一组物理网口是互斥的,先建了虚拟交换机,再用New-NetLbfoTeam就会报“找不到可用的网络适配器”。
# 传统 LBFO 团队,LACP 需要交换机侧同步配置 New-NetLbfoTeam -Name Team1 -TeamMembers 'Ethernet','Ethernet 2' ` -TeamingMode LACP -LoadBalancingAlgorithm Dynamic # Hyper-V 场景用 SET,把物理口直接交给虚拟交换机 New-VMSwitch -Name vSwitch1 -NetAdapterName 'Ethernet','Ethernet 2' ` -EnableEmbeddedTeaming $true -AllowManagementOS $true-TeamingMode有 Static、LACP、SwitchIndependent 三种,交换机侧没配链路聚合就必须用 SwitchIndependent,否则环路。-LoadBalancingAlgorithm选 Dynamic 对大多数场景够用,选 HyperVPort 是为了让流量按虚拟口分布。SET 这边-AllowManagementOS $true决定宿主机自己还能不能上网,做管理口的时候必须加。
判断顺序很简单:这台机器要跑 Hyper-V 虚拟机吗?跑就只用 SET,别碰 LBFO;不跑就只做 LBFO,别提前建虚拟交换机。两套混着配,重启后网络配置丢失是家常便饭,恢复起来比重装还费时间。
5. 四类高频翻车现场:现象、原因与处置
下面四条都是实际排过的,按“现象 → 原因 → 解决”写,照着对号入座就行。
5.1 手动指定 inf 报“找不到兼容的驱动程序”
现象:设备管理器里选中 inf 所在目录,提示“该文件夹中没有与你的设备兼容的驱动程序软件”,但 inf 明明在,硬件 ID 也对得上。
原因:inf 的[Manufacturer]段用的是带版本号的装饰器,比如%Mfg%=Mfg,NTamd64.10.0...16299。Server 2016 是 10.0.14393,只能匹配...14393及更低的装饰器,版本号高于系统的分支直接被跳过,表现出来就是“不兼容”。
解决:优先换驱动包,找厂商提供的 Server 版或面向 14393 的分支,很多完整包里会同时保留多个装饰器,换一个子目录就行。手工改 inf 的装饰器在技术上可行,但文件一改哈希就变,cat 签名立即失效,装上去要么被拒载要么只能开测试签名,生产环境不要走这条路。
5.2 网口灯亮、Status 是 Up,但 ping 不通网关
现象:Get-NetAdapter显示Status: Up、LinkSpeed: 10 Gbps,IP 配置看着也对,就是 ping 不通同网段网关。
原因:最常见的是巨型帧两端不一致。服务器侧开了 9014,交换机端口还是默认 1518,小包能过,稍大的包全被丢,ping 因为包小反而可能通,表现出来就是“能 ping 通但传不了文件”。其次是 VLAN 没打对,或者交换机端口被划到了别的 VLAN。
解决:先确认两端巨型帧设置,Get-NetAdapterAdvancedProperty里找JumboPacket,要么两边都开,要么两边都关,中间任何一跳(交换机、防火墙、虚拟交换机)不支持就统一关掉。然后查 IP 配置和 ARP,Get-NetIPConfiguration和Get-NetNeighbor两条命令能看清地址、网关、MAC 是否正常学到。
5.3 万兆口跑不满,大流量传输掉包严重
现象:单流传输只有 2~3 Gbps,多流能上去一点,抓包能看到大量重传,CPU 占用不高。
原因:通常是 VMQ(虚拟机队列)和驱动的兼容问题,这个在 Server 2016 上不是玄学,是老问题,尤其在某些芯片的早期驱动上,VMQ 开启后队列分配出错,包被扔进错误的队列直接丢弃。另一个可能是 RSS 队列数超过了物理核心数。
解决:关闭 VMQ 验证,Set-NetAdapterVmq -Name 'Ethernet' -Enabled $false,如果掉包立刻消失,就往驱动升级或换包的方向走,而不是长期关着。RSS 这边用Get-NetAdapterRss看实际队列数,控制在物理核心数以内,Set-NetAdapterRss -MaxProcessors可以调整。改完都要重启网卡或者重启系统才生效。
5.4 升级驱动之后重启失联,带外管理也进不去
现象:远程升级网卡驱动,重启后 RDP 不上、ping 不通,带外管理里能看到系统起来了但网络不通。
原因:新驱动包和旧包同时留在驱动库里,两个 oemXX.inf 抢同一个 DEV,设备初始化阶段加载了错误的那个;或者新装的套件接管了网卡的团队配置,把原来的绑定关系打散了。
解决:这类问题只能在带外或者本地救。进去之后先pnputil /enum-drivers把所有 Net 类的第三方包列出来,找同一个 Provider 的多个版本,删掉新装的那个,/uninstall /force之后重启。所以我的习惯是:升级驱动前先跑一遍第 6 章那个清单脚本存个档,出问题按存档回滚,比现场猜快得多。
6. 做成清单再动手:一份能回滚的网络驱动清点脚本
驱动这活儿做多了会发现,真正花时间的不是装,是出事之后搞不清“原来是什么版本”。我现在每台机器装完系统、配好网络之后,第一件事就是跑一段脚本把当前状态存成 CSV 归档,文件名带机器名和日期,扔到共享盘的固定目录里。两年下来救过好几次场,尤其是那种升级完驱动、过了一周才出问题的场景。
# 保存路径按机器名分目录,避免互相覆盖 $out = "C:\drv-audit\$env:COMPUTERNAME" New-Item -ItemType Directory -Path $out -Force | Out-Null # 1. 网络设备清单:名称、状态、驱动版本、硬件 ID Get-PnpDevice -Class Net | ForEach-Object { $hw = (Get-PnpDeviceProperty -InstanceId $_.InstanceId ` -KeyName 'DEVPKEY_Device_HardwareIds').Data $ver = (Get-PnpDeviceProperty -InstanceId $_.InstanceId ` -KeyName 'DEVPKEY_Device_DriverVersion').Data [pscustomobject]@{ Name = $_.FriendlyName Status = $_.Status DriverVer = $ver HardwareIds = ($hw -join ';') } } | Export-Csv "$out\nic-$((Get-Date).ToString('yyyyMMdd')).csv" -NoTypeInformation -Encoding UTF8 # 2. 驱动库快照,回滚时按 Published Name 找包 pnputil /enum-drivers > "$out\oemdrivers-$((Get-Date).ToString('yyyyMMdd')).txt" # 3. 当前生效的网络配置,包括团队和虚拟交换机 Get-NetAdapter | Select-Object Name, InterfaceDescription, Status, LinkSpeed, MacAddress | Export-Csv "$out\adapter.csv" -NoTypeInformation -Encoding UTF8 Get-VMSwitch -ErrorAction SilentlyContinue | Export-Csv "$out\vswitch.csv" -NoTypeInformation -Encoding UTF8DEVPKEY_Device_DriverVersion拿的是驱动版本字符串,比在设备管理器里点属性看快得多。pnputil /enum-drivers的输出重定向成文本,好处是保留了原始格式,回滚的时候能直接照着Published Name敲命令,不用再解析。Get-VMSwitch加了-ErrorAction SilentlyContinue,没装 Hyper-V 角色的机器上这条不会报错中断。
回滚按三步走:先用 CSV 里记录的 DriverVer 对比当前值,确认是不是驱动变了;再到 oemdrivers 文本里找同 Provider 的旧包编号;最后pnputil /delete-driver oemXX.inf /uninstall /force加重启。三步都不需要联网,也不需要重新下载任何东西,这是提前存档最大的价值。
还有一个容易被忽略的点:这份 CSV 不要只留在本机,本机网络不通的时候它就在不通的那台机器上。归档到共享盘或者带外管理能访问的存储里,才算真的留了退路。
从那以后我每次碰网卡驱动,不管是新装、升级还是换模块,都强制先跑一遍这段脚本再动手,宁可多花两分钟,也不要在机房站着猜上一个版本是什么。希望帮到你。
本文还有配套的精品资源,点击获取