Skip to content

Commit

Permalink
Merge pull request #10 from santisq/9-sort-trees-by-ascending-values
Browse files Browse the repository at this point in the history
Adds comparer for ascending sorting of sub-trees
  • Loading branch information
santisq authored Sep 2, 2024
2 parents 2b6bf70 + d1a7e20 commit 1916a19
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 57 deletions.
2 changes: 1 addition & 1 deletion module/PSADTree.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
}

# Version number of this module.
ModuleVersion = '1.1.3'
ModuleVersion = '1.1.4'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down
15 changes: 7 additions & 8 deletions src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.DirectoryServices.AccountManagement;
using System.Management.Automation;

namespace PSADTree;
namespace PSADTree.Commands;

[Cmdlet(
VerbsCommon.Get, "ADTreeGroupMember",
Expand Down Expand Up @@ -43,11 +43,11 @@ protected override void ProcessRecord()
}
catch (MultipleMatchesException e)
{
WriteError(ErrorHelper.AmbiguousIdentity(Identity, e));
WriteError(e.AmbiguousIdentity(Identity));
}
catch (Exception e)
{
WriteError(ErrorHelper.Unspecified(Identity, e));
WriteError(e.Unspecified(Identity));
}
}

Expand Down Expand Up @@ -111,7 +111,7 @@ private TreeObjectBase[] Traverse(
}
catch (Exception e)
{
WriteError(ErrorHelper.EnumerationFailure(current, e));
WriteError(e.EnumerationFailure(current));
}
}

