diff --git a/.github/workflows/build-test-ci.yml b/.github/workflows/build-test-ci.yml index db15e24..797c608 100644 --- a/.github/workflows/build-test-ci.yml +++ b/.github/workflows/build-test-ci.yml @@ -1,4 +1,4 @@ -name: Built Test +name: Build Test on: push: @@ -9,12 +9,11 @@ jobs: strategy: matrix: targetplatform: [x64] - #targetplatform: [x86, x64] runs-on: windows-latest env: - Project_File: FAFB-PowerShell-Tool\FAFB-PowerShell-Tool.csproj + Project_File: ActiveDirectoryQuerier\ActiveDirectoryQuerier.csproj steps: - name: Checkout @@ -31,7 +30,8 @@ jobs: Import-Module ActiveDirectory - name: Dotnet Restore & Build - run: dotnet build $env:Project_File -c Debug -f net6.0-windows -r win-${{ matrix.targetplatform }} + run: dotnet build $env:Project_File -c Debug -f net8.0-windows -r win-${{ matrix.targetplatform }} - - name: Dotnet Test - run: dotnet test + - name: Dotnet Test with Coverage + run: | + dotnet test $env:Project_File --no-build diff --git a/.github/workflows/release-ci.yml b/.github/workflows/release-ci.yml index cb29c6c..7da31fa 100644 --- a/.github/workflows/release-ci.yml +++ b/.github/workflows/release-ci.yml @@ -16,7 +16,7 @@ jobs: runs-on: windows-latest env: - Project_File: FAFB-PowerShell-Tool\FAFB-PowerShell-Tool.csproj + Project_File: ActiveDirectoryQuerier\ActiveDirectoryQuerier.csproj steps: - name: Checkout @@ -29,16 +29,16 @@ jobs: - name: Dotnet Build & Publish run: | - dotnet build $env:Project_File -c Release -f net6.0-windows -r win-${{ matrix.targetplatform }} - dotnet publish $env:Project_File -c Release -f net6.0-windows -r win-${{ matrix.targetplatform }} -o ./publish/FAFB_PowerShell_Tool_${{ matrix.targetplatform }} + dotnet build $env:Project_File -c Release -f net8.0-windows -r win-${{ matrix.targetplatform }} + dotnet publish $env:Project_File -c Release -f net8.0-windows -r win-${{ matrix.targetplatform }} -o ./publish/ActiveDirectoryQuerier_${{ matrix.targetplatform }} - name: Zip Release Files - run: Compress-Archive -Path .\publish\FAFB_PowerShell_Tool_${{ matrix.targetplatform }} -DestinationPath .\FAFB_PowerShell_Tool_${{ matrix.targetplatform }}.zip + run: Compress-Archive -Path .\publish\ActiveDirectoryQuerier_${{ matrix.targetplatform }} -DestinationPath .\ActiveDirectoryQuerier_${{ matrix.targetplatform }}.zip - name: Create Release id: create_release uses: softprops/action-gh-release@v1 with: - files: FAFB_PowerShell_Tool_${{ matrix.targetplatform }}.zip + files: ActiveDirectoryQuerier_${{ matrix.targetplatform }}.zip env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} diff --git a/.gitignore b/.gitignore index e0bed98..248bc4c 100644 --- a/.gitignore +++ b/.gitignore @@ -476,14 +476,14 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -.vscode/launch.json - -.vscode/tasks.json +# Rider files +.idea -.idea/.idea.FAFB-PowerShell-Tool/.idea/indexLayout.xml -.idea/.idea.FAFB-PowerShell-Tool/.idea/workspace.xml - -FAFB-PowerShell-Tool/FAFB-PowerShell-Tool-Output.txt +# VSCode files +.vscode/launch.json +.vscode/tasks.json -.idea/.idea.FAFB-PowerShell-Tool/.idea/ +# Text and CSV files +*.txt +*.csv diff --git a/ActiveDirectoryQuerier.Tests/ActiveDirectoryCommandsTests.cs b/ActiveDirectoryQuerier.Tests/ActiveDirectoryCommandsTests.cs new file mode 100644 index 0000000..267c130 --- /dev/null +++ b/ActiveDirectoryQuerier.Tests/ActiveDirectoryCommandsTests.cs @@ -0,0 +1,31 @@ +using System.Collections.ObjectModel; +using System.Management.Automation.Runspaces; +using ActiveDirectoryQuerier.PowerShell; + +namespace ActiveDirectoryQuerier.Tests; + +public class ActiveDirectoryCommandsTests +{ + [Fact] + public async Task GetActiveDirectoryCommands_ReturnsCommandList_IsNotEmpty() + { + // Act + ObservableCollection commandList = await ActiveDirectoryCommands.GetActiveDirectoryCommands(); + + // Assert + Assert.NotEmpty(commandList); + } + + [Theory] + [InlineData("Get-ADUser")] + [InlineData("Get-ADGroup")] + [InlineData("Get-ADComputer")] + public async Task GetActiveDirectoryCommands_ReturnsCommandList_ContainsCommand(string commandName) + { + // Act + ObservableCollection commandList = await ActiveDirectoryCommands.GetActiveDirectoryCommands(); + + // Assert + Assert.Contains(commandList, cmd => cmd.CommandText == commandName); + } +} diff --git a/FAFB-PowerShell-Tool.Tests/FAFB-PowerShell-Tool.Tests.csproj b/ActiveDirectoryQuerier.Tests/ActiveDirectoryQuerier.Tests.csproj similarity index 65% rename from FAFB-PowerShell-Tool.Tests/FAFB-PowerShell-Tool.Tests.csproj rename to ActiveDirectoryQuerier.Tests/ActiveDirectoryQuerier.Tests.csproj index 51cd79e..ee0dbed 100644 --- a/FAFB-PowerShell-Tool.Tests/FAFB-PowerShell-Tool.Tests.csproj +++ b/ActiveDirectoryQuerier.Tests/ActiveDirectoryQuerier.Tests.csproj @@ -1,28 +1,25 @@ - net6.0-windows - FAFB_PowerShell_Tool.Tests - enable - enable - false + ActiveDirectoryQuerier.Tests + ActiveDirectoryQuerier.Tests - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/ActiveDirectoryQuerier.Tests/CommandParametersTests.cs b/ActiveDirectoryQuerier.Tests/CommandParametersTests.cs new file mode 100644 index 0000000..aa749a2 --- /dev/null +++ b/ActiveDirectoryQuerier.Tests/CommandParametersTests.cs @@ -0,0 +1,46 @@ +using System.Management.Automation.Runspaces; +using ActiveDirectoryQuerier.PowerShell; + +namespace ActiveDirectoryQuerier.Tests; + +public class CommandParametersTests +{ + [Fact] + public void PossibleParameters_LoadCommandParametersAsyncNotPopulated_ThrowInvalidOperationException() + { + // Arrange + CommandParameters commandParameters = new(); + + // Assert + Assert.Throws(() => commandParameters.PossibleParameters); + } + + [Fact] + public async Task LoadCommandParametersAsync_PopulatesPossibleParameters_IsNotEmpty() + { + // Arrange + CommandParameters commandParameters = new(); + Command command = new("Get-Process"); + + // Act + await commandParameters.LoadCommandParametersAsync(command); + + // Assert + Assert.NotEmpty(commandParameters.PossibleParameters); + } + + [Fact] + public async Task LoadCommandParametersAsync_CheckPossibleParameter_ContentIsCorrect() + { + // Arrange + CommandParameters commandParameters = new(); + Command command = new("Get-Process"); + + // Act + await commandParameters.LoadCommandParametersAsync(command); + + // Assert + Assert.Contains("-Name", commandParameters.PossibleParameters); + Assert.Contains("-Id", commandParameters.PossibleParameters); + } +} diff --git a/FAFB-PowerShell-Tool.Tests/GlobalUsings.cs b/ActiveDirectoryQuerier.Tests/GlobalUsings.cs similarity index 100% rename from FAFB-PowerShell-Tool.Tests/GlobalUsings.cs rename to ActiveDirectoryQuerier.Tests/GlobalUsings.cs diff --git a/ActiveDirectoryQuerier.Tests/PowerShellExecutorTests.cs b/ActiveDirectoryQuerier.Tests/PowerShellExecutorTests.cs new file mode 100644 index 0000000..24c8828 --- /dev/null +++ b/ActiveDirectoryQuerier.Tests/PowerShellExecutorTests.cs @@ -0,0 +1,105 @@ +using System.Management.Automation.Runspaces; +using ActiveDirectoryQuerier.PowerShell; + +namespace ActiveDirectoryQuerier.Tests; + +public class PowerShellExecutorTests +{ + [Theory] + [InlineData("Get-Command", "Module", "ActiveDirectory")] + [InlineData("Get-Process", "Name", "explorer")] + public void Execute_WhenGivenValidCommand_ReturnsExpectedOutput(string cmd, string paramName, string paramValue) + { + // Arrange + Command command = new(cmd); + command.Parameters.Add(paramName, paramValue); + PowerShellExecutor powerShellExecutor = new(); + + // Act + ReturnValues result = powerShellExecutor.Execute(command); + + // Assert + Assert.False(result.HadErrors); + Assert.Empty(result.StdErr); + Assert.NotEmpty(result.StdOut); + } + + [Fact] + public void Execute_CheckIfOutputChanged_ReturnsDifferentOutput() + { + // Arrange + Command command = new("Get-Command"); + command.Parameters.Add("Module", "ActiveDirectory"); + Command command2 = new("Get-Process"); + command.Parameters.Add("Name", "explorer"); + PowerShellExecutor powerShellExecutor = new(); + + // Act + ReturnValues result = powerShellExecutor.Execute(command); + ReturnValues result2 = powerShellExecutor.Execute(command2); + + // Assert + Assert.NotEqual(result, result2); + } + + [Theory] + [InlineData("Get-Command", "Module", "ActiveDirectory")] + [InlineData("Get-Process", "Name", "explorer")] + public async Task ExecuteAsync_WhenGivenValidCommand_ReturnsExpectedOutput(string cmd, + string paramName, + string paramValue) + { + // Arrange + Command command = new(cmd); + command.Parameters.Add(paramName, paramValue); + PowerShellExecutor powerShellExecutor = new(); + + // Act + ReturnValues result = await powerShellExecutor.ExecuteAsync(command); + + // Assert + Assert.False(result.HadErrors); + Assert.Empty(result.StdErr); + Assert.NotEmpty(result.StdOut); + } + + [Theory] + [InlineData("Get-ADUser", "InvalidParameter", "*")] + [InlineData("InvalidCommand", "Filter", "*")] + public void Execute_WhenGivenInvalidCommand_ReturnsExpectedOutput(string cmd, string paramName, string paramValue) + { + // Arrange + Command command = new(cmd); + command.Parameters.Add(paramName, paramValue); + PowerShellExecutor powerShellExecutor = new(); + + // Act + ReturnValues result = powerShellExecutor.Execute(command); + + // Assert + Assert.True(result.HadErrors); + Assert.NotEmpty(result.StdErr); + Assert.Empty(result.StdOut); + } + + [Theory] + [InlineData("Get-ADUser", "InvalidParameter", "*")] + [InlineData("InvalidCommand", "Filter", "*")] + public async Task ExecuteAsync_WhenGivenInvalidCommand_ReturnsExpectedOutput(string cmd, + string paramName, + string paramValue) + { + // Arrange + Command command = new(cmd); + command.Parameters.Add(paramName, paramValue); + PowerShellExecutor powerShellExecutor = new(); + + // Act + ReturnValues result = await powerShellExecutor.ExecuteAsync(command); + + // Assert + Assert.True(result.HadErrors); + Assert.NotEmpty(result.StdErr); + Assert.Empty(result.StdOut); + } +} diff --git a/ActiveDirectoryQuerier.Tests/RelayCommandTests.cs b/ActiveDirectoryQuerier.Tests/RelayCommandTests.cs new file mode 100644 index 0000000..b44ba75 --- /dev/null +++ b/ActiveDirectoryQuerier.Tests/RelayCommandTests.cs @@ -0,0 +1,83 @@ +namespace ActiveDirectoryQuerier.Tests; + +public class RelayCommandTests +{ + [Fact] + public void CanExecute_WithNullPredicate_ReturnsTrue() + { + RelayCommand command = new( + _ => + {}); + Assert.True(command.CanExecute(null)); + } + + [Fact] + public void CanExecute_WithNonNullPredicate_ReturnsTrue() + { + RelayCommand command = new( + _ => + {}, + _ => true); + Assert.True(command.CanExecute(null)); + } + + [Fact] + public void CanExecute_WithNonNullPredicate_ReturnsFalse() + { + RelayCommand command = new( + _ => + {}, + _ => false); + Assert.False(command.CanExecute(null)); + } + + [Fact] + public void Execute_WithNullParameter_Executes() + { + bool executed = false; + RelayCommand command = new( + _ => executed = true); + command.Execute(null); + Assert.True(executed); + } + + [Fact] + public void Execute_WithNonNullParameter_Executes() + { + bool executed = false; + RelayCommand command = new( + _ => executed = true); + command.Execute("test"); + Assert.True(executed); + } + + [Fact] + public void RaiseCanExecuteChanged_WithNullParameter_DoesNotThrow() + { + RelayCommand command = new( + _ => + {}); + command.RaiseCanExecuteChanged(); + } + + [Fact] + public void CanExecuteChanged_WithNullParameter_DoesNotThrow() + { + RelayCommand command = new( + _ => + {}); + command.CanExecuteChanged += (_, _) => + {}; + } + + [Fact] + public void CanExecuteChanged_WithNullParameter_DoesNotThrow2() + { + RelayCommand command = new( + _ => + {}); + // ReSharper disable once EventUnsubscriptionViaAnonymousDelegate + command.CanExecuteChanged -= (_, _) => + {}; + } +} diff --git a/ActiveDirectoryQuerier.Tests/ReturnValuesTest.cs b/ActiveDirectoryQuerier.Tests/ReturnValuesTest.cs new file mode 100644 index 0000000..7e75175 --- /dev/null +++ b/ActiveDirectoryQuerier.Tests/ReturnValuesTest.cs @@ -0,0 +1,38 @@ +using ActiveDirectoryQuerier.PowerShell; + +namespace ActiveDirectoryQuerier.Tests; + +public class ReturnValuesTest +{ + [Fact] + public void HadErrors_StdErrHasEntries_ReturnsTrue() + { + // Arrange + var returnValues = new ReturnValues(); + returnValues.StdErr.Add("Error"); + + // Act + var result = returnValues.HadErrors; + + // Assert + Assert.True(result); + Assert.NotEmpty(returnValues.StdErr); + Assert.Empty(returnValues.StdOut); + } + + [Fact] + public void NoErrors_StdOutHasEntries_ReturnsFalse() + { + // Arrange + var returnValues = new ReturnValues(); + returnValues.StdOut.Add("Output"); + + // Act + var result = returnValues.HadErrors; + + // Assert + Assert.False(result); + Assert.Empty(returnValues.StdErr); + Assert.NotEmpty(returnValues.StdOut); + } +} diff --git a/FAFB-PowerShell-Tool.sln b/ActiveDirectoryQuerier.sln similarity index 91% rename from FAFB-PowerShell-Tool.sln rename to ActiveDirectoryQuerier.sln index 1cbddd3..953b81b 100644 --- a/FAFB-PowerShell-Tool.sln +++ b/ActiveDirectoryQuerier.sln @@ -2,9 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34309.116 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FAFB-PowerShell-Tool", "FAFB-PowerShell-Tool\FAFB-PowerShell-Tool.csproj", "{C6E51308-E9E0-4738-9D5A-49841912633B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ActiveDirectoryQuerier", "ActiveDirectoryQuerier\ActiveDirectoryQuerier.csproj", "{C6E51308-E9E0-4738-9D5A-49841912633B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FAFB-PowerShell-Tool.Tests", "FAFB-PowerShell-Tool.Tests\FAFB-PowerShell-Tool.Tests.csproj", "{C1FD9137-6780-44AE-9920-A566FC555F68}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveDirectoryQuerier.Tests", "ActiveDirectoryQuerier.Tests\ActiveDirectoryQuerier.Tests.csproj", "{C1FD9137-6780-44AE-9920-A566FC555F68}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/ActiveDirectoryQuerier/ActiveDirectoryQuerier.csproj b/ActiveDirectoryQuerier/ActiveDirectoryQuerier.csproj new file mode 100644 index 0000000..29697df --- /dev/null +++ b/ActiveDirectoryQuerier/ActiveDirectoryQuerier.csproj @@ -0,0 +1,28 @@ + + + + WinExe + x64 + true + ActiveDirectoryQuerier + ActiveDirectoryQuerier + + + Active Directory Querier + 0.4.1 + Hunter T., Pieter Landry Sobtafo, Joseph + https://github.com/StrangeRanger/FAFB-PowerShell-Tool + + + false + true + embedded + true + + + + + + + + diff --git a/FAFB-PowerShell-Tool/App.xaml b/ActiveDirectoryQuerier/App.xaml similarity index 70% rename from FAFB-PowerShell-Tool/App.xaml rename to ActiveDirectoryQuerier/App.xaml index 251099b..4a1f861 100644 --- a/FAFB-PowerShell-Tool/App.xaml +++ b/ActiveDirectoryQuerier/App.xaml @@ -1,7 +1,6 @@ - diff --git a/FAFB-PowerShell-Tool/App.xaml.cs b/ActiveDirectoryQuerier/App.xaml.cs similarity index 79% rename from FAFB-PowerShell-Tool/App.xaml.cs rename to ActiveDirectoryQuerier/App.xaml.cs index b06bd4e..8f83fe4 100644 --- a/FAFB-PowerShell-Tool/App.xaml.cs +++ b/ActiveDirectoryQuerier/App.xaml.cs @@ -1,6 +1,6 @@ using System.Windows; -namespace FAFB_PowerShell_Tool; +namespace ActiveDirectoryQuerier; /// /// Interaction logic for App.xaml diff --git a/FAFB-PowerShell-Tool/AssemblyInfo.cs b/ActiveDirectoryQuerier/AssemblyInfo.cs similarity index 100% rename from FAFB-PowerShell-Tool/AssemblyInfo.cs rename to ActiveDirectoryQuerier/AssemblyInfo.cs diff --git a/ActiveDirectoryQuerier/ComboBoxParameterViewModel.cs b/ActiveDirectoryQuerier/ComboBoxParameterViewModel.cs new file mode 100644 index 0000000..b9c800e --- /dev/null +++ b/ActiveDirectoryQuerier/ComboBoxParameterViewModel.cs @@ -0,0 +1,68 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; + +namespace ActiveDirectoryQuerier; + +/// +/// ViewModel for a ComboBox that displays possible parameters for a PowerShell command. +/// It is used when adding a new parameter slot to a command in the UI. +/// +public sealed class ComboBoxParameterViewModel : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + private ObservableCollection _possibleParameterList = new(); + private string _selectedParameter = string.Empty; + + /// + /// Initializes a new instance of the ComboBoxParameterViewModel class. + /// + /// Initial list of possible parameters for the ComboBox. + public ComboBoxParameterViewModel(ObservableCollection possibleParameterList) + { + PossibleParameterList = possibleParameterList ?? throw new ArgumentNullException(nameof(possibleParameterList)); + } + + /// + /// Sets a unique selected value for each combo box. + /// + public string SelectedParameter + { + get => _selectedParameter; + set { + if (_selectedParameter != value) + { + _selectedParameter = value; + OnPropertyChanged(nameof(SelectedParameter)); + } + } + } + + /// + /// Gets or sets the list of possible parameters that can be selected for a command. + /// + public ObservableCollection PossibleParameterList + { + get => _possibleParameterList; + set { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (_possibleParameterList != value) + { + _possibleParameterList = value; + OnPropertyChanged(nameof(PossibleParameterList)); + } + } + } + + /// + /// Invokes the PropertyChanged event for the specified property name. + /// + /// Name of the property that has changed. + private void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} diff --git a/ActiveDirectoryQuerier/MainWindow.xaml b/ActiveDirectoryQuerier/MainWindow.xaml new file mode 100644 index 0000000..7a62e8f --- /dev/null +++ b/ActiveDirectoryQuerier/MainWindow.xaml @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +