Skip to content

Commit ceebcf0

Browse files
committed
Updated dbtool to support MTA files
1 parent 1b44640 commit ceebcf0

File tree

10 files changed

+507
-231
lines changed

10 files changed

+507
-231
lines changed
Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// // Copyright (c) Microsoft Corporation.
1+
// // Copyright (c) Microsoft Corporation.
22
// // Licensed under the MIT License.
33

44
using EventLogExpert.Eventing.EventProviderDatabase;
@@ -20,6 +20,14 @@ public static Command GetCommand()
2020
Description = "File to create. Must have a .db extension."
2121
};
2222

23+
Argument<string?> sourceArgument = new("source")
24+
{
25+
Description = "Optional provider source: a .db file, an exported .evtx file, or a folder containing " +
26+
".db and/or .evtx files (top-level only). When omitted, local providers on this machine are used. " +
27+
"When supplied, ONLY the source is used (no fallback to local providers).",
28+
Arity = ArgumentArity.ZeroOrOne
29+
};
30+
2331
Option<string> filterOption = new("--filter")
2432
{
2533
Description = "Only providers matching specified regex string will be added to the database."
@@ -28,7 +36,8 @@ public static Command GetCommand()
2836
Option<string> skipProvidersInFileOption = new("--skip-providers-in-file")
2937
{
3038
Description =
31-
"Any providers found in the specified database file will not be included in the new database. " +
39+
"Any providers found in the specified source (a .db file, an exported .evtx file, or a folder " +
40+
"containing them, top-level only) will not be included in the new database. " +
3241
"For example, when creating a database of event providers for Exchange Server, it may be useful " +
3342
"to provide a database of all providers from a fresh OS install with no other products. That way, all the " +
3443
"OS providers are skipped, and only providers added by Exchange or other installed products " +
@@ -41,6 +50,7 @@ public static Command GetCommand()
4150
};
4251

4352
createDatabaseCommand.Arguments.Add(fileArgument);
53+
createDatabaseCommand.Arguments.Add(sourceArgument);
4454
createDatabaseCommand.Options.Add(filterOption);
4555
createDatabaseCommand.Options.Add(skipProvidersInFileOption);
4656
createDatabaseCommand.Options.Add(verboseOption);
@@ -51,14 +61,15 @@ public static Command GetCommand()
5161
new CreateDatabaseCommand(sp.GetRequiredService<ITraceLogger>())
5262
.CreateDatabase(
5363
result.GetRequiredValue(fileArgument),
64+
result.GetValue(sourceArgument),
5465
result.GetValue(filterOption),
5566
result.GetValue(skipProvidersInFileOption));
5667
});
5768

5869
return createDatabaseCommand;
5970
}
6071

