function Get-GACAssemblyPath {
PARAM ([Parameter(Mandatory=$true)][string] $AssemblyName)
$GAC = Join-Path -Path (Join-Path -Path $env:WINDIR -ChildPath '\assembly\GAC_MSIL') -ChildPath $AssemblyName
try {
(Get-ChildItem -Path (Get-ChildItem -Path $GAC -EA STOP).FullName -EA STOP).FullName
}
catch { }
}
Add-Type -Path (Get-GACAssemblyPath -AssemblyName 'Microsoft.Office.Interop.Outlook') #PS5/PS7 compatible
$Outlook = New-Object -ComObject 'Outlook.Application'
$MAPI = $Outlook.GetNamespace('MAPI')
Register-ObjectEvent -InputObject $Outlook -EventName 'AdvancedSearchComplete' -ErrorAction STOP # FAILS on PS7
PS C:> Cannot register for the specified event. An event with the name 'AdvancedSearchComplete' does not exist. (Parameter 'eventName')
At C:\test-registerEvent.ps1:15 char:1
PS C:> $PSversiontable
Name Value
---- -----
PSVersion 7.0.0-rc.1
PSEdition Core
GitCommitId 7.0.0-rc.1
OS Microsoft Windows 10.0.19041
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
PS C:>
@daxian-dbw If you have time could you please point where is root of the issue?
Seems like the main difference is that Marshal.GetTypeFromCLSID doesn't check primary interop assemblies in core. So in Windows PowerShell it returns ApplicationClass from the PIA and in Core it returns __ComObject.
As a workaround you can call the constructor for ApplicationClass directly instead of going through New-Object:
# You also need to import the "office.dll" assembly. If you're loading an assembly
# from the GAC in core then you need to manually import all dependencies. A easier
# route would be using something like nuget to manage and distribute the assemblies
# with the script.
Add-Type -Path (Get-GACAssemblyPath -AssemblyName office)
Add-Type -Path (Get-GACAssemblyPath -AssemblyName Microsoft.Office.Interop.Outlook)
# This will be properly typed and still functional
$outlook = [Microsoft.Office.Interop.Outlook.ApplicationClass]::new()
$mapi = $outlook.GetNamespace('MAPI')
Register-ObjectEvent -InputObject $outlook -EventName AdvancedSearchComplete -ErrorAction Stop
Is this a regression from 5.1, 6.0?
I would guess anything after 5.1, but I can confirm it reproduces on 6.2.3 as well as 7 rc1
I did not found that we would change in the code but I feel we could/should fix this because New-Object is native for PowerShell.
I did not found that we would change in the code but I feel we could/should fix this because New-Object is native for PowerShell.
I think in order to fix this on the PowerShell end, New-Object would have to implement the logic of looking up registered primary interop assemblies in the registry. Then fall back to Marshal.GetTypeFromCLSID if one is not found.
just FYI, using the suggestion from SeeminglyScience the full script runs fine. It is doing a search for an Outlook folder then an AdvancedSearch for messages with a subject starting with X or Y.
PS5 it take 8-10 seconds to find the 5 messages.
PS7 is consistently around 35-38 seconds.
@SteveL-MSFT Could you please triage the regression issue?
@iSazonov This looks like a regression in .NET Core. Do you mind opening an issue in https://github.com/dotnet/runtime repo?
@daxian-dbw Thanks! They would want to see C# repo. I am not sure that I can do.
I will be on last resort :-) if @lukeb1961 or @SeeminglyScience open the issue.
Most helpful comment
Seems like the main difference is that
Marshal.GetTypeFromCLSIDdoesn't check primary interop assemblies in core. So in Windows PowerShell it returnsApplicationClassfrom the PIA and in Core it returns__ComObject.As a workaround you can call the constructor for
ApplicationClassdirectly instead of going throughNew-Object: