What happens if a rollback custom action fails? - wix

What happens if a rollback custom action fails? Do I need to specify a Return attribute in Wix CustomAction element for a rollback custom action?
I did a quick test. I created a binary custom action:
This is a C++ code:
UINT __stdcall ForceInstallFailure(MSIHANDLE hModule)
{
return ERROR_INSTALL_FAILURE;
}
A Wix code:
<CustomAction Id="CA_ForceInstallFailure" BinaryKey="Bin_CAInst"
DllEntry="ForceInstallFailure"
Execute="rollback" Return="check" Impersonate="no" />
Wix translated it into type 3329:
Type 1 (DLL generated from a binary stream called through an entry point) +
3328 (msidbCustomActionTypeInScript + msidbCustomActionTypeNoImpersonate + msidbCustomActionTypeRollback)
I simulated a rollback with https://wixtoolset.org/docs/v3/customactions/wixfailwhendeferred/
This is what I get in MSI log:
Rollback: CA_ForceInstallFailure
MSI (s) (90:B4) [02:18:54:053]: Executing op: ActionStart(Name=CA_ForceInstallFailure,,)
MSI (s) (90:B4) [02:18:54:053]: Executing op: CustomActionRollback(Action=CA_ForceInstallFailure,ActionType=3329,Source=BinaryData,Target=ForceInstallFailure,)
MSI (s) (90:14) [02:18:54:053]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIC523.tmp, Entrypoint: ForceInstallFailure
CustomAction CA_ForceInstallFailure returned actual error code 1603 but will be translated to success due to continue marking
It looks like Windows Installer doesn't check a custom action return value during a rollback, even though I didn't mark it specifically as Return="ignore" which would translate to msidbCustomActionTypeContinue addition.
Although it logically seems the correct behavior, I could not find any official documentation that describes this.

The Windows Installer does not have rollback for rollback, so it ignores custom action failures during rollback.

Related

ApplicationInsights dotnet core custom initializer

I'm unable to figure out how to configure AI for aspnetcore project. I've done the following:
services.AddSingleton<ITelemetryInitializer, AppInsightsInitializer>();
services.AddApplicationInsightsTelemetry(Configuration);
Where I need the loggedin user and the servicename so I've got this initializer:
public class AppInsightsInitializer : ITelemetryInitializer
{
private IHttpContextAccessor _httpContextAccessor;
public AppInsightsInitializer(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException("httpContextAccessor");
}
public void Initialize(ITelemetry telemetry)
{
var httpContext = _httpContextAccessor.HttpContext;
telemetry.Context.Properties["appname"] = "MyCoolService";
if (httpContext != null && httpContext.User.Identity.IsAuthenticated == true && httpContext.User.Identity.Name != null)
{
telemetry.Context.User.AuthenticatedUserId = httpContext.User.Identity.Name;
}
}
}
I've got no applicationinights.config file (I understand they are not needed)
Problem: I got 4 entries of each log (same id). The data is correct. I also got the following errror in the logs:
AI: Error collecting 9 of the configured performance counters. Please check the configuration. Counter \Process(??APP_WIN32_PROC??)\% Processor Time: Failed to perform the first read for performance counter. Please make sure it exists.
Category: Process, counter: % Processor Time, instance Counter \Memory\Available Bytes: Failed to register performance counter.
Category: Memory, counter: Available Bytes, instance: .
Counter \ASP.NET Applications(??APP_W3SVC_PROC??)\Requests/Sec: Failed to perform the first read for performance counter. Please make sure it exists.
Category: ASP.NET Applications, counter: Requests/Sec, instance MyCoolv3.Api.exe Counter \.NET CLR Exceptions(??APP_CLR_PROC??)\# of Exceps Thrown / sec: Failed to perform the first read for performance counter. Please make sure it exists.
Category: .NET CLR Exceptions, counter: # of Exceps Thrown / sec, instance Counter \ASP.NET Applications(??APP_W3SVC_PROC??)\Request Execution Time: Failed to perform the first read for performance counter. Please make sure it exists.
Category: ASP.NET Applications, counter: Request Execution Time, instance MyCoolv3.Api.exe Counter \Process(??APP_WIN32_PROC??)\Private Bytes: Failed to perform the first read for performance counter. Please make sure it exists. Category: Process, counter: Private Bytes, instance Counter \Process(??APP_WIN32_PROC??)\IO Data Bytes/sec: Failed to perform the first read for performance counter. Please make sure it exists.
Category: Process, counter: IO Data Bytes/sec, instance Counter \ASP.NET Applications(??APP_W3SVC_PROC??)\Requests In Application Queue: Failed to perform the first read for performance counter. Please make sure it exists. Category: ASP.NET Applications, counter: Requests In Application Queue, instance MyCoolv3.Api.exe
Counter \Processor(_Total)\% Processor Time: Failed to register performance counter. Category: Processor, counter: % Processor Time, instance: _Total.
I'm using:
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.1.0-beta1" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
services.AddApplicationInsightsTelemetry(Configuration);
isn't needed anymore (hypothetically, you should even be getting deprecation warnings on that line?)
if you create a asp.net core new project in VS2017, AI will already be there in package references (though the 2.0 version, not that 2.1 beta version), and all of the wireup would already be done in program.cs and in some other files.
If you're porting an existing one, then instead of the above AddApplicationInsights... line, instead you'd have
.UseApplicationInsights()
in your program.cs startup of your app instead. for more details, there's some info about this in the 2.1 beta release notes on github
We're also working on updating the "configure application insights" tools in VS2017 to properly "migrate" apps like this in a future update.
I'm not sure why you'd get multiple instances of any events unless you're explicitly logging them, or if you possibly have multiple calls to startup (which also shouldn't affect anything). Where are are you seeing multiple instances? in VS's appinsights tools? in the portal?

