Search code examples
powershell

type-safe powershell: Unable to find type `[Application]`


I am trying to slowly move towards more type-safe powershell scripts and therefore experimenting with explicitly setting types for all my variables. In the following, I attempt to instantiate a Word.Application object and then quit out of it:

using namespace Microsoft.Office.Interop.Word
using namespace System.Management.Automation

$ErrorActionPreference = [ActionPreference]::"Stop"
[Application]$wordApp = new-object -comobject Word.Application
$wordApp.Quit()

Could anyone explain to me why, upon running this script I get the following error:

InvalidOperation: test.ps1:5 Line | 5 | [Application]$wordApp = new-object -comobject Word.Application | ~~~~~~~~~~~~~ | Unable to find type [Application].

What is the correct way to remediate this?


Solution

  • Could anyone explain to me why, upon running this script I get the following error: [Unable to find type]?

    • A using namespace statement merely provides syntactic convenience: it allows you to reference already loaded types by their simple name, without having to use the namespace part (in the case at hand, [Application] instead of [Microsoft.Office.Interop.Word.Application])

    • Thus, you must ensure separately that the assemblies containing the types of interest are loaded, either via using assembly statements or Add-Type calls.

    Therefore:

    # NOTE:
    #  Windows PowerShell only - doesn't work in PowerShell (Core) 7, as of v7.4.x
    using assembly Microsoft.Office.Interop.Word
    using namespace Microsoft.Office.Interop.Word
    using namespace System.Management.Automation
    
    $ErrorActionPreference = [ActionPreference]::Stop
    [Application]$wordApp = New-Object -ComObject Word.Application
    $wordApp.Name # Get and output the .Name property value, for demonstration purposes.
    $wordApp.Quit()
    

    Note:

    • This does not work in PowerShell (Core) 7, as of v7.4.x:

      • Generally, there seems to be a problem with loading well-known assemblies with using assembly - see GitHub issue #11856.

      • However, even using Add-Type -AssemblyName doesn't help in this case, because the PIAs (Primary Interop Assemblies) (such as Microsoft.Office.Interop.Word.dll) are in an older part of the GAC (Global Assembly Cache) that PowerShell 7 does not consult by default. Trying to load such an assembly with an explicit path, i.e. via Add-Type -LiteralPath, fails quietly; e.g.:

        # !! Fails quietly in PowerShell (Core) 7
        Add-Type -LiteralPath C:\WINDOWS\assembly\GAC_MSIL\Microsoft.Office.Interop.Word\15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Word.dll`
        
        • That said, there is an obscure workaround that involves explicitly loading the office.dll assembly by full path too, as detailed in GitHub issue #24627 (the latter's primary purpose is to report the unexpected quiet failure).
          The root cause seems to be that when loading assemblies from the legacy part of the GAC (for .NET Framework version 1 through 3.5), their dependencies aren't automatically loaded.