Unable to delete deployed file during installation with WIX installer - permissions

In our WIX installer project, we need to generate a new file, let's call it FileB, based on a deployed file, called FileA in a managed custom action function. In another word, in the component declaration, I declare the FileA. While in a custom action (which happens at commit phase), I need to generate FileB based on FileA. After that, since FileA is no use anymore, I want to delete it in the same custom action.
And here comes the problem: with the default installation folder, which is Program Files, the normal user is not allowed to add file (generate FileB) into this folder in the custom action (I am not 100% sure I am right, but it is the case in my test. And if I install it in another folder, there is no problem at all). So I think I need to give permission of creating file. In order to do that, I add a CreateFolder element to the component which includs FileA. The whole component declaration is something like this:
<Component Id='COMPONENT_NAME' Guid='MY_GUID'>
<!--OTHER FILES IN THE COMPONENT-->
...
<CreateFolder Directory='INSTALLDIR'>
<Permission CreateFile='yes' User='Everyone' GenericAll='yes' Delete='yes'/>
</CreateFolder>
<File Id='MyFileA' Name='FileA' Source='PATH_TO_FILEA' KeyPath='no' >
<Permission GenericAll='yes' User='Everyone' Delete='yes'/>
</File>
</Component>
The component actually belongs to a component group, which resides in INSTALLDIR. The reason there is other files in the same component element is because I want another File to be the keypath, so that deleting FileA would not cause a problem of that. And now the generation of FileB is working fine. But later in the same custom action, I am experiencing the problem when deleting FileA. It just says that ": Access to the path 'DEPLOYMENT_PATH_TO_FILEA' is denied." I thought the problem lies in the FileA declaration, that's why I added the Delete='yes' in the Permission element under File, hoping to make it OK to delete it (although I am not sure whether this means in the installation it is possible to delete). But still I get this error. Can anyone tell me what I did wrong?
Another question is, I really don't know what is the purpose of those CreatFolder elements. For one thing: if the aim is to create the directory structure, I think the (nested)Directory elements already do that. And why to have such element under Component element when most of the time you probably want the directory structure to be separated with component structure(the components just use directory reference to refer to correct directory). Secondly, the default Directory property of CreateFolder is the parent Directory where the component resides in. But it is common that more than one components reside in the same directory, like what I have here: multiple components are in the same component group, whose directory element references to INSTALLDIR. So only one of these components has the CreateFolder element, whose Directory property in my case is the parent directory of all those components. It is really hard to understand this structure. I guess I have some misunderstanding of the CreateFolder element. Can someone enlighten me to usage of CreateFolder? Thanks!
Thanks!

