/// <summary> /// Initalize this class with a record with recommended values for a BaseRecord /// </summary> /// <param name="record"></param> internal ResultPrimarySecondary(BaseRecord record) { //Short-circut some values Conclusion = record.Conclusion; string description = string.IsNullOrWhiteSpace(record.Description) ? string.Empty : record.Description; switch (Conclusion) { //The primary result for these conclusion is always our pre-set value and (if available) the description from the script as secondary case ConclusionEnum.Success: case ConclusionEnum.DoesNotApply: case ConclusionEnum.Fatal: //Set Primary to a descriptive text, e.g. Conclusiong==Success -> "OK (Success)" Primary = ConclusionEnumConverter.ConclusionHumanized(Conclusion); if (record is AssetRecord) { //For an asset that returned SUCCESS, the VALUE the asset has retrieved is the interessting part, hence change primary to the value if (Conclusion == ConclusionEnum.Success) { Primary = (record as AssetRecord).Data; } //Assign to secondary either the default conclusion description or the one from the script Secondary = string.IsNullOrWhiteSpace(description) ? ConclusionEnumConverter.AssetRecordConclusionDescription(Conclusion) : description; } else { Secondary = string.IsNullOrWhiteSpace(description) ? ConclusionEnumConverter.TestRecordConclusionDescription(Conclusion) : description; } break; //For these conclusions, the text will be promoted to be Primary, and our internal description for the conclusion is secondary. //The exception for this rule is if we have text, then the value from the script will be used case ConclusionEnum.Inconclusive: case ConclusionEnum.Major: case ConclusionEnum.Minor: if (record is AssetRecord) { Primary = string.IsNullOrEmpty(description) ? ConclusionEnumConverter.ConclusionHumanized(Conclusion) : description; Secondary = ConclusionEnumConverter.AssetRecordConclusionDescription(Conclusion); } else { Primary = string.IsNullOrEmpty(description) ? ConclusionEnumConverter.ConclusionHumanized(Conclusion) : description; Secondary = ConclusionEnumConverter.TestRecordConclusionDescription(Conclusion); } break; default: throw new ArgumentOutOfRangeException(string.Format("Found unknown ConclusionEnum: {0}", Conclusion.ToString())); } }
public BaseRecord(BaseRecord copyFrom) { this.Name = copyFrom.Name; this.Conclusion = copyFrom.Conclusion; this.Description = copyFrom.Description; this.ScriptFilePath = copyFrom.ScriptFilePath; this.ProcessMessages = copyFrom.ProcessMessages; this.ScriptSuccessful = copyFrom.ScriptSuccessful; }
void ProcessHashtableOutputInternal(BaseRecord record, Hashtable table) { //We need a a key "Data" or this is considered to be fatal. The value of this key can still be NULL. if (table.ContainsKey(Xteq5EngineConstant.ReturnedHashtableKeyData) == false) { record.Conclusion = ConclusionEnum.Fatal; record.AddLineToProcessMessages("Data key missing from returned hashtable"); ProcessFailure(record); } else { string name = GetStringFromHashtable(table, Xteq5EngineConstant.ReturnedHashtableKeyName); if (string.IsNullOrEmpty(name) == false) { record.Name = name; } string text = GetStringFromHashtable(table, Xteq5EngineConstant.ReturnedHashtableKeyText); if (string.IsNullOrEmpty(text) == false) { record.Description = text; } string data = GetStringFromHashtable(table, Xteq5EngineConstant.ReturnedHashtableKeyData); if (string.IsNullOrEmpty(data)) { //Empty data means DoesNotApply record.Conclusion = ConclusionEnum.DoesNotApply; ProcessEmptyData(record, table); } else { //The data key contains something. First try if the result is maybe the string "n/a" ConclusionEnum conclusion = ConclusionEnumConverter.ParseConclusion(data); if (conclusion == ConclusionEnum.DoesNotApply) { //The script returned n/a (DoesNotApply), so it can be processed as an empty record record.Conclusion = ConclusionEnum.DoesNotApply; ProcessEmptyData(record, table); } else { //The result was something else. Let the implementation decide. ProcessNonEmptyData(record, table, data); } } } }
protected override void ProcessNonEmptyData(BaseRecord record, Hashtable table, string dataKeyValue) { //The basic values are all set by :base() and it was also validated that the hashtable contains a key ".Data". TestRecord testRecord = new TestRecord(record); //Data is not NULL and not "", hence we need to check which conclusion the author wanted to report ConclusionEnum conclusion = ConclusionEnumConverter.ParseConclusion(dataKeyValue); if (conclusion == ConclusionEnum.Fatal) { //We were not able to parse the value inside .Data testRecord.AddLineToProcessMessages(string.Format("Unable to parse result {0}", dataKeyValue)); } testRecord.Conclusion = conclusion; _results.Add(testRecord); }
//This needs to be called by the implementation to start the replacement process protected void StartGenerating(Report report) { ReplaceHeaderValuesInternal(report); ReplaceAssetStatisticsInternal(report); ReplaceTestStatisticsInternal(report); ReplaceResultTextInternal(); ReplaceAssetConclusionTextInternal(); ReplaceTestConclusionTextInternal(); ReplaceTestRecommendedActionTextInternal(); //Begin details replacement for assets StringBuilder sbAssets = new StringBuilder(); StartAssetDetails(sbAssets); foreach (AssetRecord asset in report.Assets) { BaseRecord baseRec = asset as BaseRecord; ResultPrimarySecondary rps = new ResultPrimarySecondary(baseRec); ProcessAsset(sbAssets, asset, baseRec, rps); } EndAssetDetails(sbAssets); ReplaceAssetList("AssetRows".ToUpper(), sbAssets.ToString()); //Begin details replacment for tests StringBuilder sbTests = new StringBuilder(); StartTestDetails(sbTests); foreach (TestRecord test in report.Tests) { BaseRecord baseRec = test as BaseRecord; ResultPrimarySecondary rps = new ResultPrimarySecondary(baseRec); ProcessTest(sbTests, test, baseRec, rps); } EndTestDetails(sbAssets); ReplaceTestList("TestRows".ToUpper(), sbTests.ToString()); }
/// <summary> /// Generates a JSON formated output report /// </summary> /// <param name="report">The report that should be transfered into JSON</param> /// <returns>A JSON formated string</returns> public override string Generate(Report report) { ReportClass rep = new ReportClass(); rep.IssuesFound = new IssuesFoundClass(); rep.ID = report.ID; rep.Compilation = report.CompilationFolder; rep.EngineVersion = report.EngineVersion; rep.EngineVersionString = report.EngineVersion.ToString(); rep.Username = report.UserName; rep.Computername = report.ComputerName; rep.Text = report.UserText; rep.StartDateTimeUTC = report.StartedUTC; rep.EndDateTimeUTC = report.EndedUTC; rep.RuntimeSeconds = report.RuntimeSeconds; rep.IssuesFound.Any = report.IssuesFound; rep.IssuesFound.Assets = report.AssetIssuesFound; rep.IssuesFound.Tests = report.TestIssuesFound; rep.AssetStatistics = report.AssetStatiscs; rep.TestStatistics = report.TestStatiscs; rep.Assets = new List <ItemDetail>(); rep.Tests = new List <ItemDetail>(); //Loop over all assets foreach (AssetRecord asset in report.Assets) { BaseRecord baseRec = asset as BaseRecord; rep.Assets.Add(ConvertToItemDetail(baseRec)); } //Loop over all tests foreach (TestRecord test in report.Tests) { BaseRecord baseRec = test as BaseRecord; rep.Tests.Add(ConvertToItemDetail(baseRec)); } //MTH: I can't even imaging how much magic happens in this single call. return(JsonConvert.SerializeObject(rep)); }
string CreateRecordDetails(string tagName, BaseRecord record, ResultPrimarySecondary resultPrimSecond) { //Yes, this somewhat cheating.... WeakHTMLTag tag = new WeakHTMLTag(tagName); WeakHTMLTag name = new WeakHTMLTag("Name"); name.Text = record.Name; WeakHTMLTag filename = new WeakHTMLTag("Filename"); filename.Text = record.ScriptFilename; WeakHTMLTag conclusion = new WeakHTMLTag("Conclusion"); conclusion.Text = ((int)record.Conclusion).ToString(); WeakHTMLTag conclusionString = new WeakHTMLTag("ConclusionString"); conclusionString.Text = record.Conclusion.ToString(); //Create sub tag "result" WeakHTMLTag primary = new WeakHTMLTag("Primary"); primary.Text = resultPrimSecond.Primary; WeakHTMLTag secondary = new WeakHTMLTag("Secondary"); secondary.Text = resultPrimSecond.Secondary; WeakHTMLTag result = new WeakHTMLTag("Result"); result.HTML = primary.ToString() + secondary.ToString(); //Construct the final XML tag.HTML = name.ToString() + filename.ToString() + conclusion.ToString() + conclusionString.ToString() + result.ToString(); return(tag.ToString()); }
private ItemDetail ConvertToItemDetail(BaseRecord baseRec) { ItemDetail detail = new ItemDetail(); detail.Name = baseRec.Name; detail.Filename = baseRec.ScriptFilename; detail.Conclusion = baseRec.Conclusion; detail.ConclusionString = baseRec.Conclusion.ToString(); ResultPrimarySecondary rps = new ResultPrimarySecondary(baseRec); ItemResult result = new ItemResult(); result.Primary = rps.Primary; result.Seconday = rps.Secondary; detail.Result = result; return(detail); }
protected override void ProcessNonEmptyData(BaseRecord record, Hashtable table, string dataKeyValue) { AssetRecord assetRecord = new AssetRecord(record); //Data is set = Conclusion.Success assetRecord.Conclusion = ConclusionEnum.Success; assetRecord.Data = dataKeyValue; //Check the object that was returned and copy it to .DataNative (if we support the type) object dataObjectFromHashtable = GetObjectFromHashtable(table, Xteq5EngineConstant.ReturnedHashtableKeyData); if (dataObjectFromHashtable is string) { //String is the default of .Data. Therefore no action is required } else { if (dataObjectFromHashtable is bool) { assetRecord.DataNative = (Boolean)dataObjectFromHashtable; } else { if (dataObjectFromHashtable is int) { assetRecord.DataNative = (int)dataObjectFromHashtable; } else { if (dataObjectFromHashtable is System.Version) { assetRecord.DataNative = dataObjectFromHashtable as System.Version; } } } } _results.Add(assetRecord); }
//Called by this class for each test that exists. Imlementation must add the content to the given stringbuilder. protected abstract void ProcessTest(StringBuilder sbTests, TestRecord test, BaseRecord baseRec, ResultPrimarySecondary resultPrimSecond);
//Called by this class for each asset that exists. Imlementation must add the content to the given stringbuilder. protected abstract void ProcessAsset(StringBuilder sbAssets, AssetRecord asset, BaseRecord baseRec, ResultPrimarySecondary resultPrimSecond);
protected override void ProcessTest(StringBuilder sbTests, TestRecord test, BaseRecord baseRec, ResultPrimarySecondary resultPrimSecond) { sbTests.AppendLine(CreateTableRow(baseRec, resultPrimSecond)); }
protected override void ProcessAsset(StringBuilder sbAssets, AssetRecord asset, BaseRecord baseRec, ResultPrimarySecondary resultPrimSecond) { sbAssets.AppendLine(CreateTableRow(baseRec, resultPrimSecond)); }
internal TestRecord(BaseRecord baseRecord) : base(baseRecord) { }
protected abstract void ProcessFailure(BaseRecord record);
protected abstract void ProcessEmptyData(BaseRecord record, Hashtable table);
internal AssetRecord(BaseRecord baseRecord) : base(baseRecord) { Data = string.Empty; DataNative = null; }
protected async Task RunInternalAsync(PSScriptRunner scriptRunner, string scriptDirectory, IProgress <RunnerProgressDetail> progress = null) { //Assign progress reporter and set it that it can be used after calling Report() _reporter = new ProgressReporter <RunnerProgressDetail>(progress, createNewInstanceAfterReport: true); //Report that we are about to start _reporter.Content.Action = RunnerAction.Starting; _reporter.Report(); string[] allScripts = Directory.GetFiles(scriptDirectory, Xteq5EngineConstant.ScriptFilePattern); NaturalSort.Sort(allScripts); foreach (string scriptFilename in allScripts) { //Set the values we already have BaseRecord record = new BaseRecord(); record.ScriptFilePath = scriptFilename; record.Name = Path.GetFileNameWithoutExtension(scriptFilename); try { //Report back status ReportProgressScript(scriptFilename); using (ExecutionResult execResult = await scriptRunner.RunScriptFileAsync(scriptFilename)) { record.ProcessMessages = execResult.ToString(); if (execResult.Successful == false) { ProcessFailure(record); } else { //The script was run OK record.ScriptSuccessful = true; //Search the output Hashtable table = new Hashtable(); //new() is required or the compiler will complain about an unassigned local variable bool foundHashtable = false; //Search the output collection for a hashtable foreach (PSObject psobj in execResult.StreamOutput) { if (psobj.BaseObject != null && psobj.BaseObject is Hashtable) { foundHashtable = true; table = psobj.BaseObject as Hashtable; break; } } if (foundHashtable == false) { //No hashtable was found within output stream. Add this to messages record.AddLineToProcessMessages("No Hashtable was returned"); ProcessFailure(record); } else { ProcessHashtableOutputInternal(record, table); } } } } catch (Exception exc) { //That didn't go well record.ProcessMessages = exc.ToString(); //Let the actual implementation decide what to do next ProcessFailure(record); } //MTH: End of processing with this file. Next one please! } //Report status that this entire run has finished _reporter.Content.Action = RunnerAction.Ended; _reporter.Report(); }
protected abstract void ProcessNonEmptyData(BaseRecord record, Hashtable table, string dataKeyValue);