My little script works as expected in Powershell ISE:

$FilePath = "C:\users\Daniel\Desktop\test.pdf"

Add-Type -AssemblyName "System.Web"

$DocExtension = [System.IO.Path]::GetExtension($FilePath)
$DocMimeType  = [System.Web.MimeMapping]::GetMimeMapping($DocExtension)

Write-Output "Extension: $DocExtension `nMIME-type: $DocMimeType"

Running it in Powershell.exe I get the following error: Unable to find type [System.Web.MimeMapping].

I googled and ChatGPTed for an hour but still cannot find any solution that would work for me.

I want to run that code block from above in a script that gets executed with Powershell, not ISE.

Help is much appreciated, thanks

I expect the script to run in Powershell.exe too.

2

There are 2 best solutions below

0
On

The System.Web.MimeMapping type is only supported in the legacy .NET Framework that underlies the legacy Windows PowerShell edition, which is the only edition supported in the obsolescent ISE.[1]

  • Note: This type isn't worth using, as it is no longer actively maintained, whereas the list of media types (formerly known as MIME types) continues to evolve.
    For instance, it doesn't know about the fairly common application/json (.json) and text/csv (.csv) media types.

The modern .NET (Core) framework underlying the modern, cross-platform PowerShell (Core) 7+ edition doesn't have this type anymore.

The third-party MimeTypes NuGet package offers an alternative, but use from PowerShell is nontrivial, especially in Windows PowerShell; a PowerShell (Core)-only solution is feasible, however - see the bottom section. The next section shows a cross-edition solution, i.e. one that works in both Windows PowerShell and PowerShell (Core).


Cross-PowerShell-edition solution:

The MimeTypes NuGet package is built on the Node.js mime-db project, which offers its list of media-type definitions in the form of an online JSON file that is updated periodically.

That JSON file can be downloaded and parsed on demand:

# Extract the filename extension without the leading '.'
$extension = [IO.Path]::GetExtension('c:\path\to\some\file.txt').Substring(1)

# Download and parse the list of media types (MIME types) via
# https://github.com/jshttp/mime-db,
# convert from JSON, and look up the extension at hand.
(
  Invoke-RestMethod https://cdn.jsdelivr.net/gh/jshttp/mime-db@master/db.json
).psobject.Properties.Where({ $_.Value.extensions -contains $extension }, 'First').Name

The above yields 'text/plain'.

Important:

  • The JSON format may change in the future, so using a specific release of the JSON file is advisable.

  • The wrapper function below:

    • Locks in v1.52.0, the version current as of this writing.
    • Downloads the JSON file on every call, which hurts performance. Consider caching it.

Get-MediaTypeByFilename function wrapper:

Assuming the function, whose source code is below, is defined, here's a sample call:

# -> 'text/plain', 'text/html'
Get-MediaTypeByFilename foo.txt, bar.html

Cross-edition Get-MediaTypeByFilename source code:

function Get-MediaTypeByFilename {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [string[]] $Filename
  )
  begin { 
    # Download and parse the list of media types (MIME types) via
    # https://github.com/jshttp/mime-db.
    # NOTE: 
    #  * For better performance consider caching the JSON file.
    #  * A fixed release is targeted, to ensure that future changes to the JSON
    #    format do not break the command.
    $mediaTypes = (
      Invoke-RestMethod https://cdn.jsdelivr.net/gh/jshttp/[email protected]/db.json
    ).psobject.Properties
  }
  process {
    foreach ($name in $Filename) {
      # Find the matching media type by filename extension.
      $matchingMediaType = 
        $mediaTypes.Where(
          { $_.Value.extensions -contains [IO.Path]::GetExtension($name).Substring(1) }, 
          'First'
        ).Name
      # Use a fallback type, if no match was found.
      if (-not $matchingMediaType) { $matchingMediaType = 'application/octet-stream' }
      $matchingMediaType # output
    }
  }
}

PowerShell (Core) 7+-only solution:

The MimeTypes NuGet package a source code-only package that requires compilation, which you can do on demand with Add-Type. However, because the source code uses newer C# features that aren't supported in Windows PowerShell's Add-Type, the following function works in PowerShell (Core) 7+ only.

Sample call:

# PowerShell (Core) 7+ only.
# -> 'text/plain', 'text/html'
Get-MediaTypeByFilename foo.txt, bar.html

Important:

PowerShell (Core)-only Get-MediaTypeByFilename source code:

# PowerShell 7+ only.
function Get-MediaTypeByFilename {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [string[]] $Filename
  )
  begin { 
    if (-not (Get-Variable -ErrorAction Ignore -ValueOnly IsCoreCLR)) {
      throw 'This command runs only in PowerShell (Core) 7+.'
    }
    # Download and compile a helper class, via
    # https://github.com/khellang/MimeTypes
    # Use a namespace of your choice for the compiled type; this is just an example.
    $rootnamespace = 'net.same2u.web'
    Add-Type (
      (
        Invoke-RestMethod https://raw.githubusercontent.com/khellang/MimeTypes/master/src/MimeTypes/MimeTypes.cs.pp
      ).Replace('$rootnamespace$', $rootnamespace)
    )      
    $method = ([type] "$rootnamespace.MimeTypes")::GetMimeType
  }
  process {
    foreach ($name in $Filename) {
      $method.Invoke($name)
    }
  }
}

[1] The PowerShell ISE is no longer actively developed and there are reasons not to use it (bottom section), notably not being able to run PowerShell (Core) 7+. The actively developed, cross-platform editor that offers the best PowerShell development experience is Visual Studio Code with its PowerShell extension.

2
On

Thanks mklement0, but I found an easier solution.

I ran the command "[System.AppDomain]::CurrentDomain.GetAssemblies()" in both, Powershell.exe and ISE.exe. In Powershell there was no assembly called System.Web, in ISE.exe I found one though.

Searching in the meantime had already helped me to figure out that "using assembly" in Powershell 7 requires a full path to the .dll.

So I replaced my original "using assembly System.Web" with the path I found using the command about to using assembly "C:\WINDOWS\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll"


The functioning code looks like this:

using assembly "C:\WINDOWS\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll"

$FilePath = "C:\users\Daniel\Desktop\test.pdf"

$DocExtension = [System.IO.Path]::GetExtension($FilePath)
$DocMimeType  = [System.Web.MimeMapping]::GetMimeMapping($DocExtension)

Write-Output "Extension: $DocExtension `nMIME-type: $DocMimeType"