PowerShell Set File Type Association Default Application Windows 10

? PS-SFTA Latest Update 2022-04-17

Tested in: Windows 8, Windows 8.1, Windows 10 Version 1511, Windows 10 Version 1709, Windows 10 Version 1803, Windows 10 Version 1809, Windows 10 Version 1903, Windows 10 Version 1909, Windows 10 Version 20H2, Windows 11 Pro Version 21H2


In our previous post we shared a command line tool to associate an application with a specific file type, however one of our visitors could not use the tool in his work environment due to restrictions because they could not use third-party executable applications, and told us that he wanted to do it using PowerShell.

Taking into account his very interesting idea and our passion for the world of scripting and sysadmin, we decided to create a simple version of SFTA in PowerShell using the Add-Type command that allows us to compile .NET code and use it in our Powershell instance. This is the Old Version. Use GitHub Version Instead.

Old PowerShell Script Using IApplicationAssociationRegistrationInternal
##################################
##   __                         ##
##   |  \  _   _      _     _   ##
##   |__/ (_| | ) \/ _) \/ _)   ##
##                /     /       ##
##     © 2019 Danysys.com       ##
##       SFTA-PS v.1.0.0        ##
##################################

$sourceCSharp=@"
using System;
using System.Runtime.InteropServices;

namespace SFTA
{
    public static class AssocReg
    {


