How to change ProductCode using Microsoft.Deployment.WindowsInstaller? - wix

In a deployment scenario we had the idea to allow an administrator to change properties in a installer and the ProductCode. The administrator should then push out the newer msi using a GPO policy. Since this now would be a MajorUpgrade the old version, with the old properties, should be uninstalled and the new one, with the new properties, should be installed.
However updating the ProductCode doesn't work.
When executing
db.Execute("UPDATE Property SET Value = '{30571D61-8994-449B-9725-90760DFE0467}' WHERE Property = 'ProductCode'")
an exception is thrown.
[Microsoft.Deployment.WindowsInstaller.InstallerException] = {"Function failed during execution. Database: C:\..\MyInstaller.msi Table(s) Update failed."}
What should I do to upgrade the ProductCode?
(Is it even possible?)
Edit:
If the table is opened as ReadOnly, it will show error.
Which was the case here.

The SDK documentation states that ExecuteScalar can only be used for a SELECT statement that returns a single result. Instead you should use the Execute method.
using (Database database = new Database(#"C:\MSM\ISWIX.MSI", DatabaseOpenMode.Direct))
{
database.Execute("UPDATE Property SET Value = '{00000000-0000-0000-0000-000000000000}' WHERE Property = 'ProductCode'");
}
Also realize this cannot be done as a custom action during the installation as ProductCode is immutable. Typically in a MajorUpgrade scenario you assign a new ProductCode at build/compile time.

Related

adding new document to CouchDb using ArmChair throws exception Object reference not set to an instance of an object

Iam using couch-db version 2.2.0
and I want to make crud operations on couchdb database using .Net
so I installed Armchair.Core Nuget Package version 0.11.2
and in order to add d a new document I, followed the code that is mentioned in
not finished wiki yet
https://bitbucket.org/dboneslabs/arm-chair/wiki/main-api/session-api.md
Database mydatabase = new Database("TestDb",newConnection("http://localhost:5984"));
using (var session = mydatabase.CreateSession())
{
var author = new Person("Jone");
session.Add(author);// NOTE: If no Id has been assigned before the instance is added to the Session, then ArmChair will assign it. After the object is committed to the database, the revision will then be set onto the instance
session.Commit();
}
but I still getting the error
Object reference not set to an instance of an object.
also mydatabase variable mentioned in previous code has values null for Connection and DataBase Parameters even though i passed them in the constructor as it doesn't connect to couchdb database at all and never tries to create database TestDb
any help please ,are there any wrong calls in my code
ArmChair connects to an existing database and does not create one.
if you want to create a database, have a look a look at the sample application, in the Autofac registration there is a method which ensures that there is a database created.
https://bitbucket.org/dboneslabs/arm-chair/src/bd4e70d6c51d8b45cfb89eb65ecf81a4ecefb691/samples/todo/Todo.Service/Infrastructure/Modules/DataAccessModule.cs#lines-62
its not the pretty-est of code but works.

Wix DTF Custom Action Equivalent of WcaAddTempRecord

I am trying to use Wix DTF custom action to write MSI runtime session values to registry.
This i wanted to achieve by adding temporary record to "Registry" table in the database.
Since c++ had a WcaAddTempRecord method to achieve this, really wanted to know is there any equivalent method in DTF.
Note: I tried using Session.Database.OpenView to insert the record, but consistently i am getting update failed error, due to session database readonly property.
Can someone please suggest the best approach for this situation?
The MSI database is read-only during the installation. So you cannot add permanent rows. However, you can insert temporary rows. Once you get the View back from the Session.Database.OpenView() then use the InsertTemporary() method on the View object to add temporary rows.
That's how WcaAddTempRecord() gets the Temp in its name. :)
This is my "go to" helper method:
private static void InsertTempRecord(Session session, string tableName, Object[] objects)
{
Database db = session.Database;
string sqlInsertSring = db.Tables[tableName].SqlInsertString + " TEMPORARY";
session.Log("SqlInsertString is {0}", sqlInsertSring);
View view = db.OpenView(sqlInsertSring);
view.Execute(new Record(objects));
view.Close();
}
For more information see:
Dynamic Windows Installer UI

Wix: Cannot list out properties created using C# custom action

I am creating a wix installer. In some of the wxs file i have defined some properties and i am also creating some session properties inside C# custom action.
Now my requirement is to list out all session properties.
So for this i have queried Property table and got all properties that where defined in .wxs file.
For this i have used below custom action:
Microsoft.Deployment.WindowsInstaller.View listBoxView = session.Database.OpenView(string.Format("select * from Property"));
listBoxView.Execute();
while (true)
{
using (Record r = listBoxView.Fetch())
{
if (r == null)
{
break;
}
else
{
Console.WriteLine(r[1].ToString(), r[2].ToString());
}
}
}
}
}
But it does not list out any session property that i have created using c# custom action.
Can someone help me how to list out properties that i created using c# custom action or where these properties get stored?
Thanks much
When you query the property table the way you do in your sample, you get only those properties defined statically in your WiX authoring, and this is expected. At install-time there's a concept called in-memory property collection - this consists out of all the properties defined in various ways: statically in Property table, provided via the command-line, system, defined in custom actions, etc.
You can access all those properties via the Session object. Just call session[name], where name is the name of the property you're going to get. I doubt there's an enumerator defined for properties, but in real life you rarely need to iterate the properties - you rather try to get a certain one.
Workaround if you REALLY need to enumerate it (requires MSI 4.0 or newer):
Add full logging in the project
<Property Id="MsiLogging" Value="Iwearucmopvx" />
This will log the entire installation process to your %TEMP% folder.
Then get the logfile location with:
var logFile = session["MsiLogFileLocation"];
Since the logfile is locked by the MSI logging you will have to access it in shared mode:
new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
Read it and get the latest in-memory PROPERTY values by searching out the lines beginning with "PROPERTY CHANGE:".
MSI (c) (90:78) [21:07:16:108]: PROPERTY CHANGE: Adding MsiRunningElevated property. Its value is '1'.
MSI (c) (90:78) [21:07:16:108]: PROPERTY CHANGE: Adding Privileged property. Its value is '1'.
MSI (c) (90:78) [21:07:16:108]: Note: 1: 1402 2: HKEY_CURRENT_USER\Software\Microsoft\MS Setup (ACME)\User Info 3: 2
MSI (c) (90:78) [21:07:16:108]: PROPERTY CHANGE: Adding USERNAME property. Its value is 'Employee'.
MSI (c) (90:78) [21:07:16:108]: Note: 1: 1402 2: HKEY_CURRENT_USER\Software\Microsoft\MS Setup (ACME)\User Info 3: 2
MSI (c) (90!A8) [21:07:30:900]: PROPERTY CHANGE: Modifying WEB_APP_NAME property. Its current value is '$projectname$/v1.0.0'. Its new value: '$projectname$\v1.0.0'.
MSI (c) (90!A8) [21:07:30:901]: PROPERTY CHANGE: Adding WEB_APP_NAME_NORMAL property. Its value is '$projectname$/v1.0.0'.
MSI (c) (90!A8) [21:07:30:901]: PROPERTY CHANGE: Adding WEB_APP_NAME_LAST property. Its value is 'v1.0.0'.
The drawback is that there will always be a log in the %TEMP% folder left over. Maybe add some cleaning up or something.