Why is CostFinalize modifying my custom property in one install and not the other?

I have two installs with virtually identical code. I set a custom property like this:
<SetProperty Id="MYCONFIGPATH" Value="[CONFIGPATH]" Before="CostInitialize"/>
And then reference that property in a component:
<Component Id="CopyConfigFromConfigPath" Guid="{XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" MultiInstance="yes">
<Condition>CONFIGPATH</Condition>
<CopyFile SourceProperty="MYCONFIGPATH" DestinationDirectory="ConfigBOR" DestinationName="ConfigBOR.xml" Id="CopyConfigBOR" />
</Component>
I'm not certain this is what's causing the failure to copy this file but I suspect it is:
MSI (s) (64:6C) [14:03:42:383]: PROPERTY CHANGE: Modifying MYCONFIGPATH property. Its current value is 'C:\Installs\ConfigBOR.xml'. Its new value: 'C:\Installs\ConfigBOR.xml\'.
Notice the trailing backslash. This happens shortly after starting CostFinalize. Just above that log entry are some suspicious looking entries but I can't figure out what they mean so I'm not sure they're relevant:
MSI (s) (64:6C) [14:03:42:380]: Doing action: CostFinalize
MSI (s) (64:6C) [14:03:42:380]: Note: 1: 2205 2: 3: ActionText
and
MSI (s) (64:6C) [14:03:42:382]: Note: 1: 2205 2: 3: Patch
MSI (s) (64:6C) [14:03:42:383]: Note: 1: 2205 2: 3: Condition
I have identical code in another installer (BOR is replaced with the product name in that one) but it doesn't modify this property and does correctly copy this file. Why doesn't it work here?
I don't think your question provides enough information to answer this for certain, but my psychic powers tell me that MYCONFIGPATH is in the Directory table in one package but not in the other. Thus the directory resolution phase of CostFinalize affects the two packages differently.
C:\Installs\ConfigBOR.xml did not exist. I guess WIX picked up on that and, instead of throwing an error, decided to check if a directory with that name were present.

Too Many Events Using DTF InstallLogModes

I'm currently logging "everything" using the following flags:
const DTF.InstallLogModes logEverything = DTF.InstallLogModes.FatalExit |
DTF.InstallLogModes.Error |
DTF.InstallLogModes.Warning |
DTF.InstallLogModes.User |
DTF.InstallLogModes.Info |
DTF.InstallLogModes.ResolveSource |
DTF.InstallLogModes.OutOfDiskSpace |
DTF.InstallLogModes.ActionStart |
DTF.InstallLogModes.ActionData |
DTF.InstallLogModes.CommonData |
DTF.InstallLogModes.Progress |
DTF.InstallLogModes.Initialize |
DTF.InstallLogModes.Terminate |
DTF.InstallLogModes.ShowDialog;
DTF.Installer.SetInternalUI(DTF.InstallUIOptions.Silent);
var handler = new DTF.ExternalUIRecordHandler(ProcessMessage);
DTF.Installer.SetExternalUI(handler, logEverything);
DTF.Installer.EnableLog(logEverything, logPath, true, true);
DTF.Installer.InstallProduct(installerPath, commandLine);
This has the effect of writing an enormous number of events to the log file.
For example, I'm seeing thousands of these:
MSI (s) (14:A0) [11:33:50:764]: Component: comp_27E5179987044690962CE98B3F95FD72; Installed: Local; Request: Null; Action: Null; Client State: Local
MSI (c) (4C:8C) [11:34:17:869]: Creating MSIHANDLE (592) of type 790531 for thread 8076
MSI (c) (4C:8C) [11:34:17:893]: Closing MSIHANDLE (592) of type 790531 for thread 8076
How do I disable those extremely verbose messages in the log? I need to keep the Progress events.
If you don't want them, don't set the bts in the API call. Just set progress. However, you do need to get hold of the error messages and warnings to display them.
However....what's your goal here? You don't need to re-invent the logging that you can get in other ways. The purpose of using that external UI call API is that you are now in charge of all the UI for the install. This isn't really about logging, it's about you being responsible for the UI, and a standard install will typically show all those messages in one form or another. For example, along with progress messages you get action messages that says what's going on (file name being copied, etc). If that is an actual product that you are installing, then you really need to show error messages, files in use dialogs, warnings, or you're simply hiding everything that goes on.
Link to underlying AP docs: https://msdn.microsoft.com/en-us/library/aa370573(v=vs.85).aspx

Can't run a managed custom action on uninstall

