diff --git a/ActiveDirectoryQuerier.Tests/PSExecutorTests.cs b/ActiveDirectoryQuerier.Tests/PSExecutorTests.cs index ae5f78b..f16f027 100644 --- a/ActiveDirectoryQuerier.Tests/PSExecutorTests.cs +++ b/ActiveDirectoryQuerier.Tests/PSExecutorTests.cs @@ -107,4 +107,25 @@ public async Task ExecuteAsync_WhenGivenInvalidCommand_ReturnsExpectedOutput(str Assert.NotEmpty(result.StdErr); Assert.Empty(result.StdOut); } + + [Theory] + [InlineData("Get-Command", "Module", "ActiveDirectory")] + [InlineData("Get-Process", "Name", "explorer")] + public async Task ExecuteAsync_ExecuteToCsv_ReturnsExpectedOutput(string command, + string parameter, + string parameterValue) + { + // Arrange + Command psCommand = new(command); + psCommand.Parameters.Add(parameter, parameterValue); + PSExecutor psExecutor = new(); + + // Act + PSOutput result = await psExecutor.ExecuteAsync(psCommand, OutputFormat.Csv); + + // Assert + Assert.False(result.HadErrors); + Assert.Empty(result.StdErr); + Assert.NotEmpty(result.StdOut); + } } diff --git a/ActiveDirectoryQuerier/PowerShell/OutputFormat.cs b/ActiveDirectoryQuerier/PowerShell/OutputFormat.cs new file mode 100644 index 0000000..c753713 --- /dev/null +++ b/ActiveDirectoryQuerier/PowerShell/OutputFormat.cs @@ -0,0 +1,7 @@ +namespace ActiveDirectoryQuerier.PowerShell; + +public enum OutputFormat +{ + Text, + Csv +} diff --git a/ActiveDirectoryQuerier/PowerShell/PSExecutor.cs b/ActiveDirectoryQuerier/PowerShell/PSExecutor.cs index 8ac3ecf..02ef166 100644 --- a/ActiveDirectoryQuerier/PowerShell/PSExecutor.cs +++ b/ActiveDirectoryQuerier/PowerShell/PSExecutor.cs @@ -21,7 +21,7 @@ public PSExecutor() _powerShell.Commands.Clear(); } - private void AssembleFullCommand(Command psCommand) + private void AssembleFullCommand(Command psCommand, OutputFormat outputFormat) { ArgumentNullException.ThrowIfNull(psCommand); @@ -31,14 +31,19 @@ private void AssembleFullCommand(Command psCommand) { _powerShell.Commands.AddParameter(parameter.Name, parameter.Value); } + + if (outputFormat == OutputFormat.Csv) + { + _powerShell.Commands.AddCommand("ConvertTo-Csv").AddParameter("NoTypeInformation"); + } } - public PSOutput Execute(Command psCommand) + public PSOutput Execute(Command psCommand, OutputFormat outputFormat = OutputFormat.Text) { try { _powerShell.Commands.Clear(); - AssembleFullCommand(psCommand); + AssembleFullCommand(psCommand, outputFormat); Collection results = _powerShell.Invoke(); @@ -50,12 +55,12 @@ public PSOutput Execute(Command psCommand) } } - public async Task ExecuteAsync(Command command) + public async Task ExecuteAsync(Command command, OutputFormat outputFormat = OutputFormat.Text) { try { _powerShell.Commands.Clear(); - AssembleFullCommand(command); + AssembleFullCommand(command, outputFormat); PSDataCollection results = await _powerShell.InvokeAsync(); diff --git a/ActiveDirectoryQuerier/QueryExecutor.cs b/ActiveDirectoryQuerier/QueryExecutor.cs index 911890f..b25a86c 100644 --- a/ActiveDirectoryQuerier/QueryExecutor.cs +++ b/ActiveDirectoryQuerier/QueryExecutor.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.IO; using System.Management.Automation.Runspaces; +using System.Reflection; using System.Text; using System.Windows; using System.Windows.Controls; @@ -34,9 +35,11 @@ public async Task ExecuteQueryAsync(ConsoleViewModel consoleOutput, Command? com try { PSOutput result; + OutputFormat outputFormat = CalculateOutputFormat(); + if (command is not null) { - result = await psExecutor.ExecuteAsync(command); + result = await psExecutor.ExecuteAsync(command, outputFormat); } else { @@ -44,7 +47,8 @@ public async Task ExecuteQueryAsync(ConsoleViewModel consoleOutput, Command? com // Null forgiveness operator is used because if command is not null, this line will never be reached. // If it is null, that must mean that SelectedCommandInQueryBuilder is not null, else the return // statement above would have been executed. - result = await psExecutor.ExecuteAsync(mainWindowViewModel.SelectedCommandInQueryBuilder!); + result = + await psExecutor.ExecuteAsync(mainWindowViewModel.SelectedCommandInQueryBuilder!, outputFormat); } if (result.HadErrors) @@ -60,39 +64,37 @@ public async Task ExecuteQueryAsync(ConsoleViewModel consoleOutput, Command? com consoleOutput.Append($"Error executing command: {exception.Message}"); } } - - public async Task OutputExecutionResultsToTextFileAsync(object? queryButton) + + public void ExportConsoleOutputToFile(object _) { - if (queryButton is not null) - { - var buttonQuery = (Query)((Button)queryButton).Tag; - await ExecuteQueryAsync(consoleOutputInQueryBuilder, buttonQuery.Command); - } - else + if (consoleOutputInQueryBuilder.ConsoleOutput.Length == 0) { - await ExecuteQueryAsync(consoleOutputInQueryBuilder); + MessageBox.Show("The console is empty.", "Information", MessageBoxButton.OK, MessageBoxImage.Information); + return; } - // Filepath - // Write the text to a file & prompt user for the location - SaveFileDialog saveFileDialog = new() { // Set properties of the OpenFileDialog - FileName = "Document", // Default file name - Filter = "All files(*.*) | *.*" - }; + SaveFileDialog saveFileDialog = new() { DefaultExt = ".txt", Filter = "Text documents (.txt)|*.txt" }; - // Display bool? result = saveFileDialog.ShowDialog(); - // Get file and write text if (result == true) { - // Open document - string filePath = saveFileDialog.FileName; - await File.WriteAllTextAsync(filePath, consoleOutputInQueryBuilder.ConsoleOutput); + string filename = saveFileDialog.FileName; + consoleOutputInQueryBuilder.ExportToTextFile(filename); } } + public async Task OutputExecutionResultsToTextFileAsync(object? queryButton) + { + await OutputExecutionResultsToFileAsync(queryButton, ".txt", "Text documents (.txt)|*.txt"); + } + public async Task OutputExecutionResultsToCsvFileAsync(object? queryButton) + { + await OutputExecutionResultsToFileAsync(queryButton, ".csv", "CSV files (*.csv)|*.csv"); + } + + private async Task OutputExecutionResultsToFileAsync(object? queryButton, string fileExtension, string filter) { if (queryButton is not null) { @@ -104,49 +106,40 @@ public async Task OutputExecutionResultsToCsvFileAsync(object? queryButton) await ExecuteQueryAsync(consoleOutputInQueryBuilder); } - StringBuilder csv = new(); - string[] output = consoleOutputInQueryBuilder.ConsoleOutput.Split(' ', '\n'); - - for (int i = 0; i < output.Length - 2; i++) - { - var first = output[i]; - var second = output[i + 1]; - // format the strings and add them to a string - var newLine = $"{first},{second}"; - csv.AppendLine(newLine); - } - - // Write the text to a file & prompt user for the location - SaveFileDialog saveFileDialog = new() { FileName = "Document", Filter = "All files(*.*) | *.*" }; + SaveFileDialog saveFileDialog = new() { DefaultExt = fileExtension, Filter = filter }; - // Display bool? result = saveFileDialog.ShowDialog(); - // Get file and write text if (result == true) { - // Open document string filePath = saveFileDialog.FileName; - await File.WriteAllTextAsync(filePath, csv.ToString()); + await File.WriteAllTextAsync(filePath, consoleOutputInQueryBuilder.ConsoleOutput); } } - - public void ExportConsoleOutputToFile(object _) + + private OutputFormat CalculateOutputFormat() { - if (consoleOutputInQueryBuilder.ConsoleOutput.Length == 0) - { - MessageBox.Show("The console is empty.", "Information", MessageBoxButton.OK, MessageBoxImage.Information); - return; - } - - SaveFileDialog saveFileDialog = new() { DefaultExt = ".txt", Filter = "Text documents (.txt)|*.txt" }; + StackTrace stackTrace = new(); + StackFrame[] stackFrames = stackTrace.GetFrames(); - bool? result = saveFileDialog.ShowDialog(); + try + { + if (stackFrames.Length > 2) + { + // Null forgiveness operator is used because the method this statement would not be reached if the + // length of the stackFrames array is less than 3. + MethodBase callingMethod = stackFrames[2].GetMethod()!; + if (callingMethod.Name == "OutputExecutionResultsToCsvFileAsync") + { + return OutputFormat.Csv; + } + } - if (result == true) + return OutputFormat.Text; + } + catch (Exception) { - string filename = saveFileDialog.FileName; - consoleOutputInQueryBuilder.ExportToTextFile(filename); + return OutputFormat.Text; } } }