Public/Get-DLLsInModulePath.ps1

function Get-DLLsInModulePath {
    <#
    .SYNOPSIS
        Show a list of all DLLs in PowerShell module paths that contain the specified product name in their FileInfo property.
 
    .DESCRIPTION
        Check all installed PowerShell module locations for DLL files that have the specified product name (e.g., 'Microsoft Identity') in their file's Productname attribute.
        By default, searches all paths in the PSModulePath environment variable. Can optionally check custom locations using the -Path parameter.
 
    .EXAMPLE
        Get-DLLsInModulePath -ProductName "Microsoft Identity"
 
        Find all Microsoft Identity-related DLLs within installed PowerShell module locations.
 
    .EXAMPLE
        Get-DLLsInModulePath -ProductName "Microsoft Identity" | Sort-Object -Property InternalName | Format-Table InternalName, @{Label = 'ProductVersion'; Expression = { $_.ProductVersionRaw } }, @{Label = 'Module'; Expression = { $($_.FileName -replace '^.*Modules[\\/]([^\\/]+)([\\/].*)?', '$1') }}
 
        Find all Microsoft Identity-related DLLs within installed PowerShell module locations. Shows the name of the module that the DLL is included in.
 
    .NOTES
        To Do:
 
        - Further reduce the number of paths inspected by (optionally) only scanning the newest version of each module in each scope's paths.
        - Fix PassThru logic.
        - Apply custom formatting type for output.
 
        Example Output:
 
        InternalName ProductVersion Module
        ------------ -------------- ------
        Microsoft.Identity.Abstractions.dll 9.5.0.0 DLLPickle
        Microsoft.IdentityModel.Abstractions.dll 0.0.0.0 Az.Accounts
        Microsoft.IdentityModel.JsonWebTokens.dll 8.6.0.0 ExchangeOnlineManagement
        Microsoft.IdentityModel.Logging.dll 8.6.0.0 ExchangeOnlineManagement
        Microsoft.IdentityModel.Protocols.dll 8.6.1.0 WinTuner
        Microsoft.IdentityModel.Protocols.OpenIdConnect.dll 8.6.1.0 WinTuner
        Microsoft.IdentityModel.Tokens.dll 8.6.0.0 ExchangeOnlineManagement
        Microsoft.IdentityModel.Validators.dll 8.6.1.0 WinTuner
        System.IdentityModel.Tokens.Jwt.dll 8.6.0.0 ExchangeOnlineManagement
    #>


    [CmdletBinding()]
    [OutputType([System.Diagnostics.FileVersionInfo])]
    param (
        # The product name to search for in DLL file info properties.
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$ProductName = 'Microsoft Identity',

        # Locations to search for Microsoft Identity-related DLLs.
        [Parameter()]
        [ValidateScript({ Test-Path -Path $_ -PathType Container })]
        [string[]]$Path = @( $env:PSModulePath -split [System.IO.Path]::PathSeparator | Where-Object { Test-Path $_ -PathType Container } ),

        # Directories to exclude from inspection so the process goes faster.
        [Parameter()]
        [string[]]$ExcludeDirectories = @('en-US', 'help', 'Tests', '.git'),

        # The module installation scope to search. Valid options are AllUsers, CurrentUser, or Both (default).
        [Parameter()]
        [ValidateSet('CurrentUser', 'AllUsers', 'Both')]
        [string]$Scope = 'Both',

        # Display formatted output to host in addition to returning objects to the pipeline.
        [switch] $PassThru
    )

    # Determine the scoped paths to inspect. Defaults to all scopes.
    if ($Scope -eq 'CurrentUser') {
        $ScopedPath = @( $Path | Where-Object { $_ -match 'User' } )
    } elseif ($Scope -eq 'AllUsers') {
        $ScopedPath = @( $Path | Where-Object { $_ -notmatch 'User' } )
    } else {
        $ScopedPath = $Path
    }

    # Write an error and exit if none of the specified paths are found in the specified scope.
    if (-not $ScopedPath -or $ScopedPath.Count -eq 0) {
        $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
            [System.Exception]::new("Scope '$Scope' produced no valid paths."), 'ScopePathsNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $Scope
        )
        $PSCmdlet.WriteError($ErrorRecord)
        return
    }

    Write-Verbose "Enumerating DLLs with the product name '$ProductName' under:`n - $($ScopedPath -join "`n - ")"

    # Get the newest version of any DLLs that have "Microsoft Identity" in their ProductName property.
    <#
    $DLLs = @(
        Get-ChildItem -Path $ScopedPath -Filter '*.dll' -File -Recurse |
            Select-Object -ExpandProperty VersionInfo -ErrorAction SilentlyContinue | Where-Object { $_.ProductName -like "*$ProductName*" } | Group-Object -Property OriginalFilename | ForEach-Object {
                $_.Group | Sort-Object -Property Version -Descending | Select-Object -First 1
            }
    )
    # Potentially optimized below.
    #>

    $DLLs = @(
        Get-ChildItem -Path $ScopedPath -Filter '*.dll' -File -Recurse | Where-Object { $ExcludeDirectories -notcontains $_.Directory.Name } | ForEach-Object {
            $VersionInfo = $_.VersionInfo
            if ($VersionInfo.ProductName -like "*$ProductName*") {
                # Pass the VersionInfo object on through the pipline if it matches the desired product name.
                $VersionInfo
            }
        } | Group-Object -Property OriginalFilename | ForEach-Object {
            # Get the newest version of each DLL.
            $_.Group | Sort-Object -Property Version -Descending | Select-Object -First 1
        }
    )

    if ($DLLs.Count -eq 0) {
        Write-Warning "No DLLs found matching the product name pattern '*ProductName*'."
    }

    if ($PSBoundParameters.ContainsKey('PassThru')) {
        # Show the results as a table to the host in addition to returning to the pipeline.
        $DLLs | Sort-Object -Property InternalName | Format-Table InternalName, @{Label = 'ProductVersion'; Expression = { $_.ProductVersionRaw } }, @{Label = 'Module'; Expression = { $($_.FileName -replace '^.*Modules[\\/]([^\\/]+)([\\/].*)?', '$1') } }, FileDescription | Out-Host
    }

    $DLLs
}