There have been a lot of copies of Windows 8 sold since it came out a few months ago, and the Surface Pro was just released. (In fact, I’m writing this on my brand new Surface Pro, which I really like, but that’s a subject for another time.)
If you’re using ClickOnce deployment, you’re probably wondering how (or if) it’s going to work with Windows 8. I’ve worked with Saurabh Bhatia at Microsoft to ensure that this article will cover what you need to know. We use ClickOnce at GoldMail (whose product is now called Point Across) for our desktop product and VSTO applications, as well as several internal utility applications, so I’ve also tested this on our products to make sure it’s accurate.
If you are hosting your deployment on a file share or on an intranet, you won’t have to make any changes. You can go get ice cream now while the rest of us soldier on.
If you are hosting your deployment on the internet, you will eventually get calls from your customers who have upgraded to Windows 8 or purchased a Windows 8 machine. So let’s talk about that.
I’m not going to talk about the bootstrapper right now; that’s going to come up later. For now, let’s concentrate on the ClickOnce application itself. When a user installs a ClickOnce application on Windows 8, here’s what happens:
- ClickOnce gets the manifest, checks the certificate, and shows the ClickOnce prompt with “trusted publisher” or “unknown publisher” (depending on your signing certificate).
- The user clicks the Install button.
- It checks the certificate on the executable. If it’s not signed, the Smart Screen Filter is triggered.
So here’s what the user experience looks like when you install a ClickOnce application on Windows 8:
You get the standard install prompt:
The publisher is known because I am signing the deployment with a signing certificate purchased from a Certificate Authority – in this case, Verisign.
If you click Install, it shows the standard install dialog and actually installs the application. But then it shows a blue band across your screen saying, “Windows SmartScreen prevented an unrecognized app from starting. Running this app might put your PC at risk.”
There is a small “More Info” link under the warning, and a big “OK” button on the bottom of the dialog. Which one would you click? Which one would your customers click? Most people will click the OK button.
If the user clicks OK, the dialog closes, and nothing else happens. Now let’s say the user goes to TileWorld (I’m borrowing David Pogue’s name for the new Windows 8 interface formerly known as Metro). The user can see the application there in the list of apps because it actually got installed. If he clicks on it to run it, nothing happens. So congratulations! The user has installed your application, but he can’t run it.
What happens if the user clicks “More Info” instead of “OK”? He sees the following screen, and he can choose “Run Anyway” or “Don’t run”.
For “Publisher”, it says “Unknown publisher” – this is referring to the executable, which is not specifically signed. Only the manifests are signed. This has never been a requirement for ClickOnce deployments. Until now.
If the user chooses “Run Anyway”, it will run the application. Yay! And when he goes back to TileWorld and tries to run it from there the next time, it will work and will not prompt him again. Yay!
So let’s say he clicks “Run Anyway”, and now he has no problem running your application. What happens when an update is published and he installs it? Uh-oh. The smart screen filter interrupts again, and he has to select “More Info” and “Run Anyway” again.
Is there a way to circumvent your ClickOnce application being captured and stopped by the Smart Screen Filter? Yes. Otherwise, this would be a much shorter (and depressing) article. All you have to do is sign the application executable after building it and before deploying it. For this, you need your signing certificate and signtool.exe, which is one of the .NET Framework tools. There are three points in the build/publish process at which you can do this:
#1: Signing the application executable post-publish
To do it post-publish, you have to do the following:
- a. Publish the files to a local directory.
- b. Use signtool to sign the exe for the application.
- c. Use mage or mageUI to re-sign the application manifest (.exe.manifest).
- d. Use mage or mageUI to re-sign the deployment manifest (.application).
- e. Copy the files to the deployment location.
If you’ve already automated your deployment with a script and msbuild, this may be the choice you make. If you publish directly from Visual Studio, the other two options are easier.
#2: Signing the application executable post-build
To do this, you define a post-build command in your project. Assuming your certificate (pfx file) is in the top level of your project, you can use something like this:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\signtool.exe" sign /f "$(ProjectDir)TestWin8CO_TemporaryKey.pfx" /p nightbird /v "$(ProjectDir)obj\x86\$(ConfigurationName)\$(TargetFileName)"
- The double quotes are required.
- “C:Program Files (x86)Microsoft SDKsWindows\v7.0A\bin\signtool.exe” is the path to the signtool application, used to sign the executable.
- $(ProjectDir) points to the top directory of the project. The subfolder “\obj\x86” will vary depending on your build output path. The above was created and tested on VS2010. On VS2012, my subfolder is just \obj.
- $(ConfigurationName) is the build configuration name, such as Debug or Release – this is required because it signs it in the obj directory and has to know which folder to use.
- $(TargetFileName) is the name of the application executable.
- TestWin8CO_TemporaryKey.pfx is the name of my certificate file, which is in the top folder of my project.
- /p nightbird – this is the password for my temporary certificate
I have specified the full path to signtool.exe. I tried to do this with one of the msbuild variables that points to the location of the .NET framework files, but it doesn’t work – it doesn’t translate the variable until after it executes the statement. If you print it out in the post-build command, it shows the right location in the Visual Studio output window, but gives you an error that it can’t find it when it actually runs this statement. I’m saving you some time here, because I messed around with that for quite a while trying to get it to work, and after asking Saurabh at Microsoft, he couldn’t get it to work without specifying the whole path, either. So if you get it to work with a msbuild variable, let me know how.
After you’ve created your version of the post-build command, you need to put it in the project properties. Double-click on Properties and click on the Build Events tab. Put your command in the Post-build event command line box.
Now build the project, and the output window will show the results.
If you now publish the application and put the files in the deployment directory, the user can install it and will not see the Smart Screen Filter. Yay!
What if you have multiple programmers working on the application, and they all build and run the application? Every programmer must have signtool.exe in the exact same location for this post-build command to work for everybody. If you have a 32-bit machine, the folder for the “Microsoft SDKs” is under “C:Program Files”, without the “(x86)” on the end. And someone might actually install Windows to a drive other than C. If their signtool.exe file is not in the same location, they can’t build and run the application, which means they can’t put in changes and test them.
Only the person publishing the application really needs this build command to work. So how do you execute this only for the person publishing the application? You can set up a pre-publish command.
#3: Signing the application executable pre-publish (recommended solution)
The pre-publish command is executed after building the application and right before publishing it. There is no box for this under Build Events, so you have to add it to the project yourself. (Be sure to clear out the post-build event command line before doing this.)
To add a pre-publish command, right-click on the project in Visual Studio and select “Unload Project”.
Now right-click on the project again and select “Edit yourprojectname.csproj”.
It will open the csproj file in Visual Studio so you can edit it. Go down to the bottom and add a new section before the </Project> line. You’re going to put your pre-publish command line in this section.
So what do you put in this section? You are going to specify a command to execute, so you have to use Exec Command, and put the command to execute in double quotes. Since you can’t put double-quotes inside of double-quotes (at least, not if you want it to work), you need to change the double-quotes in your command to " instead. So my build command from above now looks like this:
<Exec Command=""C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\signtool.exe" sign /f "$(ProjectDir)TestWin8CO_TemporaryKey.pfx" /p nightbird /v "$(ProjectDir)obj\x86\$(ConfigurationName)\$(TargetFileName)"" />
After making this match your parameters, save the csproj file and then close it. Then right-click on the project and reload it:
Now if you build your project, you won’t see anything about signing the application executable in the output window. It will only do it if you publish, and there won’t be logging letting you know it signed it. How do you know if it worked? Go to the folder you published to, and look in the Application Files folder. Locate the application executable in the folder for the new version. Right-click on it, choose properties. Look for a tab called “Digital Signatures”. If it’s not found, it’s not signed. If you do see it, go to that tab; it will show the signature list and the signer of the certificate. You can double-click on the signer and then view the signing certificate.
How will the application work after publishing it with a signed executable?
If you sign your executable and your deployment with a valid certificate from a Certificate Authority like Verisign using one of the methods above, when the user clicks install, it will install without stopping and showing the SmartScreen filter, and updates will do the same. Yay!
Do I have to use a certificate from a Certificate Authority to circumvent the Smart Screen Filter?
Is there any workaround?
If you try the old tried and true “install the certificate in the trusted publishers store on the client computer”, you will find that this does not circumvent the Smart Screen Filter. You must have a certificate from a valid Certificate Authority. Without one, your customer will get the Smart Screen filter when he installs the application, and every time he installs an update.
What about the bootstrapper (setup.exe)?
The bootstrapper (setup.exe) is signed the same way as the ClickOnce deployment; this happens when you publish. When run, this installs the prerequisites and then calls the ClickOnce application installation. If your certificate is not from a valid CA, the Smart Screen Filter will catch it. This isn’t as critical a problem as the ClickOnce deployment itself because in most cases, your users will only run this the first time.
What about VSTO applications?
If your VSTO application is deployed via a file share or the intranet zone, you will not be impacted. If your VSTO application is deployed via the Internet zone, you may be impacted.
There is no executable for a VSTO application, just an assembly, so you don’t have to do any extra signing. However, the following is true:
If you sign your deployment with a certificate from a CA, everything will work fine, and the Smart Screen filter will not interrupt either the setup.exe or the vsto file from installing the app or keep the app from running.
If you are using a test certificate, setup.exe will be caught by the Smart Screen filter. If you click ‘Run Anyway’, it will install the prerequisites, but it will not let you install the VSTO application.
If you install the test certificate in the Trusted Publishers store, setup.exe will still be caught by the Smart Screen filter, but the VSTO application can be installed and run. This is strongly advised against, as installing the certificate on the user’s machine introduces a significant security risk.
Which method to you recommend?
The advantage of the post-build command is that it is transparent. You can easily go into the Build properties and see there is a post-build command. A pre-publish command is kind of hidden in the project file. However, everybody has to have signtool.exe in the same place, and for us that’s a non-starter. Also, if I did leave the post-build command in there, someone might change it to match their path and check in the change, causing a problem when we actually try to build the application for production.
I used the post-build methods to test my build command until I got it to work, and then ported it to a pre-publish command.
To summarize, a flowchart:
In summary, here’s a flowchart to help you easily see whether your users will get the Smart Screen filter when they install your application on Windows 8.
One last note: The first version of VS2012 had a bug where the bootstrapper created when publishing a ClickOnce application would not work on a Windows XP machine. This problem was fixed in the first update.
[edit: Fixed build paths, some \’s were missing. Added recommendation. –Robin 2.26.2013]
[edit: After publishing this article, I heard from a couple of people who were still having problems. Please check out the next blog article about this if you are still having problems with the Smart Screen filter, or getting the dreaded “exe has a different computed hash than the manifest” error. –Robin 4.14.2013]