About File Associations

The following article Microsoft Broke Windows 10’s File Associations With a Botched Update appeared recently and states that:

File associations no longer work properly on Windows 10 after a buggy update. Windows won’t let you select certain applications as your defaults.
[…]
For example, here’s what happens when we try setting Notepad++ as our default application for .txt files in Windows 10’s Settings app. Windows just ignores our choice and chooses Notepad as the default.

behavior

It appears that I’ve experienced the same thing on a Windows 10 Enterprise (1803). Just keep in mind that we see in the above gif that only “registered” applications can be set. Applications like notepad++ isn’t registered and cannot be set and used for the .txt file association.

I’ve set successfully a group policy that defines the .pdf file to be opened by Adobe Reader. It’s still there and works fine. I’ve created it using the official guidance from Microsoft and the ProgID found in the Adobe documentation on this page.

Using my Google-fu, I also found the following articles that shed some lights on how the file associations work:

I was not able to define and load a custom xml file where I could set notepad++ as the default .txt handler.

After I removed the anti-tampering protection where Microsoft sets a DENY permission on the
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xxx\UserChoice registry key, I could delete values under that key.

I didn’t need to reverse engineer secret hashes under that key like some known tools (setuserfta) do.

All I did actually is remove anything under the UserChoice, create my own ProgId under the OpenWithProgids key and create its related value under the OpenWithList list.

Function Add-FileAssociation {
[CmdletBinding()]
Param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^\.[a-zA-Z0-9]{1,3}')]
$Extension,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[ValidateScript({
Test-Path -Path $_ -PathType Leaf
})]
[string]$TargetExecutable,
[Parameter()]
[string]$ftypeName
)
Begin {
$ext = [Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($Extension)
$exec = [Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($TargetExecutable)
# 2. Create a ftype
if (-not($PSBoundParameters['ftypeName'])) {
$ftypeName = '{0}{1}File'-f $($ext -replace '\.',''),
$((Get-Item -Path "$($exec)").BaseName)
$ftypeName = [Management.Automation.Language.CodeGeneration]::EscapeFormatStringContent($ftypeName)
} else {
$ftypeName = [Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($ftypeName)
}
Write-Verbose -Message "Ftype name set to $($ftypeName)"
}
Process {
# 1. remove anti-tampering protection if required
if (Test-Path -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)") {
$ParentACL = Get-Acl -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)"
if (Test-Path -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\UserChoice") {
$k = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\UserChoice",'ReadWriteSubTree','TakeOwnership')
$acl = $k.GetAccessControl()
$null = $acl.SetAccessRuleProtection($false,$true)
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ($ParentACL.Owner,'FullControl','Allow')
$null = $acl.SetAccessRule($rule)
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ($ParentACL.Owner,'SetValue','Deny')
$null = $acl.RemoveAccessRule($rule)
$null = $k.SetAccessControl($acl)
Write-Verbose -Message 'Removed anti-tampering protection'
}
}
# 2. add a ftype
$null = & (Get-Command "$($env:systemroot)\system32\reg.exe") @(
'add',
"HKCU\Software\Classes\$($ftypeName)\shell\open\command"
'/ve','/d',"$('\"{0}\" \"%1\"'-f $($exec))",
'/f','/reg:64'
)
Write-Verbose -Message "Adding command under HKCU\Software\Classes\$($ftypeName)\shell\open\command"
# 3. Update user file association
@"
Windows Registry Editor Version 5.00
[-HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\OpenWithList]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\OpenWithList]
"MRUList"="a"
"a"="$((Get-Item -Path "$($exec)").Name)"
[-HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\OpenWithProgids]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\OpenWithProgids]
"$($ftypeName)"=hex(0):
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$($ext)\UserChoice]
"Hash"=-
"Progid"=-
"@ |
Out-File -FilePath "$($env:TEMP)\$($ftypeName).dat" -Encoding ascii -Force
& (Get-Command "$($env:systemroot)\regedit.exe") @('/s',"$($env:TEMP)\$($ftypeName).dat")
Write-Verbose -Message 'Updated user file extension under HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts'
}
End {}
<#
.SYNOPSIS
Set user file associations
.DESCRIPTION
Define a program to open a file extension
.PARAMETER Extension
The file extension to modify
.PARAMETER TargetExecutable
The program to use to open the file extension
.PARAMETER ftypeName
Non mandatory parameter used to override the created file type handler value
.EXAMPLE
$HT = @{
Extension = '.txt'
TargetExecutable = "C:\Program Files\Notepad++\notepad++.exe"
}
Add-FileAssociation @HT
.EXAMPLE
$HT = @{
Extension = '.xml'
TargetExecutable = "C:\Program Files\Microsoft VS Code\Code.exe"
FtypeName = 'vscode'
}
Add-FileAssociation @HT
#>
}

Bonus: If you use the Reset button under Default Apps, Microsoft will gracefully restore the previous behavior.
With the above function or script, your user (admin or not) is autonomous and can restore his favorite file associations until Microsoft changes the rules…

18 thoughts on “About File Associations

  1. Pingback: A complex solution to the ‘broken file associations’ problem in Win10 1803 @ AskWoody

  2. Thanks for the great script. I had a minor problem when using an extension which was not already associated with a program. The insertion of an If block solved the problem.
    If ($Null -ne $k) {
    $acl = $k.GetAccessControl()
    $null = $acl.SetAccessRuleProtection($false,$true)
    $rule = New-Object System.Security.AccessControl.RegistryAccessRule ($ParentACL.Owner,’FullControl’,’Allow’)
    $null = $acl.SetAccessRule($rule)
    $rule = New-Object System.Security.AccessControl.RegistryAccessRule ($ParentACL.Owner,’SetValue’,’Deny’)
    $null = $acl.RemoveAccessRule($rule)
    $null = $k.SetAccessControl($acl)
    Write-Verbose -Message ‘Removed anti-tampering protection’
    } #End If ($Null…

    • Thanks for reporting it. My bad, I made a wrong assumption about the existence of the UserChoice registry key. I’ve fixed the code in the gist using the Test-Path cmdlet but your fix also works 🙂

  3. Pingback: Microsoft confirms File Association bug in Windows 10 version 1803 - gHacks Tech News

  4. Pingback: Microsoft、Windows 10 Version 1803/1809で発生しているファイル関連付けの不具合を認める | ソフトアンテナブログ

    • What version and branch of Windows are you running?
      The above is a PowerShell function, it doesn’t do anything by itself.
      You should load it (into memory), then you can use/invoke it. The first example in the help of function shows how to associate the .txt with a notepad++ located in the “program files” folder.
      The function is compatible with “Reset” button I mentioned above. Be careful, the “Reset” button is there to restore many file extensions to the Microsoft default recommended values.

      Microsoft has acknowledged there’s a problem with file associations and will fix it. You can also wait for there fix.

  5. Pingback: Microsoft Broke Windows 10’s File Associations With a Botched Update - How to do easily - Learn How to do Tasks Easily

  6. I had a bit of luck and found very easy alternative solution:

    Right click on .txt -> Open With -> Notepad++ -> Close it
    And now Open properties of file -> Change -> Notepad++

    First line is adding notepad++ to MRU list of .txt. Luckily M$ is allowing you to change associate between MRU items.

  7. we have an issue in our environment where chrome keeps taking over PDFs on windows ver 1803 (17134.648) , i tried using you script and it is unsuccessful on setting the PDF to open with acrobat, a windows notification pops up stating ” an app default was reset ” and then resets PDFs to open with Edge. i tried setting a few other file extensions to open with acroRd32.exe and it works flawless. has anyone else seen this additional protection on PDF files?

  8. Hi, excellent gist, thank you so much for sharing. I don’t fully understand when I should or should not use the ftype option. What does ftype offer where the registry tweak doesn’t / can’t?

    Thanks!

    • It depends on the target application to be launched. There’s an example in the help of the function with vcode. Visual Studio code uses a ftype.
      It offers a single reference in the registry but can have many extensions associated.

  9. Great work, is there a way to refresh the file association icons without rebooting, logging off / restarting explorer.exe? It seems to me like the behavior through MS’s gui does not close explorer at all.

  10. Pingback: Microsoft hat die Dateizuordnungen von Windows 10 mit einem verpfuschten Update gebrochen - Wie Man Tech

  11. Pingback: Microsoft a cassé les associations de fichiers de Windows 10 avec une mise à jour bâclée - Azur Plus

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.