Expand All @@ -124,7 +124,7 @@ private void EnumerateMembers(
string source,
int depth)
{
foreach (Principal member in searchResult)
foreach (Principal member in searchResult.GetSortedEnumerable(_comparer))
{
IDisposable? disposable = null;
try
Expand All @@ -135,10 +135,9 @@ private void EnumerateMembers(
continue;
}

if (member is not GroupPrincipal)
if (member.StructuralObjectClass != "group")
{
disposable = member;

if (Group.IsPresent)
{
continue;
Expand Down Expand Up @@ -199,7 +198,7 @@ TreeObjectBase HandleGroup(
return treeGroup;
}

treeGroup = new(source, parent, group, depth);
treeGroup = new TreeGroup(source, parent, group, depth);
Push(group, treeGroup);
return treeGroup;
}
Expand Down
25 changes: 13 additions & 12 deletions src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Management.Automation;

namespace PSADTree;
namespace PSADTree.Commands;

[Cmdlet(
VerbsCommon.Get, "ADTreePrincipalGroupMembership",
Expand Down Expand Up @@ -32,12 +31,12 @@ protected override void ProcessRecord()
}
catch (MultipleMatchesException e)
{
WriteError(ErrorHelper.AmbiguousIdentity(Identity, e));
WriteError(e.AmbiguousIdentity(Identity));
return;
}
catch (Exception e)
{
WriteError(ErrorHelper.Unspecified(Identity, e));
WriteError(e.Unspecified(Identity));
return;
}

Expand Down Expand Up @@ -71,10 +70,11 @@ protected override void ProcessRecord()
try
{
using PrincipalSearchResult<Principal> search = principal.GetGroups();
foreach (GroupPrincipal parent in search.Cast<GroupPrincipal>())
foreach (Principal parent in search)
{
TreeGroup treeGroup = new(source, null, parent, 1);
Push(parent, treeGroup);
GroupPrincipal groupPrincipal = (GroupPrincipal)parent;
TreeGroup treeGroup = new(source, null, groupPrincipal, 1);
Push(groupPrincipal, treeGroup);
}
}
catch (Exception e) when (e is PipelineStoppedException or FlowControlException)
Expand All @@ -83,7 +83,7 @@ protected override void ProcessRecord()
}
catch (Exception e)
{
WriteError(ErrorHelper.EnumerationFailure(null, e));
WriteError(e.EnumerationFailure(null));
}
finally
{
Expand Down Expand Up @@ -149,7 +149,7 @@ private TreeObjectBase[] Traverse(string source)
}
catch (Exception e)
{
WriteError(ErrorHelper.EnumerationFailure(current, e));
WriteError(e.EnumerationFailure(current));
}
}

Expand All @@ -162,9 +162,9 @@ private void EnumerateMembership(
string source,
int depth)
{
foreach (GroupPrincipal group in searchResult.Cast<GroupPrincipal>())
foreach (Principal group in searchResult)
{
TreeGroup treeGroup = ProcessGroup(group);
TreeGroup treeGroup = ProcessGroup((GroupPrincipal)group);
if (ShowAll.IsPresent)
{
parent.AddChild(treeGroup);
Expand Down Expand Up @@ -192,8 +192,9 @@ private void EnumerateMembership(TreeGroup parent, int depth)
return;
}

foreach (TreeGroup group in parent.Childs.Cast<TreeGroup>())
foreach (TreeObjectBase child in parent.Childs)
{
TreeGroup group = (TreeGroup)child;
Push(null, (TreeGroup)group.Clone(parent, depth));
}
}
Expand Down
11 changes: 6 additions & 5 deletions src/PSADTree/ErrorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ internal static ErrorRecord IdentityNotFound(string? identity) =>
ErrorCategory.ObjectNotFound,
identity);

internal static ErrorRecord AmbiguousIdentity(string? identity, Exception exception) =>
internal static ErrorRecord AmbiguousIdentity(this Exception exception, string? identity) =>
new(exception, "AmbiguousIdentity", ErrorCategory.InvalidResult, identity);

internal static ErrorRecord Unspecified(string? identity, Exception exception) =>
internal static ErrorRecord Unspecified(this Exception exception, string? identity) =>
new(exception, "Unspecified", ErrorCategory.NotSpecified, identity);

internal static ErrorRecord EnumerationFailure(
GroupPrincipal? groupPrincipal,
Exception exception) =>
internal static ErrorRecord EnumerationFailure(this Exception exception, GroupPrincipal? groupPrincipal) =>
new(exception, "EnumerationFailure", ErrorCategory.NotSpecified, groupPrincipal);

internal static ErrorRecord SetPrincipalContext(this Exception exception) =>
new(exception, "SetPrincipalContext", ErrorCategory.ConnectionError, null);
}
15 changes: 9 additions & 6 deletions src/PSADTree/PSADTree.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@
<DefineConstants>$(DefineConstants);CORE</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0"
PrivateAssets="all" />
<PackageReference Include="System.Management.Automation" Version="7.2.0" PrivateAssets="all" />
<PackageReference Include="System.DirectoryServices" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="6.0.0"
PrivateAssets="all" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" PrivateAssets="all" />
<Reference Include="System.DirectoryServices" PrivateAssets="all" />
<Reference Include="System.DirectoryServices.AccountManagement" PrivateAssets="all" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" PrivateAssets="all" />
<PackageReference Include="System.Management.Automation" Version="7.2.0" PrivateAssets="all" />
<PackageReference Include="System.DirectoryServices" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="6.0.0" PrivateAssets="all" />
</ItemGroup>
</Project>
7 changes: 4 additions & 3 deletions src/PSADTree/PSADTreeCmdletBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable

internal readonly TreeIndex _index = new();

internal PSADTreeComparer _comparer = new();

[Parameter(
Position = 0,
Mandatory = true,
Expand Down Expand Up @@ -54,10 +56,9 @@ protected override void BeginProcessing()

_context = new PrincipalContext(ContextType.Domain, Server);
}
catch (Exception e)
catch (Exception exception)
{
ThrowTerminatingError(new ErrorRecord(
e, "SetPrincipalContext", ErrorCategory.ConnectionError, null));
ThrowTerminatingError(exception.SetPrincipalContext());
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/PSADTree/PSADTreeComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;

namespace PSADTree;

#pragma warning disable CS8767
internal sealed class PSADTreeComparer : IComparer<Principal>
{
public int Compare(Principal lhs, Principal rhs) =>
lhs.StructuralObjectClass == "group" && rhs.StructuralObjectClass == "group"
? rhs.SamAccountName.CompareTo(lhs.SamAccountName) // Groups in descending order
: lhs.SamAccountName.CompareTo(rhs.SamAccountName); // Other in ascending order
}
2 changes: 1 addition & 1 deletion src/PSADTree/TreeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal sealed class TreeCache
internal TreeGroup this[string distinguishedName] =>
_cache[distinguishedName];

internal TreeCache() => _cache = new();
internal TreeCache() => _cache = [];

internal void Add(TreeGroup treeGroup) =>
_cache.Add(treeGroup.DistinguishedName, treeGroup);
Expand Down
9 changes: 9 additions & 0 deletions src/PSADTree/TreeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

Expand Down Expand Up @@ -58,6 +60,13 @@ internal static TreeObjectBase[] ConvertToTree(
return inputObject;
}

internal static IOrderedEnumerable<Principal> GetSortedEnumerable(
this PrincipalSearchResult<Principal> search, PSADTreeComparer comparer) =>
search
.OrderBy(static e => e.StructuralObjectClass == "group")
.ThenBy(static e => e, comparer);


private static void UpdateCorner(int index, TreeObjectBase current)
{
if (current.Hierarchy[index] == '└')
Expand Down
27 changes: 15 additions & 12 deletions src/PSADTree/TreeGroup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.DirectoryServices.AccountManagement;
using System.Text;

namespace PSADTree;

Expand All @@ -14,9 +16,11 @@ public sealed class TreeGroup : TreeObjectBase

private const string _vtReset = "\x1B[0m";

private static readonly StringBuilder s_sb = new();

private List<TreeObjectBase>? _childs;

public ReadOnlyCollection<TreeObjectBase> Childs => new(_childs ??= new());
public ReadOnlyCollection<TreeObjectBase> Childs => new(_childs ??= []);

public bool IsCircular { get; private set; }

Expand Down Expand Up @@ -46,23 +50,22 @@ internal TreeGroup(
internal void SetCircularNested()
{
IsCircular = true;
Hierarchy = string.Concat(
Hierarchy.Insert(
Hierarchy.IndexOf("─ ") + 2,
_vtBrightRed),
_isCircular,
_vtReset);
Hierarchy = s_sb
.Append(Hierarchy.Insert(Hierarchy.IndexOf("─ ") + 2, _vtBrightRed))
.Append(_isCircular)
.Append(_vtReset)
.ToString();

s_sb.Clear();
}

internal void SetProcessed() =>
Hierarchy = string.Concat(Hierarchy, _isProcessed);
internal void SetProcessed() => Hierarchy = string.Concat(Hierarchy, _isProcessed);

internal void Hook(TreeCache cache) =>
_childs ??= cache[DistinguishedName]._childs;
internal void Hook(TreeCache cache) => _childs ??= cache[DistinguishedName]._childs;

internal void AddChild(TreeObjectBase child)
{
_childs ??= new();
_childs ??= [];
_childs.Add(child);
}

Expand Down
15 changes: 6 additions & 9 deletions src/PSADTree/TreeIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,24 @@ internal sealed class TreeIndex

internal TreeIndex()
{
_principals = new();
_output = new();
_principals = [];
_output = [];
}

internal void AddPrincipal(TreeObjectBase principal) =>
_principals.Add(principal);
internal void AddPrincipal(TreeObjectBase principal) => _principals.Add(principal);

internal void Add(TreeObjectBase principal) =>
_output.Add(principal);
internal void Add(TreeObjectBase principal) => _output.Add(principal);

internal void TryAddPrincipals()
{
if (_principals.Count > 0)
{
_output.AddRange(_principals.ToArray());
_output.AddRange([.. _principals]);
_principals.Clear();
}
}

internal TreeObjectBase[] GetTree() =>
_output.ToArray().ConvertToTree();
internal TreeObjectBase[] GetTree() => _output.ToArray().ConvertToTree();

internal void Clear()
{
Expand Down

0 comments on commit 1916a19

Please sign in to comment.