Dim*_*dis 5 c# com powershell wuapi
这个问题本质上是一个 6 年多前的问题的后续问题:\n IUpdateInstaller4::Commit not found
\n正如 Hans Passant 在该答案中所述,当时,不仅类型库完全缺少此接口,而且其他接口(如 IUpdateInstaller3)也完全缺少。
\n快进到现在,Windows 10 20H2 及更高版本实际上有一个 wuapi.dll,其中包含 wuapi.dll 内的完整类型库,并且 MSDN 文档已更新。
\n以下是 IUpdateInstaller4 接口(以及之前缺失的其余接口)的链接:\n https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdateinstaller4
\n也就是说,在旧版本的 Windows 10 上,如果要安装功能更新,则必须调用 IUpdateInstaller4.Commit 才能正确安装功能更新。我的观察是,如果您不这样做,您的 Windows 安装可能会回滚或使您的系统处于几乎无法使用的状态(问我是怎么知道的)。
\n我正在寻找一种使用本机 powershell 的方法,以便能够在旧版本的 Windows 10(例如 Windows 10 1909)上调用 Commit 方法。到目前为止,我唯一成功的是在较新版本的 Windows 10 上创建 COM 互操作 DLL Windows 10(例如 21H2)并将 COM 互操作 DLL 带回 1909 计算机并利用它 -但我正在寻找一种方法来执行此操作,而无需将整个 DLL 发送到计算机。我怀疑有一种方法可以使用 Add-Type 和一些 C# 代码来完成此操作,这是我理想的解决方案,以便整个 Windows 更新过程可以由我编写的 Powershell 脚本来处理。
\n我尝试过很多很多东西可以在 Win 10 20H2+ 上运行,但不行Windows 10 1909 上运行。一个可以接受的答案是,它可以在 Windows 10 的所有版本上运行。
\n我尝试了各种声明 IUpdateInstaller4 的方法(使用我生成的 COM 互操作 DLL 中的反编译定义,并使用 Add-Type 引入类型),但没有成功。每次我都会尝试一些类似的事情,比如:
\n[wuapi.IUpdateInstaller4].GetType().InvokeMember(\'Commit\',[Reflection.BindingFlags]::InvokeMethod, $null, $UpdateInstaller, @(0))\nRun Code Online (Sandbox Code Playgroud)\n...我遇到一个异常,例如:
\nException calling "InvokeMember" with "5" argument(s): "Object does not match target type."\nAt line:85 char:2\n + [wuapi.IUpdateInstaller4].GetType().InvokeMember(\'Commit\',[Reflec \xe2\x80\xa6\n + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n + CategoryInfo : NotSpecified: (:) [], MethodInvocationException\n + FullyQualifiedErrorId : TargetException\nRun Code Online (Sandbox Code Playgroud)\n我相当确定熟悉 COM 内部工作原理的人(例如 Hans Passant)可能会有一个快速的解决方案。
\n基于评论中的问题的附加信息/代码。以下是安装更新的脚本片段(基于创建基于多个脚本参数构造的 $UpdateSearchString)
\n$Searcher = New-Object -ComObject Microsoft.Update.Searcher\n$Searcher.ServiceID = $UpdateServiceID\n$Results = $Searcher.Search($UpdatesSearchString)\n$Results.Updates | % {if($_.EulaAccepted -eq $false){$_.AcceptEula()}}\n$UpdateList = $Results.Updates\n$Updates = New-Object -ComObject Microsoft.Update.UpdateColl\n$UpdateList | % {$null = $Updates.Add($_)}\n$UpdateSession = New-Object -ComObject Microsoft.Update.Session\n$UpdateInstaller = $UpdateSession.CreateUpdateInstaller()\nwhile($UpdateInstaller.IsBusy) {Start-Sleep 5}\n$UpdateInstaller.Updates = $Updates\n$InstallResult = $UpdateInstaller.Install()\nRun Code Online (Sandbox Code Playgroud)\n在 Windows 10 上,您应该能够执行以下操作:
\n$CommitResult = $UpdateInstaller.Commit(0)\nRun Code Online (Sandbox Code Playgroud)\n...但是除非您使用的 Windows 10 版本在 wuapi COM dll 中具有更新的类型库,否则这不起作用。
\n以下代码适用于具有更新的 wuapi.dll 的计算机,但不适用于旧版本(并且失败并出现上面发布的异常):
\n$Source = @"\nusing System;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nnamespace wuapi\n{\n [TypeLibType(TypeLibTypeFlags.FHidden | TypeLibTypeFlags.FDual | TypeLibTypeFlags.FNonExtensible | TypeLibTypeFlags.FDispatchable)]\n [Guid("EF8208EA-2304-492D-9109-23813B0958E1")]\n [ComImport]\n public interface IUpdateInstaller4 : IUnknown\n {\n [DispId(1610874882)]\n [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]\n int Commit([In] uint dwFlags);\n }\n [ComImport]\n [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n [Guid("00000000-0000-0000-C000-000000000046")]\n public interface IUnknown\n {\n }\n public static class UpdateCommitter\n {\n public static int Commit(IUnknown comObject, uint dwFlags)\n {\n var updateInstaller = comObject as IUpdateInstaller4;\n return updateInstaller.Commit(dwFlags);\n }\n }\n}\n"@\nAdd-Type -TypeDefinition $Source\n$CommitResult=[wuapi.IUpdateInstaller4].InvokeMember(\'Commit\',[Reflection.BindingFlags]::InvokeMethod, $null, $UpdateInstaller, @(0))\nRun Code Online (Sandbox Code Playgroud)\n
事实证明,Simon Mourier 让我走上了能够调用 IUpdateInstaller4.Commit 的正确道路。
我不知道为什么即使有了这个接口定义,你也不能调用 Commit:
$CommitResult=[wuapi.IUpdateInstaller4].InvokeMember('Commit',[Reflection.BindingFlags]::InvokeMethod, $null, $UpdateInstaller, @(0))
Run Code Online (Sandbox Code Playgroud)
..但它可以通过静态类/静态方法间接调用。
这是我过去几天在旧版本的 Windows 10 以及 Server 2016、2019、2022 和 Windows 11 上成功测试和使用的示例。
$Source = @"
using System;
using System.Runtime.InteropServices;
namespace wuapi
{
[ComImport, Guid("ef8208ea-2304-492d-9109-23813b0958e1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IUpdateInstaller4
{
void _VtblGap0_29(); // skip 4 (IDispatch) + 25 IUpdateInstaller4 methods
[PreserveSig]
int Commit(uint dwFlags);
}
public static class UpdateCommitter
{
public static int Commit(object comObject, uint dwFlags)
{
var updateInstaller = (IUpdateInstaller4)comObject;
return updateInstaller.Commit(dwFlags);
}
}
}
"@
Add-Type -TypeDefinition $Source
[int]$CommitResult = [wuapi.UpdateCommitter]::Commit($UpdateInstaller,0)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
369 次 |
| 最近记录: |