61-
private void CreateDatabase(string path, string? filter, string? skipProvidersInFile)
72+
private void CreateDatabase(string path, string? source, string? filter, string? skipProvidersInFile)
6273
{
6374
if (File.Exists(path))
6475
{
@@ -72,55 +83,43 @@ private void CreateDatabase(string path, string? filter, string? skipProvidersIn
7283
return;
7384
}
7485

75-
HashSet<string> skipProviderNames = [];
86+
if (source is not null && !ProviderSource.TryValidate(source, Logger)) { return; }
87+
88+
HashSet<string> skipProviderNames = new(StringComparer.OrdinalIgnoreCase);
7689

7790
if (!string.IsNullOrWhiteSpace(skipProvidersInFile))
7891
{
79-
if (!File.Exists(skipProvidersInFile))
80-
{
81-
Logger.Error($"File not found: {skipProvidersInFile}");
82-
return;
83-
}
84-
85-
using var skipDbContext = new EventProviderDbContext(skipProvidersInFile, true, Logger);
92+
if (!ProviderSource.TryValidate(skipProvidersInFile, Logger)) { return; }
8693

87-
foreach (var provider in skipDbContext.ProviderDetails)
94+
foreach (var name in ProviderSource.LoadProviderNames(skipProvidersInFile, Logger))
8895
{
89-
skipProviderNames.Add(provider.ProviderName);
96+
skipProviderNames.Add(name);
9097
}
9198

92-
Logger.Info($"Found {skipProviderNames.Count} providers in file {skipProvidersInFile}. These will not be included in the new database.");
99+
Logger.Info($"Found {skipProviderNames.Count} providers in {skipProvidersInFile}. These will not be included in the new database.");
93100
}
94101

95-
var providerNames = GetLocalProviderNames(filter);
102+
IEnumerable<ProviderDetails> providersToAdd = source is null
103+
? LoadLocalProviders(filter)
104+
: ProviderSource.LoadProviders(source, Logger, filter);
96105

97-
if (!providerNames.Any())
98-
{
99-
Logger.Warn($"No providers found matching filter {filter}.");
100-
return;
101-
}
102-
103-
var providerNamesNotSkipped = providerNames.Where(name => !skipProviderNames.Contains(name)).ToList();
106+
var providersNotSkipped = providersToAdd
107+
.Where(p => !skipProviderNames.Contains(p.ProviderName))
108+
.ToList();
104109

105-
var numberSkipped = providerNames.Count - providerNamesNotSkipped.Count;
106-
107-
if (numberSkipped > 0)
110+
if (providersNotSkipped.Count == 0)
108111
{
109-
Logger.Info($"{numberSkipped} providers were skipped due to being present in the specified database.");
112+
Logger.Warn($"No providers to add to the new database.");
113+
return;
110114
}
111115

112116
using var dbContext = new EventProviderDbContext(path, false, Logger);
113117

114-
LogProviderDetailHeader(providerNamesNotSkipped);
118+
LogProviderDetailHeader(providersNotSkipped.Select(p => p.ProviderName));
115119

116-
foreach (var providerName in providerNamesNotSkipped)
120+
foreach (var details in providersNotSkipped)
117121
{
118-
var provider = new EventMessageProvider(providerName, Logger);
119-
120-
var details = provider.LoadProviderDetails();
121-
122122
dbContext.ProviderDetails.Add(details);
123-
124123
LogProviderDetails(details);
125124
}
126125

@@ -131,4 +130,5 @@ private void CreateDatabase(string path, string? filter, string? skipProvidersIn
131130

132131
Logger.Info($"Done!");
133132
}
133+
134134
}

src/EventLogExpert.EventDbTool/DbToolCommand.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ protected static List<string> GetLocalProviderNames(string? filter)
2626
return providers;
2727
}
2828

29+
protected IEnumerable<ProviderDetails> LoadLocalProviders(string? filter)
30+
{
31+
foreach (var providerName in GetLocalProviderNames(filter))
32+
{
33+
yield return new EventMessageProvider(providerName, Logger).LoadProviderDetails();
34+
}
35+
}
36+
2937
protected void LogProviderDetailHeader(IEnumerable<string> providerNames)
3038
{
3139
var maxNameLength = providerNames.Any() ? providerNames.Max(p => p.Length) : 14;

src/EventLogExpert.EventDbTool/DiffDatabaseCommand.cs

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,31 @@ public static Command GetCommand()
1515
{
1616
Command diffDatabaseCommand = new(
1717
"diff",
18-
"Given two databases, produces a third database containing all providers " +
19-
"from the second database which are not in the first database.");
18+
"Given two provider sources (each may be a .db, an exported .evtx, or a folder containing them), " +
19+
"produces a database containing all providers from the second source which are not in the first source.");
2020

21-
Argument<string> dbOneArgument = new("first db")
21+
Argument<string> firstArgument = new("first source")
2222
{
23-
Description = "The first database to compare."
23+
Description = "The first source to compare: a .db, an exported .evtx, or a folder containing .db and/or .evtx files (top-level only)."
2424
};
2525

26-
Argument<string> dbTwoArgument = new("second db")
26+
Argument<string> secondArgument = new("second source")
2727
{
28-
Description = "The second database to compare."
28+
Description = "The second source to compare: a .db, an exported .evtx, or a folder containing .db and/or .evtx files (top-level only)."
2929
};
3030

3131
Argument<string> newDbArgument = new("new db")
3232
{
33-
Description = "The new database containing only the providers in the second db which are not in the first db. Must have a .db extension."
33+
Description = "The new database containing only the providers in the second source which are not in the first source. Must have a .db extension."
3434
};
3535

3636
Option<bool> verboseOption = new("--verbose")
3737
{
3838
Description = "Verbose logging. May be useful for troubleshooting."
3939
};
4040

41-
diffDatabaseCommand.Arguments.Add(dbOneArgument);
42-
diffDatabaseCommand.Arguments.Add(dbTwoArgument);
41+
diffDatabaseCommand.Arguments.Add(firstArgument);
42+
diffDatabaseCommand.Arguments.Add(secondArgument);
4343
diffDatabaseCommand.Arguments.Add(newDbArgument);
4444
diffDatabaseCommand.Options.Add(verboseOption);
4545

@@ -48,23 +48,18 @@ public static Command GetCommand()
4848
using var sp = Program.BuildServiceProvider(action.GetValue(verboseOption));
4949
new DiffDatabaseCommand(sp.GetRequiredService<ITraceLogger>())
5050
.DiffDatabase(
51-
action.GetRequiredValue(dbOneArgument),
52-
action.GetRequiredValue(dbTwoArgument),
51+
action.GetRequiredValue(firstArgument),
52+
action.GetRequiredValue(secondArgument),
5353
action.GetRequiredValue(newDbArgument));
5454
});
5555

