How to Modify Existing MIME Types in IIS 7.5 Using PowerShell Without Duplicate Errors


4 views

When working with IIS 7.5 configuration through PowerShell, many administrators hit a wall when trying to modify existing MIME types. The standard approaches either fail with duplicate entry errors or dangerously wipe out all existing configurations. Here's the technical breakdown of why this happens and how to solve it properly.

IIS stores MIME types in the system.webServer/staticContent configuration section. The key issue stems from how PowerShell's WebAdministration module handles collection modifications. When you use Add-WebConfigurationProperty on an existing file extension, IIS correctly prevents duplication. However, Set-WebConfigurationProperty treats the entire collection as a single unit, explaining why it overwrites everything.

Here's the PowerShell solution that preserves existing entries while modifying specific MIME types:

# First get the existing MIME type configuration
$mimeMap = Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' 
    -Filter "system.webServer/staticContent" 
    -Name "."

# Modify specific entry (example: changing .json mapping)
$newType = "application/json"
$fileExt = ".json"

# Create new collection with modified entry
$newCollection = @()
foreach ($mime in $mimeMap.Collection) {
    if ($mime.fileExtension -eq $fileExt) {
        $newCollection += @{fileExtension=$fileExt; mimeType=$newType}
    } else {
        $newCollection += @{fileExtension=$mime.fileExtension; mimeType=$mime.mimeType}
    }
}

# Apply the modified collection
Clear-WebConfiguration -PSPath 'MACHINE/WEBROOT/APPHOST' 
    -Filter "system.webServer/staticContent"
    
$newCollection | ForEach-Object {
    Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' 
        -Filter "system.webServer/staticContent" 
        -Name "." 
        -Value @{fileExtension=$_.fileExtension; mimeType=$_.mimeType}
}

For more surgical precision, you can target specific entries with XPath:

$filter = "system.webServer/staticContent/mimeMap[@fileExtension='.json']"
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' 
    -Filter $filter 
    -Name "mimeType" 
    -Value "application/json"

When dealing with multiple sites or application pools:

  1. Replace 'MACHINE/WEBROOT/APPHOST' with your specific site path
  2. Consider adding error handling for missing extensions
  3. For bulk operations, pipeline the file extensions

While this approach requires more code than appcmd.exe, it:

  • Maintains configuration integrity
  • Works in constrained environments
  • Provides better audit trails
  • Can be incorporated into DSC configurations

When working with IIS 7.5 configuration through PowerShell, many administrators hit the same wall: the apparent lack of a straightforward way to modify existing MIME types without either creating duplicates or wiping out the entire collection. The standard cmdlets like Add-WebConfigurationProperty and Set-WebConfigurationProperty don't behave as expected for this specific operation.

# Typical failed attempt with Add-WebConfigurationProperty
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent" -name "." -value @{fileExtension='.foo'; mimeType='text/foo'}

# This throws: "The collection already contains an element with key '.foo'"
# Dangerous attempt with Set-WebConfigurationProperty
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent" -name "mimeMap" -value @{fileExtension='.foo'; mimeType='text/foo'}

# This nukes all existing MIME types - definitely not what we want!

After extensive testing, I've found the most reliable method is to use Get-WebConfiguration to locate the specific node and modify it directly:

# First get the configuration section
$staticContent = Get-WebConfiguration -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent"

# Find and modify the specific MIME type
$mimeMap = $staticContent.GetCollection()
foreach($mime in $mimeMap) {
    if($mime.fileExtension -eq '.foo') {
        $mime.mimeType = 'text/newfoo'
        break
    }
}

# Commit the changes
$staticContent.CommitChanges()

For those who prefer a more cmdlet-oriented approach:

# 1. Get current settings
$currentMime = Get-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent/mimeMap[@fileExtension='.foo']" -name "mimeType"

# 2. Remove existing entry
Clear-WebConfiguration -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent/mimeMap[@fileExtension='.foo']"

# 3. Add modified version
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent" -name "." -value @{fileExtension='.foo'; mimeType='text/updated'}

When working with specific sites or virtual directories, modify the -pspath parameter accordingly:

# For Default Web Site
$sitePath = 'IIS:\Sites\Default Web Site'

# For an application
$appPath = 'IIS:\Sites\Default Web Site\MyApp'

Get-WebConfiguration -pspath $sitePath -filter "system.webServer/staticContent"

Always include proper error handling, especially in production scripts:

try {
    $mime = Get-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' 
        -filter "system.webServer/staticContent/mimeMap[@fileExtension='.foo']" 
        -name "mimeType" -ErrorAction Stop
    
    if($mime) {
        Clear-WebConfiguration -pspath 'MACHINE/WEBROOT/APPHOST' 
            -filter "system.webServer/staticContent/mimeMap[@fileExtension='.foo']"
        
        Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' 
            -filter "system.webServer/staticContent" -name "." 
            -value @{fileExtension='.foo'; mimeType='text/updated'}
    }
}
catch {
    Write-Warning "MIME type modification failed: $_"
}

For scripts that need to modify multiple MIME types, consider this bulk approach:

$updates = @{
    '.foo' = 'text/newfoo'
    '.bar' = 'application/newbar'
}

$staticContent = Get-WebConfiguration -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/staticContent"
$mimeMap = $staticContent.GetCollection()

foreach($key in $updates.Keys) {
    $existing = $mimeMap | Where-Object { $_.fileExtension -eq $key }
    if($existing) {
        $existing.mimeType = $updates[$key]
    }
}

$staticContent.CommitChanges()