Certmgr shows I have my company's Symantec Class 3 SHA256 Code Signing CA installed, along with ones with Private in the name. Can I add this line to my Assembly Info:
[assembly: AssemblyKeyName("what name do I use here?")]
to strongly-name an assembly at build time? Would that find the public/private key pair in the certificate store and insert them into my assembly? Or do I have to extract the public/private key pair from the certificates and use the well-documented process for strong-naming that I see all over the Internet?
I've tried the above with variations of the company name but build fails with:
Keyset does not exist
Here is a blog post that explains what needs to be done: https://matthewdippel.blogspot.com/2017/09/howto-strong-name-sign-net-assembly.html
However, there’s an ugly catch-22. Running sn.exe -c, if it ends up changing the CSP, can only be done as an elevated user. However, that same elevated user cannot access the key in the personal store of your non-elevated account. So simply adding this to the pre-build or post-build and running Visual Studio under elevation results in the exact same Keyset not found error on build.
...
To get this working, you’ll need the script located at this gist. The only requirement is that you have the .Net Framework SDK 4.6, 4.6.1 or 4.6.2 installed. It uses it to get the path to the sn.exe file so that it’ll work regardless of how your system is configured.
Related
I have a windows forms application that is deployed to two different locations.
Intranet - ClickOnce
Internet - Installed on a citrix farm through Windows installer
I display ClickOnce version number for click-once deployed versionApplicationDeployment.IsNetworkDeployed.
if (ApplicationDeployment.IsNetworkDeployed)
return ApplicationDeployment.CurrentDeployment.CurrentVersion;
But for the non-click application, I am not sure how to retrieve clickonce version unless I hardcode the version number in assembly info.
Is there an automatic way of retrieve ClickOnce version number for non-clickonce deployed version?
Add an assembly reference to System.Deployment to your project.
Import the namespace in your class file:
VB.NET:
Imports System.Deployment.Application
C#:
using System.Deployment.Application;
Retrieve the ClickOnce version from the CurrentVersion property.
You can obtain the current version from the ApplicationDeployment.CurrentDeployment.CurrentVersion property. This returns a System.Version object.
Note (from MSDN):
CurrentVersion will differ from UpdatedVersion if a new update has
been installed but you have not yet called Restart. If the deployment
manifest is configured to perform automatic updates, you can compare
these two values to determine if you should restart the application.
NOTE: The CurrentDeployment static property is only valid when the application has been deployed with ClickOnce. Therefore before you access this property, you should check the ApplicationDeployment.IsNetworkDeployed property first. It will always return a false in the debug environment.
VB.NET:
Dim myVersion as Version
If ApplicationDeployment.IsNetworkDeployed Then
myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion
End If
C#:
Version myVersion;
if (ApplicationDeployment.IsNetworkDeployed)
myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion;
Use the Version object:
From here on you can use the version information in a label, say on an "About" form, in this way:
VB.NET:
versionLabel.Text = String.Concat("ClickOnce published Version: v", myVersion)
C#:
versionLabel.Text = string.Concat("ClickOnce published Version: v", myVersion);
(Version objects are formatted as a four-part number (major.minor.build.revision).)
No I do not believe that there is a way. I believe the ClickOnce information comes from the manifest which will only be available in a ClickOnce deployment. I think that hard coding the version number is your best option.
I would simply make the assembly version of the main assembly the same as the CLickOnce version every time you put out a new version. Then when it runs as a non-clickonce application, just use Reflection to pick up the assembly version.
Try thread verification:
if (ApplicationDeployment.IsNetworkDeployed)
{
if (ApplicationDeployment.CurrentDeployment.CurrentVersion != ApplicationDeployment.CurrentDeployment.UpdatedVersion)
{
Application.ExitThread();
Application.Restart();
}
}
not that it matters three years later, but I ended up just parsing the manifest file with xml reader.
To expand on RobinDotNet's solution:
Protip: You can automatically run a program or script to do this for you from inside the .csproj file MSBuild configuration every time you build. I did this for one Web application that I am currently maintaining, executing a Cygwin bash shell script to do some version control h4x to calculate a version number from Git history, then pre-process the assembly information source file compiled into the build output.
A similar thing could be done to parse the ClickOnce version number out of the project file i.e., Project.PropertyGroup.ApplicationRevision and Project.PropertyGroup.ApplicationVersion (albeit I don't know what the version string means, but you can just guess until it breaks and fix it then) and insert that version information into the assembly information.
I don't know when the ClickOnce version is bumped, but probably after the build process so you may need to tinker with this solution to get the new number compiled in. I guess there's always /*h4x*/ +1.
I used Cygwin because *nix scripting is so much better than Windows and interpreted code saves you the trouble of building your pre-build program before building, but you could write the program using whatever technology you wanted (including C#/.NET). The command line for the pre-processor goes inside the PreBuildEvent:
<PropertyGroup>
<PreBuildEvent>
$(CYGWIN_ROOT)bin\bash.exe --login -c refresh-version
</PreBuildEvent>
</PropertyGroup>
As you'd imagine, this happens before the build stage so you can effectively pre-process your source code just before compiling it. I didn't want to be automatically editing the Properties\AssemblyInfo.cs file so to play it safe what I did was create a Properties\VersionInfo.base.cs file that contained a text template of a class with version information and was marked as BuildAction=None in the project settings so that it wasn't compiled with the project:
using System.Reflection;
using EngiCan.Common.Properties;
[assembly: AssemblyVersion("0.$REVNUM_DIV(100)$.$REVNUM_MOD(100)$.$DIRTY$")]
[assembly: AssemblyRevisionIdentifier("$REVID$")]
(A very dirty, poor-man's placeholder syntax resembling Windows' environment variables with some additional h4x thrown in was used for simplicity's/complexity's sake)
AssemblyRevisionIdentifierAttribute was a custom attribute that I created to hold the Git SHA1 since it is much more meaningful to developers than a.b.c.d.
My refresh-version program would then copy that file to Properties\VersionInfo.cs, and then do the substitution of the version information that it already calculated/parsed (I used sed(1) for the substitution, which was another benefit to using Cygwin). Properties\VersionInfo.cs was compiled into the program. That file can start out empty and you should ignore it by your version control system because it is automatically changing and the information to generate it is already stored elsewhere.
Hard code, or... Keep track on your versions (File, Assembly, Deploy) in a database. Make a call to the database with your Assembly and get the Deploy version.
This assumes that you are incrementing your versions in a logical way such that each version type has a relationship. It's a lot of work for such a minor problem. I'd personally go with Jared's solution; although I hate hard coding anything.
Using a build component, you could read the click-once version from the project file and write it automatically to the assembly info so both of them are in sync.
Solution for .NET (Core) 7 and higher
On .net Core, you can read the version number from the environment variable ClickOnce_CurrentVersion.
string versionString = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion") ?? "0.0.0.0";
Version version= Version.Parse(versionString);
MessageBox.Show(version.ToString());
See documentation
On my ASP.net site I have a reference to Microsoft.SQLserver.SMO. I copied this reference onto my production server and got a could not load error for Microsoft.SqlServer.Management.Sdk.Sfc. This error was fixed by copying the dll from the
C:\Program files\Microsoft Sql Server\110\SDK\Assembilies
However I then got the same error but for Microsoft.SqlServer.SqlClrProvider which is nowhere to be found.
Where can I find the SqlClrProvider dll? It works on my localhost so it must be somewhere.
On your development machine or a machine where you have SQL Server installed, the Microsoft.SqlServer.SqlClrProvider.dll file is in your GAC. However, you cannot copy this file without making changes to the registry.
Using the registry editor, go to HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Fusion. Add a new DWORD called DisableCacheViewer. Give it a value of 1.
Once this change is made, you can go to C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.SqlClrProvider\ to get the dll you need.
To see a more detailed explanation, follow one of these links:
HOW TO RESOLVE “SQLCLRPROVIDER NOT FOUND” WITHOUT INSTALLING SQL SERVER ON THE CLIENT MACHINE OR NEEDING A DEPLOYMENT PROJECT
Could not load file or assembly Microsoft.SqlServer.SqlClrProvider
I wanted to make an embedded script in powershell and stumble upon your same problem.
The thing is that Microsoft.SqlServer.SqlClrProvider.dll is not installed in SQL files but in windows assembly.
Assembly folder is special: you can't copy anything with windows UI.
I just needed the Microsoft.SqlServer.SqlClrProvider.dll so that I can load it in my script like that:
[System.Reflection.Assembly]::LoadFile($scriptPath+"dll\Microsoft.SqlServer.SqlClrProvider.dll") | out-null
to copy it you can do the following:
c:\>cd c:\Windows\assembly
c:\Windows\assembly>dir /s Microsoft.SqlServer.SqlClrProvider.dll
# here you get the directory and the file
c:\Windows\assembly>copy c:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.SqlClrProvider\<version>\Microsoft.SqlServer.SqlClrProvider.dll c:\Users\Administrator\Desktop\
you want to do that on a machine with SQLserver installed otherwise you may not find it.
It's just a workaround. I guess it's not the best thing to do if you need to execute your script in different environments.
hth
Copying SqlClrProvider dll into sqlserver Binn directory didn't help in my case.
Cause:
It was cause by using different versions of SQLServer on production machine and target machine.
Solution:
Make sure you are using the same version of SMO libraries as you have on the target machines. If there is SQLServer2008 on the target machine you must use v10 libraries otherwise you would get this error.
MoreDetails:
SqlServer on my target machines was version 2008 (10) and I had SqlServer2014 (12) on my own machine. When I used SMO library visualstudio added v12 libraries (Microsoft.SqlServer.SMO, ...) but smo is just a shell which use SqlClrProvider and it expects to have SqlClrProvider of same version on system assemblies. this caused the application to crash on the target machine since the v12 of SqlClrProvider didn't exist. By using v10 smo libraries I solved the problem
Had the same issue but for version 11. To get the right assemblies installed a did the following steps:
Check what version is expected: https://sqlserverbuilds.blogspot.com/. Version 11 => sql server 2012
Download Microsoft's web platform installer and install it
Search for 'sql server 2012' and install one or all of the following:
The first thing you need to do is disable the GAC Shell extension which allows you to browse the GAC, to do this:
Open “regedit”
Navigate to
HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Fusion
Add a new DWORD or 32
bit DWORD named DisableCacheViewer with the Hex value of 0x1 or a
decimal value of 1
That disables the GAC Shell allowing you to fully browse assembly folder, now we can extract the assembly from the GAC and drop it into the bin folder or the dll location on the client machine.
Go to C:\Windows\assembly\GAC_MSIL\Microsoft.SqlServer.SqlClrProvider\
You may notice more than folder here, this is for each version of SQL server you have installed
For SQL 2012 it will be : \11.0.0.0__89845dcd8080cc91
You will then find the file Microsoft.SqlServer.SqlClrProvider.dll
Reference
I could not solve my issue, while using Microsoft.Sqlerver.SMO reference. So I instead used the System.Data.Sql.SqlDataSourceEnumerator class for all my Sql functionality needs.
For people googling this error, and arriving here, there is another possibility. Go into Services, and make sure that your SQL Server process can run. On my machine, the password for the user account had changed. Once I fixed the password, the process started, and I no longer received the above error.
We are building an Outlook plugin in C#. It is built without problems in VS and signed with a temporary pfx certificate. We want to put the build process in Jenkins and have it run automatically.
We tried to run the VS solution with MSBuild. It works great on the development machine but in Jenkins there is an error:
Cannot import the following key file: OutlookPlugin_TemporaryKey.pfx. The key file
may be password protected. To correct this, try to import the certificate again or manually
install the certificate to the Strong Name CSP with the following key container name:
VS_KEY_A688DC31A30F3EF1
We don't know how to specify the pfx password for the automated build. Or otherwise automate the sign process.
One solution we found was to open the project in VS on the same machine and as the same user as for the automated process and type the password. This doesn't work, probably because Jenkins wipes out the workspace every time.
If we try to compile without signing and then sign it afterwards, it complains that a ClickOnce assembly must be signed. It seems that Office plugins must use ClickOnce.
So, how to specify the pfx password somewhere in the build file ?
We use VS 2010 with Office Tools.
Create a file (either local or on a well known network share) containing the password as a property and reference that from the MSBuild script. Set permissions on the file such that only the build account can read that file. Note that anyone with admin access to the build machine or that knows the build account password will be able to read the password. Ultimately, there is no silver bullet here. If MSBuild can find/decrypt/whatever the password, a human will be able to, too.
If you are concerned about the security of the private key, consider separating the signing to a separate step and store the private key on a smartcard. It may be overkill but it is one of the best, commonly available protections available.
Otherwise, just add the password as a property. As you know the project files are just MSBuild scripts. For example:
<PropertyGroup>
<PfxPassword>password</PfxPassword>
</PropertyGroup>
<!-- Sample sign task -->
<SignTask>
<File>MyOutlookPlugin.dll</File>
<KeyFile>OutlookPlugin_TemporaryKey.pfx</KeyFile>
<Password>$(PfxPassword)</Password>
</SignTask>
See http://msdn.microsoft.com/en-us/library/ms171458(v=vs.80).aspx for more information about MSBuild properties.
We were having issues building the project with MSBuild and Bamboo. The fix for us was to remove the following line from the .csproj file.
<AssemblyOriginatorKeyFile>applicationcert.pfx</AssemblyOriginatorKeyFile>
I am desperately trying to deploy an ActiveX for IE developed in C# as a CAB archive. I have read many resources (some of them from StackOverflow) and it appears a lot of people are having the same problems. I have tried 3 solutions: a) creating a CAB VS project, b) manually creating a CAB using CABARC with a COM registration in INF and c) manually creating a CAB with launching msiexec. None of them worked. I even tried d) creating a bootstrapper which launches msiexec to no avail (because some people suggested simply launching msiexec on Vista can't work).
I am running Windows Vista but my project fails to run even on IE6 on XP.
When I install ActiveX using MSI, all is fine on ALL Windows. Apparently CAB thing is not working and I could not find a proper way to debug this whole process yet.
Any help is appreciated.
Update: Note that this old but excellent answer is still a very good outline for how to approach solving this problem, at least as along the evolutionary scale as Win7 and IE11. I just succeeded making it all work using the Answerer's Firebreath.org toolset as a jumping off point. It's not simple but it can be done. I've added a reference to that project to the reference list below since it may make a more logical jumping off point for current developers than this overview is.
Hooray - I have just finished an identical project, so you'll be pleased to know that it's actually possible. I have only tested this on XP - I understand there may be issues where Vista/7 don't allow msiexec to be called.
Given that you have an assembly correctly exposing a COM interface, I did the following:
Strong-named the assembly.
Created an INF file
Created an MSI using the Visual Studio 2008 "Setup Project" template.
Created a CAB file using "iexpress.exe" bundled with Windows XP.
Create INF file
The *.inf file I used looks like:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Setup Hooks]
install=install
[install]
run=msiexec.exe /package """%EXTRACT_DIR%\SampInst.msi""" /qn
The only bit you should need to change is the SampInst.msi. Note I would use an 8.3 filename, as long filenames can cause issues. While testing, I would not use the qn switch either, as that is a silent install.
Create the Installer
The installer has to do only one thing, and that is register the assembly by calling RegAsm on it. Most installers will provide some method to easily do this. For example, an installer created through VS 2008 will simply need to have the “Register” property of the assembly set to “vsdrpCOM”. Note that vsdrpCOM should be chosen as it generates the appropriate registry entries at build-time. The vsdrpCOMSelfRegistration setting is likely to fail as it calls RegAsm at run-time, and will thus not work for non-administrators.
Package the installer into a CAB file
This can be done by any cab archiver. Windows XP contains iexpress.exe, a wizard driven archiver, while Microsoft’s CAB SDK contains cabarc.exe. Other 3rd-party tools are also available.
Note that you will need to reserve space in the CAB file for code-signing if you are going to sign the CAB.
You will need to CAB the INF file, and the MSI file. You will not need to CAB the Setup.Exe file.
Handy hint: The VS2008 Setup Project project type allows you to set a post-build step in the properties, so you can build and CAB in a single step. My post-build step looks like:
cd "$(ProjectDir)"
"%WINDIR%\System32\Makecab.exe" /f "VboCslib.ddf"
The DDF file format is documented.
Sample HTML page
The object tag is used to point to the cab file containing the installer. A very simple HTML page which would deploy an ActiveXControl would be:
<html>
<head></head>
<body>
<!--
ID : The id of the ActiveX control to be used in JavaScript.
CLASSID : The GUID associated with the ActiveX control.
CODEBASE: The location containing the CAB installer for the ActiveX
control. This could be a URL, or a relative path.
-->
<OBJECT ID="MyActiveXControl"
CLASSID="CLSID:FC36FAE1-48E0-4f6b-B469-E1B5A8C6D1AC"
CODEBASE="cabfiles\SampleCabFile.CAB#version=1,0,0,0">
</OBJECT>
<script>
MyActiveXControl.SomeMethod();
</script>
</body>
</html>
Handy hints
Ensure your installer installs on a "per-user" basis, not a "per-machine" basis. This will make it more likely to install if the user does not have admin privileges.
Trouble-shooting
Internet Explorer 6 actually provides a really useful diagnostic aid. Clear your Temporary Internet Files, then navigate to the web-page. If the installation does not work, go to your temporary internet files and you will see a couple of files in there. One of these will be an error log starting ?CodeDownloadErrorLog. Drag it to your desktop and open it in notepad, and it will give details on what it was trying to do when it failed.
References
Microsoft KB247257 – Steps for signing a .cab file
MSDN – About INF File Architecture
SN.EXE - Code Strong Programs with Strong Names
Nikolkos Craft – How To: Deploy .NET ActiveX Control
CodeProject – Create ActiveX .NET Step by Step
CodeProject – Downloading C# ActiveX Components through CAB file
MSDN - ALLUSERS Property (Windows)
MSDN – Non-Admin ActiveX Controls
MSDN – Microsoft Cabinet Format
Update: Firebreath.org has a toolset for generating browser plugins for many platforms. The IE/ActiveX code to solve the problem posed here is just a subset. But as of 6 Nov 2014, I found it easier to start with Firebreath and its instructions than to try to build up my dev environment and roll all my own solutions from scratch.
I have a collection of ClickOnce packages in a publish folder on a network drive and need to move them all to another server (our DR machine).
After copy/pasting the whole directory and running the setups on the new machine I get an error message stating that it cannot find the old path:
Activation of
...MyClickOnceApp.application resulted
in exception. Following failure
messages were detected:
+ Downloading file://oldMachine/c$/MyClickOnceApp.application did not succeed.
+ Could not find a part of the path '\\oldMachine\c$\MyClickOnceApp.application'.
Once I change the installation URL to point at my new machine, I get another error:
Manifest XML signature is not valid.
+ The digital signature of the object did not verify.
I've tried using MageUI.exe, to modify the deployment URL, but it asks for a certificate, which I don't have.
What am I doing wrong and how do I successfully move published ClickOnce packages?
I found a solution:
Firstly, using MageUI, I changed the "Start Location" under "Deployment Options". On saving, it prompted me to sign with a key, which I created there and then. I then ran the setup.exe file, and it worked without fail.
After checking which files had changed, I realised it was only the one file: the application manifest file (myAppName.application). The only things that changed in the file were the deployment provider and the signature (which is what I changed in MageUI).
Once I realised this was how to do it, I used the command line version of MageUI called Mage.exe, which comes with the SDK.
Below is the batch file I created to do all of this on the command line:
REM Set the enviroment
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
REM Update the deployment provider URL
mage -Update %1.application -pu %2
REM Sign the manifest with our key
mage -Sign %1.application -CertFile C:\AppKey.pfx -Password myPw
I can now use this to run against all of my published applications in a quick and easy way. I hope this helps.
Without getting into too much detail, this should get you going.
ClickOnce manifests must be signed with a certificate for security reasons. You can purchase a code signing certificate or generate a test one. The main drawback of a test certificate is that your application publisher will appear as "Unknown" rather than your company's name.
In Visual Studio, open your project's properties and go to the "Signing" tab, select "Sign the ClickOnce manifests", and "Create Test Certificate". Next, click "More Details" to bring up a dialog and click "Install Certificate". This will run you through a wizard to get your test cert in your store. Make sure you put it in the "Personal" store.
Now you can use MageUI to edit your manifests. Any time you save it will prompt you to sign the manifests but you should now be able to select the test cert you just stored. Always edit/sign the application manifest before editing/signing the deployment manifest. This is confusing because the application manifest isn't the file with the .application extension.
Good luck!
I would expect to have to do the following:
Copy current folder contents to new location
For each app:-
Change 'Installation folder' to the new location
Publish as a new version
Change 'Publishing folder' to the new location
Publish as a new version
New setups run from the new folder should work and existing ones should update to look in the correct place.
All this is untested, but I'm pretty sure that's what I did previously...
Edit:
Obviously, you'll have to run these in parallel for a certain amount of time, but as it's an internal app the worst that will happen when you finally switch over to the new location is that you'll have to inform the user of the new location to obtain a 'fixed' app
I believe that you do have a certificate. You need one to create a ClickOnce deployment. Visual Studio may have autocreated a self-signed one for you. I'm not too familiar with the process, hopefully someone with a more definitive answer will chip in. Also, have you tried the MageUI tool, maybe it will be more obvious what you need to do using a GUI.