/build/static/layout/Breadcrumb_cap_w.png

Obtaining Context Information for Deferred Execution Custom Actions

Trying to find elegant an solution for the following "problem"
- Custom actions which run deferred as SYSTEM are not allowed to access the database tables. How to pass the information from immidiate to deferred.

Microsoft states that the context information should be passed by using the CustomActionData property, according to http://msdn2.microsoft.com/en-us/library/aa370543.aspx.
But lets say I've created a table with 1600 rows and I need to pass the information from immidiate to deferred, it's gonna be a huge property value to pass along. So I am wondering what ideas other people used to transfer information.
I figure I can put the information into the registry, or to a file. Registry seems a bit of a problem as well though, since you will have to write to the location under the privs. of the user. This means only HKCU would be a correct location, but then it will be hard to retrieve this information from a custom action running under deferred (SYSTEM).

I'm also interested in the idea behind this security. Why doesn't the Windows Installer allow a deferred custom action to check information from the database tables? I would be happy with a read only copy of the information contained in the database.

Please post your solutions.
Thanks in advance,

Frank Spierings

0 Comments   [ + ] Show comments

Answers (19)

Posted by: jmcfadyen 16 years ago
5th Degree Black Belt
2
i agree I am not sure what you are trying to do.

You could also attempt this as an immediate custom action but sequence it after the installfinalise action. this will mean that the main installation will be done allowing more access to the session object.

also there is actually two virtual scripts written

the actions between installinitialise and installfinalise are parsed once during the immediate phase. from this the first script is created.

If there is any deferred commit / rollback actions in the list then a 2nd script will be created. upon successful execution of the first "script" the second script will launch. after that is completed successfully the installation reverts back to immediate sequences which may be listed after installfinalise.

theres not alot of good doco ledgible doco on this.
Posted by: Inabus 16 years ago
Second Degree Green Belt
0
There is 1 property that can be used to pass data between the sequances, CustomActionData.

http://msdn2.microsoft.com/en-us/library/2w2fhwzz(VS.80).aspx

The above is the link to the Microsoft site on the property but I dont believe that there is ANY other way to do this outside of getting clever with VBScripts, for example write a file to the c:\ drive with the information in then read it out again with another VBScript.

Paul
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
Paul,

As mentioned in my first post, I understand that the CustomActionData property could/should be used for the passing of information. What I didn't know (and just read) is that when the class used inherits from ProjectInstaller data can be passed in a more object oriented way. But what I also understand is that this works only for .NET based Custom Actions.

Still, lets say I have this big table with all those rows of information, which I need during a deferred custom action. It is a pain to first fill the MSI db with all this information, then read the information from the db in a immidiate custom action and write it to "the CustomActionData property", after that use a deferred custom action that goes threw this huge property and changes the system accordingly.

Cheers for your quick reply btw.

Frank Spierings

Edit: I just noticed you edited your post...
Posted by: anonymous_9363 16 years ago
Red Belt
0
I haven't tried, but I *believe* the restriction which is imposed is running MSIExec.EXE, in which case you should be able to open the database in script, VB Script being the obvious candidate (mainly because of the plethora of code available.) If it were me, I'd try that first and, if you get errors opening the d/b, you could make a local copy of it (in, say, TEMP) and interrogate that.

My understanding is that the non-availability of properties is due to the fact that, once the engine has written its internal script, that script gets run in a separate process. You can see that easily using Task Manager: a single instance of MSIExec spawns a separate one (or more) as the installation progresses. You may well ask why MS doesn't follow its own documentation on inter-process communication but it would probably be more productive to vigorously engage your forehead with the nearest wall.
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
VBSCab,

I've been thinking about that method as well, to be honest. If I'm not mistaken the MSI will already be copied to the %TEMP% dir when installing.
Before I wanted to try the method you mention, I really wanted to know why this security is in place. But I think you give that a reasonable Microsoft ;) explanation.
It seems odd to me that a more priviliged process (the defered CA running under SYSTEM) is not allowed to retrieve the information it needs.
Also, about that internal script. Is there any influence you can have on it? For instance the placement of registry, which is handled by some internal functions in the Windows Installer service must write its entries to the internal script, and will then get executed by the newly spawned msiexec which runs the script. Would it be possible to generate the same kind of information but now for a custom action (I know this is a long shot ;). Note that I haven't noticed any API's for modifying the internal script, which also explains why its internal...
Posted by: anonymous_9363 16 years ago
Red Belt
0
There's no method *I know of* to get at that script. There has to be an API, of course, or how else would MSIExec use it? However, there's no real need to because you can set the script to do everything you need it to with your Custom Actions. Those, along with the standard actions, are "compiled" into the internal script. As for the placement of the actions, your authoring tool can take care of that or, if you're *really* feeling masochistic, use Orca [waits for "flames" from Orca-friendly posters...]