A number of issues to address here. First, you should know that Commit phase custom actions don't execute if rollback is disabled. You should really have an deferred and rollback custom action.
Second, you can't tell MSI to install a file and then go delete it. That's counterproductive and just causes servicing issues down the road. A better solution ( I'm assuming you are using a WiX DTF managed custom action ) is to include FileA as a content item in the custom action project. This will cause the file to exist in the current (temp) directory of the custom action while it execute. You can then generate fileb. For rollback, you can delete fileb.
You'll also need to author a RemoveFile element to teach MSI to delete the file on uninstall. Otherwise it won't since MSI doesn't know anything about fileb created by your out of process custom action.
Otherwise it'd be useful to know what the contents of fileb are. It would be easier to implement if this was an xml file that could be installed as fileb and then transformed using the xml wix extension.

Related

How to create a DNN widget?

If I understood correctly, DNN widget is a way to add a js to every page on the website using module or theme. Right?
My goal evantually is to add a js to every page on a portal and preferably to do that via module that has no need to be added to every page manually.
My plan B is adding module and using setting "Display Module on All Pages", but widget seems to be a better way to do that.
At first I've tried to use this instruction. I've added the YourCompany.Widgets.SampleWidget.js file to root of existing DNN module. Also in the .dnn manifest file inside components tag I've added another component like this:
<component type="Widget">
<widgetFiles>
<basePath>YourCompany</basePath>
<widgetFile>
<name>YourCompany.Widgets.SampleWidget.js</name>
</widgetFile>
<widgetFile>
<name>license.txt</name>
</widgetFile>
<widgetFile>
<name>releasenotes.txt</name>
</widgetFile>
</widgetFiles>
</component>
I've got this error on module installation:
Failure File specified in the dnn could not be found in the zip file: - D:\Projects\website.com.ua\Host\Install\Temp\vp1vioj1\YourCompany.Widgets.SampleWidget.js
vp1vioj1 part is changing every time (seems like it's some unique id that is generating on module install).
Then I tried to place this widget component inside another package tag after checking this article. Like this:
<dotnetnuke type="Package" version="5.0">
<packages>
<package name="ModuleName" type="Module" version="00.00.01">
<!-- some module content here -->
</package>
<package name="YourCompany.SampleWidget" type="Widget" version="00.00.01">
<components>
<component type="Widget">
<widgetFiles>
<basePath>YourCompany</basePath>
<widgetFile>
<name>YourCompany.Widgets.SampleWidget.js</name>
</widgetFile>
</widgetFiles>
</component>
</components>
</package>
</packages>
</dotnetnuke>
But I still got the same error on install. I didn't find any other instructions or documentations regarding widgets. When I tried to check the DNN source code - it seems to be also very time consuming and hard way.
So could you please help me to clarify this?
Support for Widgets in DNN Platformnwas dropped a number of years ago.
Your best option if you want something ok all pages would either be to look at a SkinObject, like the breadcrumb or Login for example. Or a traditional module but marking it “display on all pages”
First, you might want to take a look at the concept of DNN Extensions and how they are built and packaged.
If examples of versions DNN extensions, https://github.com/WillStrohl/dnnextensions. The examples include a widget. So check it out.
Now, what you posted looks like a .dnn file, which the the manifest file that is intended to be a part of a packaged DNN extension. Code and other bits and pieces go into the packaged extension (really a specially named zip file). The packaged extension is installed into your DNN installation via the Extensions Persona Bar page (click the Install Extension there).
From my experience with DNN (2006 to now), I believe that I can say that a DNN Widget is something that I've never had anything to do with. So, you may be barking up an old any dying tree in the project.
If you want something included on every page, it makes more sense to include it in the theme (skin). If you want a javascript file, add that to your theme project and have the .ascx files include it, probably using https://docs.dnncommunity.org/api/DotNetNuke.Web.Client.ClientResourceManagement.html (see https://docs.dnncommunity.org/api/DotNetNuke.Web.Client.ClientResourceManagement.html)
But, if you are determined to use a widget, start with https://www.kalyani.com/blog/2009/12/25/dotnetnuke-widgets-guide-part-1-of-4/

How to set custom value to Wix Bundle Log Element?

If I put a hard-coded value it works fine
<Log PathVariable="C:\myProjectDir\myLogs\log.txt"/>
 
But if I make a separate variable and replace the hard-code, it does NOT work
<Log PathVariable="[LogLocation]"/>
<Variable Name="LogLocation" bal:Overridable="no" Type="string" Value="C:\myProjectDir\myLogs\log.txt" Persisted="yes"/>
 
I found something on the lines of <WixVariable Id="WixBundleLog"/> but I don't really know how to use it.
My end goal here is that I have a bootstrapper application and I want to change the location where logs of my msi and exe installation is created
I able able to change a Variable element value using _bootstrapper.Engine.StringVariables["LogLocation"] = "C:\ProjectGorilla\logs\log.txt"
Using the above code in C#, the Variable Id="LogLocation" is changed but that change is not reflected in Log element's PathVariable
So, my question is how can I put a variable in PathVariable attribute of Log element
Thanks in advance :)
According to the documentation, the PathVariable attribute is:
Name of a Variable that will hold the path to the log file. An empty value will cause the variable to not be set. The default is "WixBundleLog".
PathVariable does not specify the path where the (bundle) log will be written. It is a variable that the BA is supposed to read if it wants to copy the file somewhere else. The Burn engine never reads this variable's value so changing it during runtime won't do anything.
The (bundle) log is created (https://github.com/wixtoolset/wix3/blob/58abd6993afba08b39e37b0e76b1790161df9231/src/burn/engine/engine.cpp#L499) before loading the BootstrapperApplication (https://github.com/wixtoolset/wix3/blob/58abd6993afba08b39e37b0e76b1790161df9231/src/burn/engine/engine.cpp#L545). There is no way for the BA to change the path.
The package (MSI, EXE, etc) log locations work the same way today as the bundle log. However since they are created after loading the BA, it's theoretically possible that someone could implement a feature so that the BA can change their path.

Creating Element as first item within another element using Wxs (Windows Installer)

I am using Wix installer for an application and one of the scenarios I am trying to handle is changes to a .config file when the application is upgraded.
Essentially, I would want to add an Xml Element within another Xml Element.
For instance, the original .config file that was shipped with application looked like this
<root-element>
<sub-element-1/>
<sub-element-2/>
</root-element>
During app lifetime, it was updated to as below at some point.
<root-element>
<sub-element-0/>
<sub-element-1/>
<sub-element-2/>
</root-element>
For handling this case , where I need to add <sub-element-0/> under <root-element>, I tried this Wxs code.
<util:XmlFile Id="MyConfig"
File="[fileidOfMyConfigFile]"
Action="createElement"
Name="sub-element-0"
ElementPath="root-element"
Sequence="1"/>
The above formulation does add the sub-element-0 under root-element , however as the last item under the root-element.
like so
<root-element>
<sub-element-1/>
<sub-element-2/>
<sub-element-0/>
</root-element>
I couldn't find any resources on adding it as first element as I want it to be.
Any suggestions on how it could be accomplished?
Note: The above is a simplified version of my use case. The reason order is important in my case is due to a limitation on the framework that some elements need to occur before other elements in the .config

WiX: returning a value from exepackage

I have been asked to add a function to an existing WiX package.
Specifically, I need to run a small c# application and return a single int back to WiX to conditionally control further actions.
I can see from ExePackage help that there is an ExitCode, but this is an enumeration of success, error, scheduleReboot or forceReboot.
I have googled quite a bit and I am wondering if I am missing the point. I can probably implement the C# process internally within WiX to get the user to provide the information I need, but the existing package already has custom ExePackages written in C# with a particular style, so I'd like to stay with that if I can. (The existing packages don't return any needed values)
Can I do this, or do I need to try and operate entirely within WiX?
For reference, one of the existing packages looks like this:
<ExePackage
SourceFile="..."
DisplayName="License Key"
InstallSize="0"
Permanent="yes"
InstallCommand="/ignoreIfLicensed"
RepairCommand="/ignore"
UninstallCommand="/ignore"
/>
The reference to <ExePackage ...> implies you want the condition to operate in a WIX bundle. In this scenario I think your options are limited and you can only map the return value of an ExePackage to global behaviour like forceReboot.
Do you have any <MsiPackage...> references? If you have, you could move the conditional behaviour inside each <MsiPackage...> using a Custom Action to call the exe and set a property. The property can then be used as a condition in each <component...> you want to conditionally install. See Using a WiX custom action to set a property's value for more information on custom actions setting properties.

Splitting up a WIX file

So I thought it'd be clever of me to split my WIX file up into various smaller files. I did this for a couple reasons. One being that it would make it easier to maintain. Anyway, regardless of my reason, I put the components in one file. But when I compile, I now get a warning that says:
warning LGHT1079: The cabinet 'media1.cab' does not contain any files. If this installation contains no files, this warning can likely be safely ignored. Otherwise, please add files to the cabinet or remove it.
Now the Media element is in the main wix file and all of my File components have a DiskId that matches. So I thought I'd just stick the Media element in the same fragments as where I define my components. No dice. I get a warning that says that the installer has no media.
So do I have to define all of my components in the same file? Or am I missing something?
I figured out what I did wrong. I also put the features in a separate file. I needed to add a FeatureRef tag for each feature within the product tag.
Your Feature elements will need ComponentRef or ComponentGroupRef elements to associate the components to the features.