I have a custom action which should be run on uninstall. But for unknown reason the msiexec says "There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor.". The code goes below:
<Binary SourceFile="SetupWiX.CA.dll" Id="Binary1" />
<CustomAction Id="DropDatabase" BinaryKey="Binary1" DllEntry="DropDatabase" Execute="deferred" Return="check"/>
<Custom Action='DropDatabase' After="SetCustomActionDataValue_DropDatabase">Installed</Custom>
I have few other custom actions that run on install and they run fine. Everything is same there except the conditions.
So how can I make my custom action run on uninstall correctly?
I've created a blank wix setup project, and a simple custom action that shows message box on uninstall, and it works fine. I don't know what is the problem with my first custom action.
I use the same DLL on install and uninstall.
The error log goes below:
Action start 16:07:34: INSTALL.
Action start 16:07:34: ValidateProductID.
Action ended 16:07:34: ValidateProductID. Return value 1.
Action start 16:07:34: CostInitialize.
Action ended 16:07:34: CostInitialize. Return value 1.
Action start 16:07:34: FileCost.
Action ended 16:07:34: FileCost. Return value 1.
Action start 16:07:34: CostFinalize.
Action ended 16:07:34: CostFinalize. Return value 1.
Action start 16:07:34: InstallValidate.
Action ended 16:07:34: InstallValidate. Return value 1.
Action start 16:07:34: InstallInitialize.
Action ended 16:07:37: InstallInitialize. Return value 1.
Action start 16:07:37: ProcessComponents.
Action ended 16:07:37: ProcessComponents. Return value 1.
Action start 16:07:37: UnpublishFeatures.
Action ended 16:07:37: UnpublishFeatures. Return value 1.
Action start 16:07:37: RemoveFiles.
Action ended 16:07:37: RemoveFiles. Return value 0.
Action start 16:07:37: InstallFiles.
Action ended 16:07:37: InstallFiles. Return value 1.
Action start 16:07:37: DropDatabase.
Action ended 16:07:37: DropDatabase. Return value 1.
Action start 16:07:37: RegisterUser.
Action ended 16:07:37: RegisterUser. Return value 0.
Action start 16:07:37: RegisterProduct.
Action ended 16:07:37: RegisterProduct. Return value 1.
Action start 16:07:37: PublishFeatures.
Action ended 16:07:37: PublishFeatures. Return value 1.
Action start 16:07:37: PublishProduct.
Action ended 16:07:37: PublishProduct. Return value 1.
Action start 16:07:37: InstallFinalize.
CustomAction DropDatabase returned actual error code 1154 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (D4:DC) [16:07:41:650]: Product: MyProduct -- Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action DropDatabase, entry: DropDatabase, library: C:\Windows\Installer\MSI4DEF.tmp
Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action DropDatabase, entry: DropDatabase, library: C:\Windows\Installer\MSI4DEF.tmp
Action ended 16:07:41: InstallFinalize. Return value 3.
Action ended 16:07:42: INSTALL. Return value 3.
The problem was in my custom action method being private, not public.

Trapping Error Status in MSBuild

As part of some build automation of running xUnit.net tests with MSBuild, I'm running into a case where I need to loop over a batch of items.
Inside the loop, I need to detect whether an iteration failed, but I want to continue executing regardless. Then after the batched bit, I need to know whether one or more errors have occurred in order to report the outcome to TeamBuild.
IOW, in pseudocode:
Task Name=RunTests
CreateItems
ForEach item CallTarget Target=RunTest ContinueOnError=true
CombineNUnitResults
Report success/failure
Task Name=RunTest
XUnit item
I'm hoping this can be achieved without a custom task (or hacking the xunit.net MSBuild task as Jonne did). (But willing to use MSBuild Community or Sdc tasks)
And #BradWilson: I this is isnt possible to do cleanly, I'll be looking for Jonne's change a la the NUnit task to also make it into the xunit task
See also: How do I get Team Build to show test results and coverage for xUnit.net test suite?
This is what we do:
<NUnit Assemblies="#(TestAssemblies)"
ToolPath="$(NUnitPath)"
WorkingDirectory="%(TestAssemblies.RootDir)%(TestAssemblies.Directory)"
OutputXmlFile="#(TestAssemblies->'%(FullPath).$(NUnitFile)')"
Condition="'#(TestAssemblies)' != ''"
ExcludeCategory="$(ExcludeNUnitCategories)"
ContinueOnError="true">
<Output TaskParameter="ExitCode" ItemName="NUnitExitCodes"/>
</NUnit>
<Error Text="Test error(s) occured" Code="%(NUnitExitCodes.Identity)" Condition=" '%(NUnitExitCodes.Identity)' != '0' And '#(TestAssemblies)' != ''"/>
This will run all the unit tests regardless of failure but will fail after all have been run if there were any failures. Note ContinueOnError="true" ensures that they are all run and the Error at the end checks to see if any of them failed (in nunit 0 indicates success, anything else is a failure).
Note: this is using the MSBuildCommunityTasks NUnit task but if you're just using exec with the nunit exe, you can get the same effect. The output "ExitCode" is common to any Task that inherits from ToolTask.
Go grab 1.5 Beta. We fixed this by introducing the ExitCode output parameter to our xunit MSBuild task!
http://xunit.codeplex.com/Release/ProjectReleases.aspx