Sharepoint Feature Upgrades

I have the following in my feature.template.xml
...
<VersionRange BeginVersion="1.0.0.1" EndVersion="1.0.0.2">
<CustomUpgradeAction Name="1.0.0.1_TO_1.0.0.2"></CustomUpgradeAction>
</VersionRange>
<VersionRange BeginVersion="1.0.0.2" EndVersion="1.0.0.3">
<CustomUpgradeAction Name="1.0.0.2_TO_1.0.0.3"></CustomUpgradeAction>
</VersionRange>
...
My feature upgrade event is as follows:
public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
{
using (SPSite site = (SPSite)properties.Feature.Parent)
using (SPWeb mySite = site.RootWeb)
{
switch (upgradeActionName)
{
case "1.0.0.1_TO_1.0.0.2":
//execute logicA
break;
case "1.0.0.2_TO_1.0.0.3":
//execute logicB
break;
default:
break;
}
}
Am I correct in saying that if the site is currently version 1.0.0.0, it will be upgraded to v 1.0.03, executing both logicA and logicB above. This means that sharepoint would call featureupgrading event for each version upgrade.Is this correct? Or do I need to do something different to achieve this?
I also have the following concerns:
What exactly do the the BeginVersion and EndVersion mean.
I especially do not understand the BeginVersion. What happens if instead of 1.0.0.2 I set it to 1.0.0.1 as well?
Any assistance would be greately appreciated, as I did not find any good relevant details online or on books.
When you add a new Feature to your VS SharePoint project, Visual studio initializes your Feature with version 0.0.0.0.
In the properties window you can set a version number for your feature.
When you want to upgrade an existing feature you'll have to define the range of versions for which you want your upgrade actions (code, new manifest, ...) to happen.
E.g.: You deployed your feature without changing the version number. Your current deployed feature has version number 0.0.0.0.
You want to upgrade your feature and set the version number to 2.0.0.0.
If you define a versionrange as follows:
<VersionRange BeginVersion="1.0.0.0" EndVersion="2.0.0.0">
You'll notice nothing will happen when you call SPFeature.Upgrade() since 0.0.0.0 is not in the defined versionrange.
If you use this versionrange
<VersionRange EndVersion="2.0.0.0">
or
<VersionRange BeginVersion="0.0.0.0" EndVersion="2.0.0.0">
You'll notice your FeatureUpgrading eventreceiver or other upgrade actions will be triggered.
Your upgraded feature will now have version number 2.0.0.0.
If you call SPFeature.Upgrade again nothing will happen again, because 2.0.0.0 exceeds the defined versionrange. So BeginVersion is included, EndVersion not.
Every feature with a version number between [0.0.0.0 - 1.x.x.x] will be upgraded if you use the latter versionranges.
I think you can also leave the BeginVersion and EndVersion attributes entirely out. Then you're upgradeactions will be triggered at every SPFeature.Upgrade() call. (To be verified)
For more information: Chris O'Brien wrote an interesting articles series about this topic, cfr. http://www.sharepointnutsandbolts.com/2010/06/feature-upgrade-part-1-fundamentals.html

Forcing a TFS checkin of a file via C#

How can I specify that I ALWAYS want the local file to replace the server copy even if the TFS copy is newer?
if (pendingChanges.GetUpperBound(0)>-1)
ChangeSetNumber = workspace.CheckIn(pendingChanges, filename);
I can see from the intelisense that I can specify checkinoptions as a parameter of the CheckIn method, I just cannot find what I need to put in to have it always check in and ignore any conflict I might come up with.
Thanks in advance.
EDIT: I found a command TF RESOLVE "item" /auto:AcceptYours /recursive So I guess my revised question would be is there a programming equivalent to the /auto:AcceptYours switch?
NecroEDIT: process the conflicts before doing the checkin
Conflict[] conflicts = workspace.QueryConflicts(new string[] { TFSProject }, true);
foreach (Conflict conflict in conflicts)
{
conflict.Resolution = Resolution.AcceptTheirs;
workspace.ResolveConflict(conflict);
}
Checkins are atomic - either they all succeed or they all fail. If there are any conflicts that need to be resolved before the check in, the check in operation will throw an exception. (Documentation)
You have to evaluate checkin for conflicts and then resolve the CheckinConflicts by Workspace.ResolveConflict Method.
ResolveConflict expects CheckinConflict, and result of the EvaluateCheckin (which is CheckinEvaluationResult) includes CheckinConflicts.
This page may help.
Note: checkinoptions is not related with what you are asking.
Hope this helps.