Good luck. Let us know how you got on.
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
Okay VBSCab,

I will not search any further in this case. We will just have to continue to work with the API's and options we have :)

I won't flame you for the masochistic bit ;) but I do believe that if you want something done correctly and fast and you know how to do it, use Orca. It's a hell of a lot quicker than my other "main" tool in editing the tables (which is InstallShield).
Posted by: anonymous_9363 16 years ago
Red Belt
0
That's cool, Frank. If you're happy using Orca, go ahead. As you say, it's quicker than either of the two main tools but, as one never knows the competence level of posters here until we either get to know folks or get told by them.

Happy hacking.
Posted by: jmcfadyen 16 years ago
5th Degree Black Belt
0
I'm also interested in the idea behind this security. Why doesn't the Windows Installer allow a deferred custom action to check information from the database tables? I would be happy with a read only copy of the information contained in the database.


Frank,

During the immediate phase a collection of actions is written into a script. Once the InstallFinalise action is reached the script is then executed. So one of the reasons is that you are not technically running the database at the time of the deferred phase you are actually executing a virtual script which was generated during the acquisition phase.

If you want read only access to the database you could try this

session.database.openview this can be accessed by vbs or NetFX
Posted by: jmcfadyen 16 years ago
5th Degree Black Belt
0
sorry i should be a little more specific.

set oView = session.database.openview("SELECT * FROM blah WHERE blah='item')

oview.Execute
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
VBScab,

No worries mate. Its always hard to figure out the competence level after one post of a person. I've been packaging for quite some time now and will try to post a bit more of my knowledge. I couldn't find too much information about this subject though, and figured this is the best way to get a bit of a community discussion to figure out a good / elegant solution to a somewhat more advanced problem.

Cheers for your help. I see you have quite some good posts on this board!


jmcfadyen,

Your solution provided will not work. The current Session object will not allow to open that database. It probably will be possible (as VBScab stated before) to connect to a copy of that database and then read it. Here is an example (for all others reading this topic).

[font="courier new"] Option Explicit
Dim objInstaller : Set objInstaller = CreateObject("WindowsInstaller.Installer")
Dim objDatabase: Set objDatabase = objInstaller.OpenDatabase("<PATH TO COPY OF MSI DB>",0)
Dim sql : sql = "SELECT * FROM MyTable"
Dim objView : Set objView = objDatabase.OpenView(sql)
objView.Execute
Dim objRecord : Set objRecord = objView.Fetch

So what your saying as well is that for the second phase of the installation (second instance of msiexec), only the internal script is known. The database is completely left out. Only the first instance, which creates the internal script, will have access to the database. Well that sounds logical. The only thing is, is that I understood from the MSDN documentation that this was some kind of security feature. But maybe I got that feeling because of the fact that you have to specify which properties to give to the second instance as well --> SecureCustomProperties.....

Thanks for your reply.
Posted by: AngelD 16 years ago
Red Belt
0
lets say I've created a table with 1600 rows and I need to pass the information from immidiate to deferred, it's gonna be a huge property value to pass along.
Why not describe what you actually want to do as I can't imagine that you want to fetch every row in a specific table for fun as you already would know the entries from a package you've developed or transformed.
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
Good morning AngelID and jmcfadyen,

Well at the moment I'm not trying to do anything. This thread is at the moment purely theoretical. I can see several purposes for reading multiple rows with information from the database tables though. The 1600 rows is just an exaggeration to show that I want to process more information than you would put normally in a string (like the CustomActionData property).
Microsoft states that immediate custom actions should not make any system changes. The changes should be made by deferred custom actions. But the deferred custom actions are not allowed to read the information from the tables.

An example of a purpose.
I want to specify several objects which will need specific permissions and the LockPermissions table does not have sufficient options to be usefull in the situation (need to modify inheritance for example). So now I want some custom action to check the tables for information and use this information to create the correct ACE's on the objects specified. The following options are now available to get this information in an immediate action, and then execute this information with a deferred custom action (as SYSTEM).

- Write the information of all the rows to the custom action property (CustomActionData), using my own delimitting structure.
-> This will result in a fairly large property value. Also I'm not happy with the delimitting that has to be done... Still, I have to say it would work though....

- Write the information to a file.
-> The file will have to be written to a location where the current user can write as well, since the action which creates the file is running under the same credentials. Therefore the information can not be trusted at deferred execution (as SYSTEM)

- Write the information to the registry
-> The file will have to be written to a location where the current user can write as well, since the action which creates the registry keys is running under the same credentials. Therefore the information can not be trusted at deferred execution (as SYSTEM)

- Read a copy of the database
-> If this database has been transformed by (a) MST('s) this will become harder, since these will have to be detected, copied and used to transform the temp database. It's still an option though.


Another useful option would be a new ServiceInstall (-> MyServiceInstall) table. With a custom action that goes through all the information and creates the necessary services (since MSI isn't supporting new Vista options, nor kernel or filesystem services).

I hope I clarifyed the situations in which I could use the information from the tables within a deferred custom action (as SYSTEM).

Thanks for the replies guys!
Posted by: AngelD 16 years ago
Red Belt
0
Hi Frank,

I would have an immediate custom action extracting the information you want to a file into a "support" folder (usually %TEMP%) from a standard or custom table, then execute a deferred CA and use the CustomActionData property to retrieve the (support). You would now be able to parse the file however you want for your specific tasks.

If you are gonna run some 3rd party tool for setting permissions I would store this in the binary table and then extract it to the "support" folder during immediate.

You could also during the immediate phase write a batch, vbscript, ... file or whatever you prefer to the folder which the deferred CA then just would have to execute instead of parsing the file just to have everthing in order before gonig to the deferred phase.

And as the last action author a "cleanup" CA to remove the folder and its content.
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
Hey AngelID,

That is a common way of handling it. There is a major security issue though. Since the user will be able to write to that same file in his or her %TEMP% directory. A user could modify the data. A result could be that the user modifies for instance that batch file you mentioned to say "net localgroup administrators /add user". I know that for some people this is not a big issue, for me it is though.

I do like the support custom action of InstallShield (finally something they got right ;)
Posted by: AngelD 16 years ago
Red Belt
0
I've never used InstallShield but hey we can relate to the support folder naming anyway [;)]
If you are worried about any user modifying the files then have a MD5 checksum check to verify that they are not altered in any way.
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
Ahh that MD5 checksum is a good idea!
Posted by: FrankSpierings 16 years ago
Orange Senior Belt
0
Stumbling along the Windows Installer SDK documentation I just noticed I should try to read more carefully in the future.

http://msdn2.microsoft.com/en-gb/library/aa368268.aspx
[hr]Because the installation script can be executed outside of the installation session in which it was written, the session may no longer exist during execution of the installation script. This means that the original session handle and property data set during the installation sequence is not available to a deferred execution custom action. Deferred custom actions that call dynamic-link libraries (DLLs) pass a handle which can only be used to obtain a very limited amount of information, as described in Obtaining Context Information for Deferred Execution Custom Actions.
[hr]
So VBSCab and jmcfadyen where correct about why the database is unavailable at deferred execution. Nevertheless I still think Microsoft could have given access to a read-only copy of the database. This would greatly improve the functionality IMHO.

Another item is the internal script (written to %WinDir%\Installer\MSI[generated nr].tmp). This script can be viewed with the SDK sample WiLstScr.vbs. It seems to be in a sort of MSI db format. Writing to this script directly does not seem a good idea currently.

Sorry guys, I'll try to read more carefully
Posted by: dreyer 14 years ago
Purple Belt
0
ORIGINAL: jmcfadyen
You could also attempt this as an immediate custom action but sequence it after the installfinalise action. this will mean that the main installation will be done allowing more access to the session object.


[EXPLETIVE] BRILLIANT! Thank you!
Rating comments in this legacy AppDeploy message board thread won't reorder them,
so that the conversation will remain readable.
 
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