Windows 2015 LTSB普通用户无法通过脚本下载更新求助
问题背景
我在Windows 2015 LTSB系统上使用一段VBS脚本按需下载安装Windows补丁。之前普通用户运行这个脚本完全正常,但最近出现异常:脚本仅输出“下载完成成功,请按任意键继续”的提示,却没有实际下载更新文件,也不会进入安装环节;而管理员权限用户执行同一脚本则能正常下载并安装更新包。我怀疑是downloader.Download()方法在不同权限下的行为差异导致的,希望能排查普通用户无法下载的原因。
脚本代码
Option Explicit Dim updateSession, updateSearcher, update, searchResult, downloader, updatesToDownload, updatesToInstall, installer, installationResult, InputKey, i, endKey If Right((LCase(WScript.FullName)),11) <> "cscript.exe" Then WScript.Echo "Please carry out this script using CSCRIPT.EXE." & _ vbCrLf & "Example: cscript WindowsUpdate.vbs" WScript.StdOut.Write vbCrLf & "Please press any key to continue." endKey = WScript.StdIn.ReadLine WScript.Quit(0) End If Dim strInp On Error Resume Next WScript.Echo "Press Enter key to begin Windows Update." strInp = WScript.StdIn.ReadLine WScript.Echo "------------------------------" WScript.Echo "Windows Update" WScript.Echo "------------------------------" WScript.Echo "Verifying latest update..." Set updateSession = CreateObject("Microsoft.Update.Session") Set updateSearcher = updateSession.CreateupdateSearcher() Set searchResult = _ updateSearcher.Search("IsInstalled=0 and Type='Software' and AutoSelectOnWebSites=1") 'If Err.Number <> 0 Then If IsNull(searchResult.Updates.Count) Or IsEmpty(searchResult.Updates.Count) Then WScript.Echo "An error occurred. Please check your network connection and try again." WScript.StdOut.Write vbCrLf & "Please press any key to continue." endKey = WScript.StdIn.ReadLine 'Err.Clear WScript.Quit(0) End If For i = 0 To searchResult.Updates.Count-1 Set update = searchResult.Updates.Item(i) WScript.Echo i + 1 & vbTab & update.Title & " Size: " & update.MaxDownloadSize Next If searchResult.Updates.Count = 0 Then WScript.Echo "Windows is up to date." WScript.StdOut.Write vbCrLf & "Please press any key to continue." endKey = WScript.StdIn.ReadLine WScript.Quit(0) Else WScript.Echo "A newer version of " & searchResult.Updates.Count & _ " is found. Downloading starts." End If WScript.StdOut.Write "Preparing download..." Set updatesToDownload = CreateObject("Microsoft.Update.UpdateColl") For i = 0 to searchResult.Updates.Count-1 Set update = searchResult.Updates.Item(i) WScript.StdOut.Write "." updatesToDownload.Add(update) Next WScript.Echo vbCrLf & "Newer version of programs is downloading..." Set downloader = updateSession.CreateUpdateDownloader() downloader.Updates = updatesToDownload downloader.Download() 'WScript.Echo "DEBUG [downloader.Download().ResultCode]:" & downloader.Download().ResultCode If downloader.Download().ResultCode = 2 Then WScript.Echo "Download completed successfully." Else WScript.Echo "Download failed." End If If downloader.Download().ResultCode = 4 Then WScript.StdOut.Write vbCrLf & "Please press any key to continue." endKey = WScript.StdIn.ReadLine WScript.Quit(0) End If WScript.Echo "Download the following programs is successfully completed." For i = 0 To searchResult.Updates.Count-1 Set update = searchResult.Updates.Item(i) If update.IsDownloaded Then WScript.Echo i + 1 & vbTab & update.Title End If Next Set updatesToInstall = CreateObject("Microsoft.Update.UpdateColl") WScript.StdOut.Write "Preparing installation..." For i = 0 To searchResult.Updates.Count-1 Set update = searchResult.Updates.Item(i) If update.IsDownloaded = True Then WScript.StdOut.Write "." updatesToInstall.Add(update) End If Next 'WScript.StdOut.Write vbCrLf & "DEBUG [updatesToInstall.Count]:" & updatesToInstall.Count If updatesToInstall.Count = 0 Then WScript.Echo vbCrLf & "Installation failed." WScript.StdOut.Write vbCrLf & "Please press any key to continue." endKey = WScript.StdIn.ReadLine WScript.Quit(0) End If WScript.Echo vbCrLf & "Installing..." Set installer = updateSession.CreateUpdateInstaller() installer.Updates = updatesToInstall Set installationResult = installer.Install() If installationResult.ResultCode = 2 Then WScript.Echo "Installation completed successfully." Else WScript.Echo "Installation failed." End If WScript.Echo "Detail information." For i = 0 to updatesToInstall.Count - 1 WScript.StdOut.Write i + 1 & vbTab & _ updatesToInstall.Item(i).Title If installationResult.GetUpdateResult(i).ResultCode = 2 then WScript.Echo "Succeed." Else WScript.Echo "Failure." End If Next 'WScript.StdOut.Write "Restart is required." If installationResult.RebootRequired Then 'WScri
可能的原因分析
核心权限限制
Windows Update的COM组件和下载缓存目录(C:\Windows\SoftwareDistribution)对普通用户的权限有限制:管理员拥有系统级权限,可读写该目录并调用更新组件的所有方法;但普通用户可能仅拥有读取权限,无法写入下载的补丁文件,导致下载失败,而脚本的错误处理机制掩盖了真实问题,误报下载成功。脚本逻辑缺陷:重复调用
Download()
脚本中downloader.Download()被重复调用了三次:
downloader.Download() If downloader.Download().ResultCode = 2 Then
第一次调用若因权限问题失败,On Error Resume Next会忽略错误;后续再次调用可能返回错误的缓存结果,让脚本误以为下载成功。且多次调用完全没必要,还会干扰结果判断。
- 组策略限制
系统可能通过组策略禁用了普通用户访问Windows更新的功能,例如“删除使用所有Windows更新功能的访问权限”策略被启用,直接阻止普通用户执行更新操作。
排查&修复步骤
第一步:暴露真实错误
注释掉脚本中的On Error Resume Next,用普通用户重新运行脚本。此时脚本会弹出具体错误信息(如权限不足、无法写入目录等),直接定位问题根源。
第二步:修复脚本的重复调用问题
将多次调用downloader.Download()改为仅调用一次,将结果存入变量,避免重复触发和错误判断:
' 替换原有的三次Download调用 Dim downloadResult downloadResult = downloader.Download() ' 开启调试输出查看真实结果 WScript.Echo "DEBUG: Download Result Code = " & downloadResult.ResultCode If downloadResult.ResultCode = 2 Then WScript.Echo "Download completed successfully." Else WScript.Echo "Download failed. Result Code: " & downloadResult.ResultCode End If If downloadResult.ResultCode = 4 Then WScript.StdOut.Write vbCrLf & "Please press any key to continue." endKey = WScript.StdIn.ReadLine WScript.Quit(0) End If
常见ResultCode含义:
- 2 = 下载成功
- 4 = 下载被取消
- 5 = 下载失败(如权限不足、网络问题)
第三步:检查并修复目录权限
- 打开资源管理器,找到
C:\Windows\SoftwareDistribution目录; - 右键→属性→安全选项卡;
- 找到
Users组,检查是否拥有读取、写入、修改权限; - 若无对应权限,点击「编辑」→添加Users组,勾选所需权限,保存后重新测试脚本。
第四步:检查组策略设置
- 按下Win+R,输入
gpedit.msc打开组策略编辑器; - 导航至:计算机配置→管理模板→Windows组件→Windows更新;
- 查看是否有设置为「已启用」的限制策略(如“删除使用所有Windows更新功能的访问权限”),若有则改为「未配置」或「禁用」;
- 运行
gpupdate /force刷新组策略,再测试脚本。
总结
大概率是普通用户没有足够权限写入更新缓存目录,加上脚本的错误处理掩盖了真实问题。通过禁用错误忽略、修复脚本重复调用逻辑、调整目录权限这几步,基本能解决问题;若为组策略限制,调整对应策略即可。
内容的提问来源于stack exchange,提问作者bharat vivek

