From 81edd2739c313466972888019d97e09015d44b8f Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Fri, 6 Sep 2024 10:39:45 -0400 Subject: [PATCH 01/13] update docs --- docs/en-US/Get-ADTreeGroupMember.md | 2 +- docs/en-US/Get-ADTreePrincipalGroupMembership.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en-US/Get-ADTreeGroupMember.md b/docs/en-US/Get-ADTreeGroupMember.md index f4c7be0..b4ef6d5 100644 --- a/docs/en-US/Get-ADTreeGroupMember.md +++ b/docs/en-US/Get-ADTreeGroupMember.md @@ -102,7 +102,7 @@ The `-ShowAll` switch indicates that the cmdlet should display the hierarchy of ### -Depth Determines the number of nested groups and their members included in the recursion. -By default, only 3 levels of recursion are included. +By default, only 3 levels of recursion are included. `Get-ADTreeGroupMember` emits a warning if the levels exceed this number. ```yaml Type: Int32 diff --git a/docs/en-US/Get-ADTreePrincipalGroupMembership.md b/docs/en-US/Get-ADTreePrincipalGroupMembership.md index 261b33e..93ee83c 100644 --- a/docs/en-US/Get-ADTreePrincipalGroupMembership.md +++ b/docs/en-US/Get-ADTreePrincipalGroupMembership.md @@ -98,7 +98,7 @@ The `-ShowAll` switch indicates that the cmdlet should display the hierarchy of ### -Depth Determines the number of nested group memberships included in the recursion. -By default, only 3 levels of recursion are included. +By default, only 3 levels of recursion are included. `Get-ADTreePrincipalGroupMembership` emits a warning if the levels exceed this number. ```yaml Type: Int32 From 9fbaaca7dde987561ea4b2ff5c0f4c677a1c9eb3 Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Fri, 6 Sep 2024 10:40:40 -0400 Subject: [PATCH 02/13] add truncate warning --- src/PSADTree/PSADTreeCmdletBase.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index ebbebf0..a75833b 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -16,6 +16,8 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable private bool _disposed; + private bool _truncateWritten; + protected readonly Stack<(GroupPrincipal? group, TreeGroup treeGroup)> _stack = new(); internal readonly TreeCache _cache = new(); @@ -87,6 +89,14 @@ protected void Push(GroupPrincipal? groupPrincipal, TreeGroup treeGroup) { _stack.Push((groupPrincipal, treeGroup)); } + else + { + if (!_truncateWritten) + { + this.WriteWarning($"Result is truncated as enumeration has exceeded the set depth of {Depth}."); + _truncateWritten = true; + } + } } private static bool MatchAny( From d6ef8a145ca7b9ef91a10a9b82f57f6888534d04 Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Fri, 6 Sep 2024 11:55:28 -0400 Subject: [PATCH 03/13] add Credential parameter --- src/PSADTree/PSADTreeCmdletBase.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index a75833b..ae66a8e 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -32,7 +32,6 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable | WildcardOptions.CultureInvariant | WildcardOptions.IgnoreCase; - [Parameter( Position = 0, Mandatory = true, @@ -44,6 +43,10 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable [Parameter] public string? Server { get; set; } + [Parameter(ValueFromPipelineByPropertyName = true)] + [Credential] + public PSCredential? Credential { get; set; } + [Parameter(ParameterSetName = DepthParameterSet)] [ValidateRange(0, int.MaxValue)] public int Depth { get; set; } = 3; @@ -75,6 +78,16 @@ protected override void BeginProcessing() return; } + if (Credential is not null) + { + _context = new PrincipalContext( + ContextType.Domain, + Server, + Credential.UserName, + Credential.GetNetworkCredential().Password); + return; + } + _context = new PrincipalContext(ContextType.Domain, Server); } catch (Exception exception) From 83ee2a88c91cf2101e3ff9937f73380367f767ed Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Fri, 6 Sep 2024 12:29:03 -0400 Subject: [PATCH 04/13] fix conditional for truncate --- src/PSADTree/PSADTreeCmdletBase.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index ae66a8e..2c8b12e 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -98,17 +98,15 @@ protected override void BeginProcessing() protected void Push(GroupPrincipal? groupPrincipal, TreeGroup treeGroup) { - if (Recursive.IsPresent || treeGroup.Depth <= Depth) + if (!Recursive.IsPresent && treeGroup.Depth >= Depth && !_truncateWritten) { - _stack.Push((groupPrincipal, treeGroup)); + this.WriteWarning($"Result is truncated as enumeration has exceeded the set depth of {Depth}."); + _truncateWritten = true; } - else + + if (Recursive.IsPresent || treeGroup.Depth <= Depth) { - if (!_truncateWritten) - { - this.WriteWarning($"Result is truncated as enumeration has exceeded the set depth of {Depth}."); - _truncateWritten = true; - } + _stack.Push((groupPrincipal, treeGroup)); } } From a643c271d547d9dbfa5cf9260e161fd5c71bf467 Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Fri, 6 Sep 2024 12:53:45 -0400 Subject: [PATCH 05/13] fix cannot contact domain --- .../Commands/GetADTreePrincipalGroupMembershipCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs index 539812c..3a24a2e 100644 --- a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs +++ b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs @@ -69,7 +69,7 @@ protected override void ProcessRecord() try { - using PrincipalSearchResult search = principal.GetGroups(); + using PrincipalSearchResult search = principal.GetGroups(_context); foreach (Principal parent in search.GetSortedEnumerable(_comparer)) { if (ShouldExclude(parent, _exclusionPatterns)) @@ -138,7 +138,7 @@ private TreeObjectBase[] Traverse(string source) continue; } - using PrincipalSearchResult? search = current?.GetGroups(); + using PrincipalSearchResult? search = current?.GetGroups(_context); if (search is not null) { From 3758f6ad22caa808e54eec313cd6259794c19539 Mon Sep 17 00:00:00 2001 From: Santiago Squarzon Date: Fri, 6 Sep 2024 16:27:12 -0300 Subject: [PATCH 06/13] changed the logic so the warning message is displayed before each tree. --- .../Commands/GetADTreeGroupMemberCommand.cs | 28 +++++++++--------- ...etADTreePrincipalGroupMembershipCommand.cs | 29 ++++++++++--------- src/PSADTree/PSADTreeCmdletBase.cs | 17 +++++++---- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs index 1386e09..de68ed8 100644 --- a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs +++ b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs @@ -31,23 +31,25 @@ protected override void ProcessRecord() return; } - WriteObject( - sendToPipeline: Traverse( - groupPrincipal: group, - source: group.DistinguishedName), - enumerateCollection: true); + _truncatedOutput = false; + TreeObjectBase[] result = Traverse( + groupPrincipal: group, + source: group.DistinguishedName); + + DisplayWarningIfTruncatedOutput(); + WriteObject(sendToPipeline: result, enumerateCollection: true); } - catch (Exception e) when (e is PipelineStoppedException or FlowControlException) + catch (Exception _) when (_ is PipelineStoppedException or FlowControlException) { throw; } - catch (MultipleMatchesException e) + catch (MultipleMatchesException exception) { - WriteError(e.AmbiguousIdentity(Identity)); + WriteError(exception.AmbiguousIdentity(Identity)); } - catch (Exception e) + catch (Exception exception) { - WriteError(e.Unspecified(Identity)); + WriteError(exception.Unspecified(Identity)); } } @@ -105,13 +107,13 @@ private TreeObjectBase[] Traverse( _index.TryAddPrincipals(); current?.Dispose(); } - catch (Exception e) when (e is PipelineStoppedException or FlowControlException) + catch (Exception _) when (_ is PipelineStoppedException or FlowControlException) { throw; } - catch (Exception e) + catch (Exception exception) { - WriteError(e.EnumerationFailure(current)); + WriteError(exception.EnumerationFailure(current)); } } diff --git a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs index 3a24a2e..2ed1133 100644 --- a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs +++ b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs @@ -25,18 +25,18 @@ protected override void ProcessRecord() { principal = Principal.FindByIdentity(_context, Identity); } - catch (Exception e) when (e is PipelineStoppedException or FlowControlException) + catch (Exception _) when (_ is PipelineStoppedException or FlowControlException) { throw; } - catch (MultipleMatchesException e) + catch (MultipleMatchesException exception) { - WriteError(e.AmbiguousIdentity(Identity)); + WriteError(exception.AmbiguousIdentity(Identity)); return; } - catch (Exception e) + catch (Exception exception) { - WriteError(e.Unspecified(Identity)); + WriteError(exception.Unspecified(Identity)); return; } @@ -82,22 +82,23 @@ protected override void ProcessRecord() Push(groupPrincipal, treeGroup); } } - catch (Exception e) when (e is PipelineStoppedException or FlowControlException) + catch (Exception _) when (_ is PipelineStoppedException or FlowControlException) { throw; } - catch (Exception e) + catch (Exception exception) { - WriteError(e.EnumerationFailure(null)); + WriteError(exception.EnumerationFailure(null)); } finally { principal?.Dispose(); } - WriteObject( - sendToPipeline: Traverse(source), - enumerateCollection: true); + _truncatedOutput = false; + TreeObjectBase[] result = Traverse(source); + DisplayWarningIfTruncatedOutput(); + WriteObject(sendToPipeline: result, enumerateCollection: true); } private TreeObjectBase[] Traverse(string source) @@ -148,13 +149,13 @@ private TreeObjectBase[] Traverse(string source) _index.Add(treeGroup); current?.Dispose(); } - catch (Exception e) when (e is PipelineStoppedException or FlowControlException) + catch (Exception _) when (_ is PipelineStoppedException or FlowControlException) { throw; } - catch (Exception e) + catch (Exception exception) { - WriteError(e.EnumerationFailure(current)); + WriteError(exception.EnumerationFailure(current)); } } diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index 2c8b12e..e3db3c2 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -16,7 +16,7 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable private bool _disposed; - private bool _truncateWritten; + protected bool _truncatedOutput; protected readonly Stack<(GroupPrincipal? group, TreeGroup treeGroup)> _stack = new(); @@ -98,15 +98,20 @@ protected override void BeginProcessing() protected void Push(GroupPrincipal? groupPrincipal, TreeGroup treeGroup) { - if (!Recursive.IsPresent && treeGroup.Depth >= Depth && !_truncateWritten) + if (Recursive.IsPresent || treeGroup.Depth <= Depth) { - this.WriteWarning($"Result is truncated as enumeration has exceeded the set depth of {Depth}."); - _truncateWritten = true; + _stack.Push((groupPrincipal, treeGroup)); + return; } - if (Recursive.IsPresent || treeGroup.Depth <= Depth) + _truncatedOutput = true; + } + + protected void DisplayWarningIfTruncatedOutput() + { + if (_truncatedOutput) { - _stack.Push((groupPrincipal, treeGroup)); + WriteWarning($"Result is truncated as enumeration has exceeded the set depth of {Depth}."); } } From f5f9f13f638b1ee393e02d5bada73ddfe4a79372 Mon Sep 17 00:00:00 2001 From: Santiago Squarzon Date: Fri, 6 Sep 2024 20:14:07 -0300 Subject: [PATCH 07/13] add throw when Credential is used without Server --- .../Commands/GetADTreeGroupMemberCommand.cs | 2 +- ...etADTreePrincipalGroupMembershipCommand.cs | 2 +- .../{ErrorHelper.cs => Exceptions.cs} | 9 +++++++- src/PSADTree/PSADTreeCmdletBase.cs | 21 ++++++++++++------- 4 files changed, 23 insertions(+), 11 deletions(-) rename src/PSADTree/{ErrorHelper.cs => Exceptions.cs} (78%) diff --git a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs index de68ed8..7e6a6a7 100644 --- a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs +++ b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs @@ -27,7 +27,7 @@ protected override void ProcessRecord() using GroupPrincipal? group = GroupPrincipal.FindByIdentity(_context, Identity); if (group is null) { - WriteError(ErrorHelper.IdentityNotFound(Identity)); + WriteError(Exceptions.IdentityNotFound(Identity)); return; } diff --git a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs index 2ed1133..5528e7a 100644 --- a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs +++ b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs @@ -42,7 +42,7 @@ protected override void ProcessRecord() if (principal is null) { - WriteError(ErrorHelper.IdentityNotFound(Identity)); + WriteError(Exceptions.IdentityNotFound(Identity)); return; } diff --git a/src/PSADTree/ErrorHelper.cs b/src/PSADTree/Exceptions.cs similarity index 78% rename from src/PSADTree/ErrorHelper.cs rename to src/PSADTree/Exceptions.cs index 10e0cb3..8f8e87a 100644 --- a/src/PSADTree/ErrorHelper.cs +++ b/src/PSADTree/Exceptions.cs @@ -4,7 +4,7 @@ namespace PSADTree; -internal static class ErrorHelper +internal static class Exceptions { internal static ErrorRecord IdentityNotFound(string? identity) => new( @@ -13,6 +13,13 @@ internal static ErrorRecord IdentityNotFound(string? identity) => ErrorCategory.ObjectNotFound, identity); + internal static ErrorRecord CredentialRequiresServer() => + new( + new ArgumentException("Server parameter is required when Credential parameter is used."), + "CredentialRequiresServer", + ErrorCategory.InvalidOperation, + null); + internal static ErrorRecord AmbiguousIdentity(this Exception exception, string? identity) => new(exception, "AmbiguousIdentity", ErrorCategory.InvalidResult, identity); diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index e3db3c2..016bb75 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -72,23 +72,28 @@ protected override void BeginProcessing() .ToArray(); } - if (Server is null) + if (Credential is null && Server is null) { _context = new PrincipalContext(ContextType.Domain); return; } - if (Credential is not null) + if (Server is null) + { + ThrowTerminatingError(Exceptions.CredentialRequiresServer()); + } + + if (Credential is null) { - _context = new PrincipalContext( - ContextType.Domain, - Server, - Credential.UserName, - Credential.GetNetworkCredential().Password); + _context = new PrincipalContext(ContextType.Domain, Server); return; } - _context = new PrincipalContext(ContextType.Domain, Server); + _context = new PrincipalContext( + ContextType.Domain, + Server, + Credential.UserName, + Credential.GetNetworkCredential().Password); } catch (Exception exception) { From cd8506eb01d03435d46ddad77a7b9494fea968e2 Mon Sep 17 00:00:00 2001 From: Santiago Squarzon Date: Fri, 6 Sep 2024 20:19:50 -0300 Subject: [PATCH 08/13] ValueFromPipelineByPropertyName has no effect in BeginProcessing Method. Can be removed. --- src/PSADTree/PSADTreeCmdletBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index 016bb75..418a84e 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -43,7 +43,7 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable [Parameter] public string? Server { get; set; } - [Parameter(ValueFromPipelineByPropertyName = true)] + [Parameter] [Credential] public PSCredential? Credential { get; set; } From 6cd34797b5221347543ad280d2512c0139d8a060 Mon Sep 17 00:00:00 2001 From: Santiago Squarzon Date: Fri, 6 Sep 2024 20:59:38 -0300 Subject: [PATCH 09/13] few changes related to depth and recursive checks, hopefully this works --- .../Commands/GetADTreeGroupMemberCommand.cs | 5 ++--- .../GetADTreePrincipalGroupMembershipCommand.cs | 2 +- src/PSADTree/PSADTreeCmdletBase.cs | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs index 7e6a6a7..9d7a5f0 100644 --- a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs +++ b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs @@ -185,7 +185,7 @@ private TreeObjectBase ProcessPrincipal( TreeObjectBase AddTreeObject(TreeObjectBase obj) { - if (Recursive.IsPresent || depth <= Depth) + if (depth <= Depth) { _index.AddPrincipal(obj); } @@ -213,7 +213,6 @@ TreeObjectBase HandleGroup( private void EnumerateMembers(TreeGroup parent, int depth) { - bool shouldProcess = Recursive.IsPresent || depth <= Depth; foreach (TreeObjectBase member in parent.Childs) { if (member is TreeGroup treeGroup) @@ -222,7 +221,7 @@ private void EnumerateMembers(TreeGroup parent, int depth) continue; } - if (shouldProcess) + if (depth <= Depth) { _index.Add(member.Clone(parent, depth)); } diff --git a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs index 5528e7a..3c8d4e7 100644 --- a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs +++ b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs @@ -198,7 +198,7 @@ TreeGroup ProcessGroup(GroupPrincipal group) private void EnumerateMembership(TreeGroup parent, int depth) { - if (!Recursive.IsPresent && depth > Depth) + if (depth > Depth) { return; } diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index 418a84e..f5c7160 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -65,6 +65,11 @@ protected override void BeginProcessing() { try { + if (Recursive.IsPresent) + { + Depth = int.MaxValue; + } + if (Exclude is not null) { _exclusionPatterns = Exclude @@ -103,13 +108,17 @@ protected override void BeginProcessing() protected void Push(GroupPrincipal? groupPrincipal, TreeGroup treeGroup) { - if (Recursive.IsPresent || treeGroup.Depth <= Depth) + if (treeGroup.Depth > Depth) { - _stack.Push((groupPrincipal, treeGroup)); return; } - _truncatedOutput = true; + if (treeGroup.Depth == Depth) + { + _truncatedOutput = true; + } + + _stack.Push((groupPrincipal, treeGroup)); } protected void DisplayWarningIfTruncatedOutput() From 82efac0672b817102ab87aea9e124ec888bd0197 Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Fri, 6 Sep 2024 20:33:52 -0400 Subject: [PATCH 10/13] move _truncatedOutput to start of ProcessRecord --- src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs | 2 +- .../Commands/GetADTreePrincipalGroupMembershipCommand.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs index 9d7a5f0..1c32970 100644 --- a/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs +++ b/src/PSADTree/Commands/GetADTreeGroupMemberCommand.cs @@ -21,6 +21,7 @@ protected override void ProcessRecord() { Dbg.Assert(Identity is not null); Dbg.Assert(_context is not null); + _truncatedOutput = false; try { @@ -31,7 +32,6 @@ protected override void ProcessRecord() return; } - _truncatedOutput = false; TreeObjectBase[] result = Traverse( groupPrincipal: group, source: group.DistinguishedName); diff --git a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs index 3c8d4e7..bf00155 100644 --- a/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs +++ b/src/PSADTree/Commands/GetADTreePrincipalGroupMembershipCommand.cs @@ -18,6 +18,7 @@ protected override void ProcessRecord() { Dbg.Assert(Identity is not null); Dbg.Assert(_context is not null); + _truncatedOutput = false; Principal? principal; Clear(); @@ -95,7 +96,6 @@ protected override void ProcessRecord() principal?.Dispose(); } - _truncatedOutput = false; TreeObjectBase[] result = Traverse(source); DisplayWarningIfTruncatedOutput(); WriteObject(sendToPipeline: result, enumerateCollection: true); From d952d5aa5561ce950361f227f035e29e96931db6 Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Sat, 7 Sep 2024 13:16:05 -0400 Subject: [PATCH 11/13] UserPrincipal.GetGroups(PrincipalContext) throws on .Bind() if name is null --- src/PSADTree/PSADTreeCmdletBase.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/PSADTree/PSADTreeCmdletBase.cs b/src/PSADTree/PSADTreeCmdletBase.cs index f5c7160..d7c9bf5 100644 --- a/src/PSADTree/PSADTreeCmdletBase.cs +++ b/src/PSADTree/PSADTreeCmdletBase.cs @@ -41,7 +41,7 @@ public abstract class PSADTreeCmdletBase : PSCmdlet, IDisposable public string? Identity { get; set; } [Parameter] - public string? Server { get; set; } + public string Server { get; set; } = Environment.UserDomainName; [Parameter] [Credential] @@ -77,17 +77,6 @@ protected override void BeginProcessing() .ToArray(); } - if (Credential is null && Server is null) - { - _context = new PrincipalContext(ContextType.Domain); - return; - } - - if (Server is null) - { - ThrowTerminatingError(Exceptions.CredentialRequiresServer()); - } - if (Credential is null) { _context = new PrincipalContext(ContextType.Domain, Server); From 8e0b33dd09f692491aee282440223256c318708c Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Sat, 7 Sep 2024 13:33:07 -0400 Subject: [PATCH 12/13] update docs --- docs/en-US/Get-ADTreeGroupMember.md | 70 ++++++++++++------- .../Get-ADTreePrincipalGroupMembership.md | 68 ++++++++++++------ 2 files changed, 91 insertions(+), 47 deletions(-) diff --git a/docs/en-US/Get-ADTreeGroupMember.md b/docs/en-US/Get-ADTreeGroupMember.md index b4ef6d5..74d45a1 100644 --- a/docs/en-US/Get-ADTreeGroupMember.md +++ b/docs/en-US/Get-ADTreeGroupMember.md @@ -1,4 +1,4 @@ ---- +--- external help file: PSADTree.dll-Help.xml Module Name: PSADTree online version: @@ -20,6 +20,7 @@ Get-ADTreeGroupMember [-Group] [-Identity] [-Server ] + [-Credential ] [-Depth ] [-ShowAll] [-Exclude ] @@ -33,6 +34,7 @@ Get-ADTreeGroupMember [-Group] [-Identity] [-Server ] + [-Credential ] [-Recursive] [-ShowAll] [-Exclude ] @@ -99,6 +101,24 @@ The `-ShowAll` switch indicates that the cmdlet should display the hierarchy of ## PARAMETERS +### -Credential + +Specifies a user account that has permission to perform this action. The default is the current user. + +Type a user name, such as **User01** or **Domain01\User01**, or enter a **PSCredential** object generated by the `Get-Credential` cmdlet. If you type a user name, you're prompted to enter the password. + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Depth Determines the number of nested groups and their members included in the recursion. @@ -116,6 +136,29 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Exclude + +Specifies an array of one or more string patterns to be matched as the cmdlet enumerates child principals. +Any matching principal is excluded from the output. +Wildcard characters are accepted. + +> [!NOTE] +> +> - Patterns are tested against the principal's `.SamAccountName` property. +> - When the matched principal is of type `group`, all child principals are also excluded from the output. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + ### -Group The `-Group` switch indicates that the cmdlet should display nested group members only. Essentially, a built-in filter where [`ObjectClass`](https://learn.microsoft.com/en-us/windows/win32/adschema/a-objectclass) is `group`. @@ -222,29 +265,6 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Exclude - -Specifies an array of one or more string patterns to be matched as the cmdlet enumerates child principals. -Any matching principal is excluded from the output. -Wildcard characters are accepted. - -> [!NOTE] -> -> - Patterns are tested against the principal's `.SamAccountName` property. -> - When the matched principal is of type `group`, all child principals are also excluded from the output. - -```yaml -Type: String[] -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: True -``` - ### CommonParameters This cmdlet supports the common parameters. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). @@ -266,3 +286,5 @@ You can pipe strings containing an identity to this cmdlet. [__`ADGroup`__](http ## NOTES `treegroupmember` is the alias for this cmdlet. + +## RELATED LINKS diff --git a/docs/en-US/Get-ADTreePrincipalGroupMembership.md b/docs/en-US/Get-ADTreePrincipalGroupMembership.md index 93ee83c..c7b2d64 100644 --- a/docs/en-US/Get-ADTreePrincipalGroupMembership.md +++ b/docs/en-US/Get-ADTreePrincipalGroupMembership.md @@ -1,4 +1,4 @@ ---- +--- external help file: PSADTree.dll-Help.xml Module Name: PSADTree online version: @@ -19,6 +19,7 @@ schema: 2.0.0 Get-ADTreePrincipalGroupMembership [-Identity] [-Server ] + [-Credential ] [-Depth ] [-ShowAll] [-Exclude ] @@ -31,6 +32,7 @@ Get-ADTreePrincipalGroupMembership Get-ADTreePrincipalGroupMembership [-Identity] [-Server ] + [-Credential ] [-Recursive] [-ShowAll] [-Exclude ] @@ -95,6 +97,24 @@ The `-ShowAll` switch indicates that the cmdlet should display the hierarchy of ## PARAMETERS +### -Credential + +Specifies a user account that has permission to perform this action. The default is the current user. + +Type a user name, such as **User01** or **Domain01\User01**, or enter a **PSCredential** object generated by the `Get-Credential` cmdlet. If you type a user name, you're prompted to enter the password. + +```yaml +Type: PSCredential +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Depth Determines the number of nested group memberships included in the recursion. @@ -112,6 +132,28 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Exclude + +Specifies an array of one or more string patterns to be matched as the cmdlet enumerates child principals. +Any matching principal is excluded from the output. +Wildcard characters are accepted. + +> [!NOTE] +> +> Patterns are tested against the principal's `.SamAccountName` property. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: True +``` + ### -Identity Specifies an Active Directory principal by providing one of the following property values: @@ -202,28 +244,6 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -Exclude - -Specifies an array of one or more string patterns to be matched as the cmdlet enumerates child principals. -Any matching principal is excluded from the output. -Wildcard characters are accepted. - -> [!NOTE] -> -> Patterns are tested against the principal's `.SamAccountName` property. - -```yaml -Type: String[] -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: True -``` - ### CommonParameters This cmdlet supports the common parameters. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). @@ -245,3 +265,5 @@ You can pipe strings containing an identity to this cmdlet. [`ADObject`](https:/ ## NOTES `treeprincipalmembership` is the alias for this cmdlet. + +## RELATED LINKS From 98838093ab5385d768f5450a86c63620984c6cb2 Mon Sep 17 00:00:00 2001 From: PoshAJ <19650958-PoshAJ@users.noreply.gitlab.com> Date: Sat, 7 Sep 2024 13:43:29 -0400 Subject: [PATCH 13/13] remove CredentialRequiresServer --- src/PSADTree/Exceptions.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/PSADTree/Exceptions.cs b/src/PSADTree/Exceptions.cs index 8f8e87a..8537db3 100644 --- a/src/PSADTree/Exceptions.cs +++ b/src/PSADTree/Exceptions.cs @@ -13,13 +13,6 @@ internal static ErrorRecord IdentityNotFound(string? identity) => ErrorCategory.ObjectNotFound, identity); - internal static ErrorRecord CredentialRequiresServer() => - new( - new ArgumentException("Server parameter is required when Credential parameter is used."), - "CredentialRequiresServer", - ErrorCategory.InvalidOperation, - null); - internal static ErrorRecord AmbiguousIdentity(this Exception exception, string? identity) => new(exception, "AmbiguousIdentity", ErrorCategory.InvalidResult, identity);