5656
return diffDatabaseCommand;
5757
}
5858

59-
private void DiffDatabase(string dbOne, string dbTwo, string newDb)
59+
private void DiffDatabase(string firstSource, string secondSource, string newDb)
6060
{
61-
foreach (var path in new[] { dbOne, dbTwo })
62-
{
63-
if (File.Exists(path)) { continue; }
64-
65-
Logger.Error($"File not found: {path}");
66-
return;
67-
}
61+
if (!ProviderSource.TryValidate(firstSource, Logger)) { return; }
62+
if (!ProviderSource.TryValidate(secondSource, Logger)) { return; }
6863

6964
if (File.Exists(newDb))
7065
{
@@ -78,46 +73,42 @@ private void DiffDatabase(string dbOne, string dbTwo, string newDb)
7873
return;
7974
}
8075

81-
var dbOneProviderNames = new HashSet<string>();
82-
83-
using (var dbOneContext = new EventProviderDbContext(dbOne, true, Logger))
84-
{
85-
dbOneContext.ProviderDetails.Select(p => p.ProviderName).ToList()
86-
.ForEach(name => dbOneProviderNames.Add(name));
87-
}
76+
var firstProviderNames = new HashSet<string>(
77+
ProviderSource.LoadProviderNames(firstSource, Logger),
78+
StringComparer.OrdinalIgnoreCase);
8879

8980
var providersCopied = new List<ProviderDetails>();
9081

91-
using var dbTwoContext = new EventProviderDbContext(dbTwo, true, Logger);
9282
using var newDbContext = new EventProviderDbContext(newDb, false, Logger);
9383

94-
foreach (var details in dbTwoContext.ProviderDetails)
84+
foreach (var details in ProviderSource.LoadProviders(secondSource, Logger))
9585
{
96-
if (dbOneProviderNames.Contains(details.ProviderName))
86+
if (firstProviderNames.Contains(details.ProviderName))
9787
{
98-
Logger.Info($"Skipping {details.ProviderName} because it is present in both databases.");
88+
Logger.Info($"Skipping {details.ProviderName} because it is present in both sources.");
89+
continue;
9990
}
100-
else
91+
92+
Logger.Info($"Copying {details.ProviderName} because it is present in second source but not first.");
93+
94+
newDbContext.ProviderDetails.Add(new ProviderDetails
10195
{
102-
Logger.Info($"Copying {details.ProviderName} because it is present in second db but not first db.");
103-
newDbContext.ProviderDetails.Add(new ProviderDetails
104-
{
105-
ProviderName = details.ProviderName,
106-
Events = details.Events,
107-
Keywords = details.Keywords,
108-
Messages = details.Messages,
109-
Opcodes = details.Opcodes,
110-
Tasks = details.Tasks
111-
});
112-
113-
providersCopied.Add(details);
114-
}
96+
ProviderName = details.ProviderName,
97+
Events = details.Events,
98+
Parameters = details.Parameters,
99+
Keywords = details.Keywords,
100+
Messages = details.Messages,
101+
Opcodes = details.Opcodes,
102+
Tasks = details.Tasks
103+
});
104+
105+
providersCopied.Add(details);
115106
}
116107

117108
newDbContext.SaveChanges();
118109

119110
if (providersCopied.Count <= 0) { return; }
120-
111+
121112
Logger.Info($"Providers copied to new database:");
122113
Logger.Info($"");
123114
LogProviderDetailHeader(providersCopied.Select(p => p.ProviderName));

0 commit comments

Comments
 (0)