        [ComImport()]
        [Guid("14EBCC88-2831-4FC8-A5DF-9F36A81DB12C")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IApplicationAssociationRegistrationInternalW10_1709
        {
            [PreserveSig]
            void Dummy1();
            [PreserveSig]
            void SetProgIdAsDefault([MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName, [MarshalAs(UnmanagedType.LPWStr)] string pszSet, int atSetType);
            [PreserveSig]
            void Dummy3();
            [PreserveSig]
            void Dummy4();
            [PreserveSig]
            void Dummy5();
            [PreserveSig]
            void Dummy6();
            [PreserveSig]
            void QueryCurrentDefault([MarshalAs(UnmanagedType.LPWStr)] string pszExt, int atQueryType, int alQueryLevel, [Out, MarshalAs(UnmanagedType.LPWStr)] out string ppszAssociation);
        }

        private interface IApplicationAssociationRegistrationInternalW8_1_63
        {
            [PreserveSig]
            void Dummy1();
            [PreserveSig]
            void SetProgIdAsDefault([MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName, [MarshalAs(UnmanagedType.LPWStr)] string pszSet, int atSetType);
            [PreserveSig]
            void Dummy3();
            [PreserveSig]
            void Dummy4();
            [PreserveSig]
            void Dummy5();
            [PreserveSig]
            void Dummy6();
            [PreserveSig]
            void QueryCurrentDefault([MarshalAs(UnmanagedType.LPWStr)] string pszExt, int atQueryType, int alQueryLevel, [Out, MarshalAs(UnmanagedType.LPWStr)] out string ppszAssociation);
        }

        [ComImport()]
        [Guid("591209c7-767b-42b2-9fba-44ee4615f2c7")]
        [ClassInterface(ClassInterfaceType.None)]
        private class ApplicationAssociationRegistration
        {
        }

        public static bool Debug  = false;
        private static readonly IApplicationAssociationRegistrationInternalW10_1709 AppAssocReg10 = new ApplicationAssociationRegistration() as IApplicationAssociationRegistrationInternalW10_1709;
        private static readonly IApplicationAssociationRegistrationInternalW8_1_63 AppAssocReg8 = new ApplicationAssociationRegistration() as IApplicationAssociationRegistrationInternalW8_1_63;

        private static void WriteDebug(string message)
        {
            if ( Debug)
            {
                Console.WriteLine(DateTime.Now.ToString("[yyyy.dd.MM HH:mm:ss]") + " "+ message);
            }
        }
        public static void SetFileTypeAssociation(string ProgramId,string Ext)
        {
            if (AppAssocReg10 != null)
            {
                WriteDebug("OK AppAssocReg10");
            AppAssocReg10.SetProgIdAsDefault(ProgramId, Ext, 0);
                return;
            }

            if (AppAssocReg8 != null)
            {
                WriteDebug("OK AppAssocReg8");
            AppAssocReg8.SetProgIdAsDefault(ProgramId,Ext, 0);
                return;
            }

            WriteDebug("FAIL AppAssocReg");

        }

        public static string GetFileTypeAssociation( string Ext)
        {
            
            if (AppAssocReg10 != null)
            {
                WriteDebug("OK AppAssocReg10");
                var assocApplication = "";
                AppAssocReg10.QueryCurrentDefault(Ext, 0, 1, out assocApplication);
                WriteDebug("assocApplication = " + assocApplication);
                return assocApplication;
            }

            if (AppAssocReg8 != null)
            {
                WriteDebug("OK AppAssocReg8");
                var assocApplication = "";
                AppAssocReg8.QueryCurrentDefault(Ext, 0, 1, out assocApplication);
                WriteDebug("assocApplication = " + assocApplication);
                return assocApplication;
            }


            WriteDebug("FAIL AppAssocReg");
            return "";

        }

    }
}
"@
#Add Type
if (-not ([System.Management.Automation.PSTypeName]'SFTA.AssocReg').Type)
{
    Add-Type -TypeDefinition $sourceCSharp -Language CSharp
}


#Sample Usage
#[SFTA.AssocReg]::Debug=$true; #Show Debug Information
#Get
$assocProgram=[SFTA.AssocReg]::GetFileTypeAssociation(".pdf")
Write-Host(".PDF Assoc Program = " + $assocProgram)
#Set
[SFTA.AssocReg]::SetFileTypeAssociation("Applications\SumatraPDF.exe",".pdf")

PS-SFTA Latest Version

Sample Usage:

Set Acrobat Reader DC as Default .pdf reader:

Set-FTA AcroExch.Document.DC .pdf

Additional Instructions:

Set Microsoft Edge as Default .pdf reader from Windows Command Processor (cmd.exe):

powershell -ExecutionPolicy Bypass -command "& { . .\SFTA.ps1; Set-FTA 'MSEdgePDF' '.pdf' }"

We hope this will be useful for you!!!

If you find this useful, a small donation would be greatly appreciated.

  • Bitcoin
  • Ethereum
  • Binance coin
  • Litecoin
Scan to Donate Bitcoin to 1Lrei7nhGeazvnJZHduGCduER2thjwD12F

Donate Bitcoin to this address

Scan the QR code or copy the address below into your wallet to send some Bitcoin

Scan to Donate Ethereum to 0x6BF5A047ebE7563D98e60887ab6e9485cB3564FF

Donate Ethereum to this address

Scan the QR code or copy the address below into your wallet to send some Ethereum

Scan to Donate Binance coin to bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23

Donate Binance coin to this address

Scan the QR code or copy the address below into your wallet to send some Binance coin

Tag/Note:- BEP2
Scan to Donate Litecoin to LfLJrcNEfA8Td8n2R3eV6AV3QTfNp8XgBX

Donate Litecoin to this address

Scan the QR code or copy the address below into your wallet to send some Litecoin

Other Method? Contact Us: hello.danysys@gmail.com

46 thoughts on “PowerShell Set File Type Association Default Application Windows 10

  • Impressive work! It is too hard to find a working powershell solution to change the default webbrowser. Your script works very well.

  • Excellent Job. One thing would help avoid confusion is some documentation to determine the appropriate Program Id. I was using ‘AcroExch.Document.DC’ from your examples which looked right but wasn’t.

    Set program via explorer
    Run: Get-FTA .pdf to see Program Id
    Then reset program back to default via explorer
    Run: Set-FTA .pdf

    In my case this was the ProgramId = ‘Acrobat.Document.DC’

    Thanks again! Awesome work.

  • Hi,
    Does this still work or not? I am trying the script from github on 1909 and after setting PTA for http or https, I get a message saying it was reset to default.

      • In 1909 onwards, Microsoft added a checksum/signature to FTA’s and if that isn’t correct or is missing then the FTA is reset to default by Edge (even where Edge has nothing to do with the FTA or program used).

        TMK the API to calculate the checksum/signature has not been exposed or documented by Microsoft.

        I’d love to be proved wrong BTW as this is the bane of my life at the moment!

        • Hi Steve J. Yes this was added in previous versions. I think from Windows 2008 to current versions. By the way, did you try the latest code? It was tested in 1909 and it works fine. Checksum/Signature was exposed using Reverse Engineering due to It’s an undocumented API.

          Regards

  • Hi I am using the script with Windows version 1909, but returns me an error “The term ‘Set-FTA’ is not recognized as the name of a cmdlet”

    • Hello @Kenji. Probably You’re not loading the module correctly or you have not configured Execution Policy.

      Try this way:

      powershell -ExecutionPolicy Bypass -command "& { . .\SFTA.ps1; Set-FTA 'ChromeHTML' '.pdf' }"

      Make sure the cmd/powershell working/current directory is same than SFTA.ps1.

      Regards

  • Does this work in the system context as I am going to include the SCCM Task sequence to update post-Windows 10 upgrades??

    • Hi Noorul,
      This will ONLY work if it is run in the user context. You would need to set something up to run as the user on the next logon. Perhaps you could use the task sequence to create a scheduled task to run on logon for the user.

  • In 21H1, it does not seem to work or do anything that I can see. No warnings or errors. I should note I am experienced with coding, batch files, and Windows repair, over 15 years experience. I tried a number of methods to get it to run.

    powershell -ExecutionPolicy Bypass -file “%~dp0SFTA.ps1” ChromeHTML http

    • Hello @Eran. You’re not calling any function. Try this way:

      powershell -ExecutionPolicy Bypass -command "& { . .\SFTA.ps1; Set-PTA 'ChromeHTML' 'http' }"

      Make sure console current directory path matches SFTA.ps1’s directory path.

      Regards

  • Hello, the github version appears to have broken for specifically setting the “http” protocol on (at least, this is the server I’ve been testing on), Windows Server 2016 ver 1607. Set-PTA will complete with no error messages, however the output from Get-PTA will not include HTTP (it functions just fine for HTTPS)

  • Windows 10 21H1.
    using the cmd.exe syntax from your 2021.03.12 post on this page for pdf’s.
    get error: “unable to cast object type”

    —————————————————–
    C:\scripts>powershell -ExecutionPolicy Bypass -command “& { . .\SFTA.ps1; Set-FTA AcroExch.Document.DC .pdf }”
    Unable to cast object of type ‘System.DirectoryServices.AccountManagement.GroupPrincipal’ to type ‘System.DirectoryServices.AccountManagement.UserPrincipal’.
    At C:\scripts\SFTA.ps1:474 char:5
    + [OutputType([string])]
    + ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (:) [], InvalidCastException
    + FullyQualifiedErrorId : System.InvalidCastException

    The variable ‘$userSid’ cannot be retrieved because it has not been set.
    At C:\scripts\SFTA.ps1:476 char:18
    + Write-Output $userSid
    + ~~~~~~~~
    + CategoryInfo : InvalidOperation: (userSid:String) [], RuntimeException
    + FullyQualifiedErrorId : VariableIsUndefined
    ————————————————-

    it’s like it doesn’t like the “string” variable in this section, but that’s where the water gets too deep for me.
    function local:Get-UserSid {
    [OutputType([string])]
    $userSid = ([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).SID.Value.ToLower()
    Write-Output $userSid
    }

      • Note: in case it means anything to you….with the most recent version, if I manually run the following two commands in powershell…it work as expected.

        PS>. .\SFTA.ps1
        PS>get-fta
        .3g2, AppX6eg8h5sxqq90pv53845wmnbewywdqq5h
        .3gp, AppX6eg8h5sxqq90pv53845wmnbewywdqq5h
        .3gp2, AppX6eg8h5sxqq90pv53845wmnbewywdqq5h
        .3gpp, AppX6eg8h5sxqq90pv53845wmnbewywdqq5h
        .3mf, Applications\Cura.exe

  • Thank you sir. That older command seems to work as expected.

    NOTE: I got a lot of syntax errors in VS Code with the old version of the script. Like 3/4 of the script was solid red (starting at line 198), I toyed with the @ symbols (removing one space to the left, in three locations)…got the red to go away…but then the script failed.

    Soooooo….I copied line 474 from the old version, into the new SFTA.ps1 and rem’d out the existing DirServ.AcctMgt.UsrPrin line and and it seems to play nice now.
    thank you again.
    great tool for an overly complex bit of MS sillyness.

    PS>powershell -ExecutionPolicy Bypass -command “& { . .\SFTA_test.ps1; Set-FTA AcroExch.Document.DC .pdf }”
    At C:\SFTA_test.ps1:198 char:3
    + ‘@
    + ~~
    White space is not allowed before the string terminator.
    At C:\scripts\SFTA_test.ps1:171 char:41
    + function local:Remove-UserChoiceKey {
    + ~
    Missing closing ‘}’ in statement block or type definition.
    At C:\scripts\SFTA_test.ps1:158 char:23
    + function Remove-FTA {
    + ~
    Missing closing ‘}’ in statement block or type definition.
    + CategoryInfo : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : WhitespaceBeforeHereStringFooter

    Set-FTA : The term ‘Set-FTA’ is not recognized as the name of a cmdlet, function, script file, or operable program.
    Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:24
    + & { . .\SFTA_test.ps1; Set-FTA AcroExch.Document.DC .pdf }
    + ~~~~~~~
    + CategoryInfo : ObjectNotFound: (Set-FTA:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

  • Trying to set Mailto protocol default to Outlook on Win 10 20H2, its working fine but sometime later MailTo reverting back to native Mail app with error “An App Default was reset” any one seeing this issue ?

    • Hi, is this what causes the mailto protocol to be reset?, I’ve never use FIPS before. So I don’t know what could be done for solving this issue.

      Regards

      • Fips is not enabled yet on all machines, so these are two different issues
        mailto protocol resetting back to native mail even on machines with Fips currently disabled

        Fips looks like going to be mandatory for the future, assuming your setfta.exe also needs Fips to be disabled correct ?

        • You need to test by yourself if it works or not with FIPS. I think it should work but You need to test.
          About the reset how long it takes for reset? after restart or when does it happen?

  • I am not a programmer. I am desktop support. If I can get this to work on a remote computer it will save a lot of time when default .pdf readers get changed to Edge.

    I got this to run on my computer Win10 21H2. Run the .ps1 in ISE. Next line: Get-FTA .pdf. It gives the correct setting & I was able to change it to Adobe from another PDF reader.

    How can I run this on a remote computer? I tried the same way but like this for remote computer: Invoke-Command -FilePath “the actual file path here.ps1” -ComputerName RemoteComputerNameHere Then next line: Get-FTA .pdf

    It gives me the setting from my computer, not the remote computer, which is in my office, so I can verify it. I tried to add it to the end of the command in different ways but none worked correctly.

  • so the examples and the posts are not super clear on how you are to execute this thing? In the script it only references the functions. If I can get this working , woah this will solve a problem i have with deploying a crappy app via untune.

  • I have not yet tried it as I have only read posts and the examples within the script itself. Before I do anything I am simply looking for how to best run the script. I see things in the synopsis like simply using Set-FTA but calling that would do nothing. Looking at what it is supposed to do I think it could have some real benefits in managing default associations within the newer windows world for sure.

    • It’s quite simple to use it. I’ll add some examples more in the Post with more information about running the script as I have on GitHub. It you have any question just tell me. Regards

Leave a Reply

Your email address will not be published. Required fields are marked *