📢 PS-SFTA Latest Update 2020-09-14
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
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
$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 "";
}
}
}
"@
if (-not ([System.Management.Automation.PSTypeName]'SFTA.AssocReg').Type)
{
Add-Type -TypeDefinition $sourceCSharp -Language CSharp
}
$assocProgram=[SFTA.AssocReg]::GetFileTypeAssociation(".pdf")
Write-Host(".PDF Assoc Program = " + $assocProgram)
[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
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
Other Method? Contact Us: hello.danysys@gmail.com
Doesn’t work on Win10 1809 🙁
Hi, this doesn’t work in new Windows 10 versions, Microsoft fixed it, you can check our SFTA command-line tool which is functional.
Microsoft fixed it, as in blocked the script from being able to do this? Or Microsoft fixed it as in the script works now?
It means the script will not work. Microsoft blocked/changed the Interface method that allowed to do it, but You can take a look at our command-line tool ‘SFTA’ It works.
What allows the command line tool to work and not the script?
It does not use the Interface. It use a new method. You can check source code on github. Regards
Thanks a lot for the update !
Impressive work! It is too hard to find a working powershell solution to change the default webbrowser. Your script works very well.
Thank you for your comment Rockschuppen We are happy it helps you.
Regards
Just wanted to reach out and say thanks for converting it to powershell! amazing work
It was a great pleasure. Thank you!!!
Best Regards
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.
Thank you Bryan I’ll update it.
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.
@Ben I’ve not tried yet over 1909. I’ll check as soon as possible.
Best Regards
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