You run a script that worked yesterday, and today you get 0x80020007 with the cheerful message "No named arguments." Nothing changed in Windows. What's actually happening here is that your script is calling a COM object using a name like Range:= or Filename:=, and the object's type library either doesn't declare that name or doesn't support named arguments at all. The caller and the callee disagree about the contract. Almost always, the bug is on the caller side.
Cause 1: You passed a named argument a COM object doesn't declare
This is the one I see nine times out of ten. Someone writes VBScript or PowerShell against Excel, Word, or a third-party automation server, and they use a named parameter that sounds right but isn't the real name. The classic example is Excel's Workbooks.Open. People write Filename:= because the docs sort of imply it, but the actual IDispatch name in Excel's type library is Filename as a positional parameter — Excel's late-bound Invoke doesn't accept it as a named argument from VBScript the way you'd hope.
Here's the failing pattern in VBScript:
Set xl = CreateObject("Excel.Application")
Set wb = xl.Workbooks.Open(Filename:="C:\data\book.xlsx") ' raises 0x80020007
The reason step 3 works in the fixed version is that positional arguments go through Invoke with DISPID_VALUE, which every IDispatch implementation has to handle. Named arguments require the object to expose GetIDsOfNames for that parameter name, and plenty of COM servers — including some Microsoft ones in late-binding mode — simply don't.
The fix: drop the names and use positions.
Set xl = CreateObject("Excel.Application")
Set wb = xl.Workbooks.Open("C:\data\book.xlsx")
If you need to skip a middle parameter, pass an empty value in its place. For Workbooks.Open the signature has UpdateLinks as parameter 2, so to open read-only you'd write xl.Workbooks.Open("C:\data\book.xlsx", , True) — two commas, then the ReadOnly flag. Ugly, but it works because COM's positional binding doesn't care about the gaps.
Rule of thumb: if you're calling COM from a scripting host, use positional arguments unless you've confirmed the server exposes named ones. "It reads better" isn't worth a runtime failure at 2am on a scheduled task.
Cause 2: PowerShell splatting sends a name the COM object rejects
PowerShell makes this worse because it looks like named-parameter syntax is the correct approach. It is — for cmdlets. For raw COM (via New-Object -ComObject or [Activator]::CreateInstance), PowerShell translates your named arguments into IDispatch::Invoke calls with DISPIDs resolved from those names. If the COM server doesn't publish the name, you get 0x80020007 with no hint about which parameter offended it.
Concrete trigger: this shows up constantly in scripts that automate Outlook from a scheduled task on Server 2019, where MailItem.Send and MailItem.Save are fine but someone tries $mail.Send($mailbox:=...) or passes a hash to .InvokeMember() with a name Outlook doesn't have.
Diagnose it by isolating the call. Comment out everything and try one parameter at a time:
$excel = New-Object -ComObject Excel.Application
$wb = $excel.Workbooks.Open('C:\data\book.xlsx') # works, positional
# $wb = $excel.Workbooks.Open(Filename='C:\data\book.xlsx') # may 0x80020007
The real fix is to use positional calls in PowerShell too, or switch to the -ArgumentList form when constructing:
$excel.Workbooks.Open('C:\data\book.xlsx', 0, $true)
And if you genuinely need named binding, use a strongly-typed .NET interop assembly (load Microsoft.Office.Interop.Excel via Add-Type) instead of late-bound COM. The interop types carry the real parameter metadata, so named arguments resolve at compile time and never reach DISP_E_NONAMEDARGS.
Cause 3: The COM server's registration or type library is broken
Less common, but nastier. If the object used to accept a named argument and now doesn't, the registration may have been rewritten — by an Office Click-to-Run update, by a broken installer that re-registered with the wrong TypeLib GUID, or by a 32/64-bit mismatch. A 32-bit script calling into a 64-bit-only automation server often finds a proxy that drops named-argument support.
This is the failure mode behind a lot of "it worked on the old machine" reports. A user migrates from Office 2016 MSI installs to Microsoft 365 Click-to-Run, their old script referenced Word.Application.16 with a named argument the C2R type library doesn't publish, and now every run throws 0x80020007. The script didn't change. The registration did.
Check registration with:
reg query HKCR\CLSID\{00020906-0000-0000-C000-000000000046}\TypeLib
reg query HKCR\TypeLib\{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}\Version
If the TypeLib version looks wrong for the Office build you actually have, re-register the server. For Office, run Repair from Apps & features (Windows 10/11) or OfficeClickToRun.exe scenario=Repair platform=x64 culture=en-us. If it's a custom in-house COM server, re-run regsvr32 /i yourserver.dll from an elevated prompt matching the bitness of the client that's failing.
One more diagnostic: oleview.exe (from the Windows SDK) will show you the object's IDispatch interface and the exact named parameters it publishes. If your script's names aren't in that list, you've found your answer.
Quick reference
| Cause | How to confirm | Fix |
|---|---|---|
| Named arg not declared by COM object | Replace name with positional and error disappears | Use positional args; fill skipped params with empty values |
| PowerShell sending named args to late-bound COM | Hash splat or Name=Value in the call | Use -ArgumentList or switch to interop assembly |
| Broken/mismatched TypeLib registration | reg query shows wrong version; recent Office change | Repair Office or regsvr32 the server |
Don't waste time on DISM, SFC, or reinstalling .NET. This error is contract mismatch, not corruption. Look at the call site first. The object's type library is the thing to trust, and if you can't see it, oleview.exe will show you exactly which names it will accept.