Skip to content

Commit ec84911

Browse files
Initial Command set
1 parent 6146b89 commit ec84911

12 files changed

+685
-7
lines changed

ADSec/ADSec.psd1

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
RootModule = 'ADSec.psm1'
44

55
# Version number of this module.
6-
ModuleVersion = '1.0.0'
6+
ModuleVersion = '0.1.0'
77

88
# ID used to uniquely identify this module
99
GUID = '1cfaca0a-3c7d-47dd-bb9f-9711310a0b9d'
@@ -39,7 +39,12 @@
3939
# FormatsToProcess = @('xml\ADSec.Format.ps1xml')
4040

4141
# Functions to export from this module
42-
FunctionsToExport = ''
42+
FunctionsToExport = @(
43+
'Get-AdsAcl'
44+
'Get-AdsOrphanAce'
45+
'Remove-AdsOrphanAce'
46+
'Set-AdsAcl'
47+
)
4348

4449
# Cmdlets to export from this module
4550
CmdletsToExport = ''

ADSec/changelog.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
# Changelog
2-
## 1.0.0 (2019-10-01)
3-
- New: Some Stuff
4-
- Upd: Moar Stuff
5-
- Fix: Much Stuff
2+
## 1.0.0 (2019-10-08)
3+
- Initial Release

ADSec/en-us/strings.psd1

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# This is where the strings go, that are written by
22
# Write-PSFMessage, Stop-PSFFunction or the PSFramework validation scriptblocks
33
@{
4-
'key' = 'Value'
4+
'Assert-ADConnection.Failed' = 'Failed to connect to {0} as {1}' # $target, $userName
5+
'Get-AdsAcl.ObjectError' = 'Error accessing item: {0}' # $pathItem
6+
'Get-LdapObject.CredentialError' = 'Invalid username/password' #
7+
'Get-LdapObject.SearchError' = 'Failed to execute ldap request.' #
8+
'Get-LdapObject.Searchfilter' = 'Searching with filter: {0}' # $LdapFilter
9+
'Get-LdapObject.SearchRoot' = 'Searching {0} in {1}' # $SearchScope, $searcher.SearchRoot.Path
10+
'Set-AdsAcl.SettingSecurity' = 'Updating security settings' #
11+
'Set-AdsOwner.AlreadyOwned' = '{0} is already owned by {1}' # $pathItem, $idReference
12+
'Set-AdsOwner.UnresolvedIdentity' = 'Failed to resolve Identity: {0}' # $Identity
13+
'Set-AdsOwner.UpdatingOwner' = 'Updating owner to {0}' # $idReference
514
}

ADSec/functions/acl/Get-AdsAcl.ps1

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
function Get-AdsAcl
2+
{
3+
<#
4+
.SYNOPSIS
5+
Reads the ACL from an AD object.
6+
7+
.DESCRIPTION
8+
Reads the ACL from an AD object.
9+
Allows specifying the server to ask.
10+
11+
.PARAMETER Path
12+
The DistinguishedName path to the item.
13+
14+
.PARAMETER Server
15+
The server / domain to connect to.
16+
17+
.PARAMETER Credential
18+
The credentials to use for AD operations.
19+
20+
.PARAMETER EnableException
21+
This parameters disables user-friendly warnings and enables the throwing of exceptions.
22+
This is less user friendly, but allows catching exceptions in calling scripts.
23+
24+
.EXAMPLE
25+
PS C:\> Get-ADUser -Filter * | Get-AdsAcl
26+
27+
Returns the ACL of every user in the domain.
28+
#>
29+
[OutputType([System.DirectoryServices.ActiveDirectorySecurity])]
30+
[CmdletBinding()]
31+
param (
32+
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
33+
[Alias('DistinguishedName')]
34+
[string[]]
35+
$Path,
36+
37+
[string]
38+
$Server,
39+
40+
[System.Management.Automation.PSCredential]
41+
$Credential,
42+
43+
[switch]
44+
$EnableException
45+
)
46+
47+
begin
48+
{
49+
$adParameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Credential
50+
Assert-ADConnection @adParameters -Cmdlet $PSCmdlet
51+
}
52+
process
53+
{
54+
if (Test-PSFFunctionInterrupt) { return }
55+
56+
foreach ($pathItem in $Path)
57+
{
58+
try { $adObject = Get-ADObject @adParameters -Identity $pathItem -Properties ntSecurityDescriptor }
59+
catch { Stop-PSFFunction -String 'Get-AdsAcl.ObjectError' -StringValues $pathItem -Target $pathItem -EnableException $EnableException -Cmdlet $PSCmdlet -ErrorRecord $_ -Continue }
60+
$adObject.ntSecurityDescriptor | Add-Member -MemberType NoteProperty -Name DistinguishedName -Value $adObject.DistinguishedName -PassThru
61+
}
62+
}
63+
}
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
function Get-AdsOrphanAce
2+
{
3+
<#
4+
.SYNOPSIS
5+
Returns list of all access rules that have an unresolveable identity.
6+
7+
.DESCRIPTION
8+
Returns list of all access rules that have an unresolveable identity.
9+
This is aimed at identifying and help remediating orphaned SIDs in active directory.
10+
11+
.PARAMETER Path
12+
The full distinguished name to the object to scan.
13+
14+
.PARAMETER ExcludeDomainSID
15+
SIDs from the specified domain SIDs will be ignored.
16+
Use this to safely handle one-way trust where ID resolution is impossible for some IDs.
17+
18+
.PARAMETER IncludeDomainSID
19+
If specified, only unresolved identities from the specified SIDs will be listed.
20+
Use this to safely target only rules from your owned domains in the targeted domain.
21+
22+
.PARAMETER Server
23+
The server / domain to connect to.
24+
25+
.PARAMETER Credential
26+
The credentials to use for AD operations.
27+
28+
.PARAMETER EnableException
29+
This parameters disables user-friendly warnings and enables the throwing of exceptions.
30+
This is less user friendly, but allows catching exceptions in calling scripts.
31+
32+
.EXAMPLE
33+
PS C:\> Get-ADObject -LDAPFillter '(objectCategory=*)' | Get-AdsOrphanAce
34+
35+
Scans all objects in the current domain for orphaned access rules.
36+
#>
37+
[CmdletBinding()]
38+
param (
39+
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
40+
[string[]]
41+
$Path,
42+
43+
[string[]]
44+
$ExcludeDomainSID,
45+
46+
[string[]]
47+
$IncludeDomainSID,
48+
49+
[string]
50+
$Server,
51+
52+
[System.Management.Automation.PSCredential]
53+
$Credential,
54+
55+
[switch]
56+
$EnableException
57+
)
58+
59+
begin
60+
{
61+
$adParameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Credential
62+
Assert-ADConnection @adParameters -Cmdlet $PSCmdlet
63+
64+
function Write-Result
65+
{
66+
[CmdletBinding()]
67+
param (
68+
[string]
69+
$Path,
70+
71+
[System.DirectoryServices.ActiveDirectoryAccessRule]
72+
$AccessRule
73+
)
74+
75+
[PSCustomObject]@{
76+
PSTypeName = 'ADSec.AccessRule'
77+
Path = $Path
78+
Identity = $AccessRule.IdentityReference
79+
ADRights = $AccessRule.ActiveDirectoryRights
80+
Type = $AccessRule.AccessControlType
81+
ObjectType = $AccessRule.ObjectType
82+
InheritedOpectType = $AccessRule.InheritedObjectType
83+
Rule = $AccessRule
84+
}
85+
}
86+
87+
# Wrap as nested pipeline to avoid asserting connection each time
88+
$scriptCmd = { Get-AdsAcl @adParameters -EnableException:$EnableException }
89+
$getAdsAcl = $scriptCmd.GetSteppablePipeline()
90+
$getAdsAcl.Begin($true)
91+
}
92+
process
93+
{
94+
foreach ($pathItem in $Path)
95+
{
96+
try { $getAdsAcl.Process($pathItem) }
97+
catch { Stop-PSFFunction -String 'Get-AdsOrphanAce.Read.Failed' -StringValues $pathItem -EnableException $EnableException -ErrorRecord $_ -Cmdlet $PSCmdlet -Continue }
98+
if (-not $acl) { Stop-PSFFunction -String 'Get-AdsOrphanAce.Read.Failed' -StringValues $pathItem -EnableException $EnableException -Cmdlet $PSCmdlet -Continue }
99+
100+
foreach ($rule in $acl.Access)
101+
{
102+
if ($rule.IdentityReference -is [System.Security.Principal.NTAccount]) { continue }
103+
104+
if ($rule.IdentityReference.AccountDomainSID.Value -in $ExcludeDomainSID) { continue }
105+
if ($IncludeDomainSID -and ($rule.IdentityReference.AccountDomainSID.Value -notin $IncludeDomainSID)) { continue }
106+
107+
try { $null = $rule.IdentityReference.Translate([System.Security.Principal.NTAccount]) }
108+
catch { Write-Result -Path $pathItem -AccessRule $rule }
109+
}
110+
}
111+
}
112+
end
113+
{
114+
$getAdsAcl.End()
115+
}
116+
}
+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
function Remove-AdsOrphanAce
2+
{
3+
<#
4+
.SYNOPSIS
5+
Removes all access rules that have an unresolveable identity.
6+
7+
.DESCRIPTION
8+
Removes all access rules that have an unresolveable identity.
9+
This is aimed at identifying and remediating orphaned SIDs in active directory.
10+
11+
.PARAMETER Path
12+
The full distinguished name to the object to clean.
13+
14+
.PARAMETER ExcludeDomainSID
15+
SIDs from the specified domain SIDs will be ignored.
16+
Use this to safely handle one-way trust where ID resolution is impossible for some IDs.
17+
18+
.PARAMETER IncludeDomainSID
19+
If specified, only unresolved identities from the specified SIDs will be listed.
20+
Use this to safely target only rules from your owned domains in the targeted domain.
21+
22+
.PARAMETER Server
23+
The server / domain to connect to.
24+
25+
.PARAMETER Credential
26+
The credentials to use for AD operations.
27+
28+
.PARAMETER EnableException
29+
This parameters disables user-friendly warnings and enables the throwing of exceptions.
30+
This is less user friendly, but allows catching exceptions in calling scripts.
31+
32+
.PARAMETER Confirm
33+
If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
34+
35+
.PARAMETER WhatIf
36+
If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
37+
38+
.EXAMPLE
39+
PS C:\> Get-ADObject -LDAPFillter '(objectCategory=*)' | Remove-AdsOrphanAce
40+
41+
Purges all objects in the current domain from orphaned access rules.
42+
#>
43+
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
44+
param (
45+
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
46+
[string[]]
47+
$Path,
48+
49+
[string[]]
50+
$ExcludeDomainSID,
51+
52+
[string[]]
53+
$IncludeDomainSID,
54+
55+
[string]
56+
$Server,
57+
58+
[System.Management.Automation.PSCredential]
59+
$Credential,
60+
61+
[switch]
62+
$EnableException
63+
)
64+
65+
begin
66+
{
67+
$adParameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Credential
68+
Assert-ADConnection @adParameters -Cmdlet $PSCmdlet
69+
70+
function Write-Result
71+
{
72+
[CmdletBinding()]
73+
param (
74+
[string]
75+
$Path,
76+
77+
[System.DirectoryServices.ActiveDirectoryAccessRule]
78+
$AccessRule,
79+
80+
[ValidateSet('Deleted', 'Failed')]
81+
[string]
82+
$Action,
83+
84+
[System.Management.Automation.ErrorRecord]
85+
$ErrorRecord
86+
)
87+
88+
[PSCustomObject]@{
89+
PSTypeName = 'ADSec.AccessRule'
90+
Path = $Path
91+
Identity = $AccessRule.IdentityReference
92+
Action = $Action
93+
ADRights = $AccessRule.ActiveDirectoryRights
94+
Type = $AccessRule.AccessControlType
95+
ObjectType = $AccessRule.ObjectType
96+
InheritedOpectType = $AccessRule.InheritedObjectType
97+
Rule = $AccessRule
98+
Error = $ErrorRecord
99+
}
100+
}
101+
102+
# Wrap as nested pipeline to avoid asserting connection each time
103+
$scriptCmd = { Get-AdsAcl @adParameters -EnableException:$EnableException }
104+
$getAdsAcl = $scriptCmd.GetSteppablePipeline()
105+
$getAdsAcl.Begin($true)
106+
}
107+
process
108+
{
109+
foreach ($pathItem in $Path)
110+
{
111+
Write-PSFMessage -Level Verbose -String 'Remove-AdsOrphanAce.Searching' -StringValues $pathItem
112+
try { $acl = $getAdsAcl.Process($pathItem) }
113+
catch { Stop-PSFFunction -String 'Remove-AdsOrphanAce.Read.Failed' -StringValues $pathItem -EnableException $EnableException -ErrorRecord $_ -Cmdlet $PSCmdlet -Continue }
114+
if (-not $acl) { Stop-PSFFunction -String 'Remove-AdsOrphanAce.Read.Failed' -StringValues $pathItem -EnableException $EnableException -Cmdlet $PSCmdlet -Continue }
115+
116+
$rulesToPurge = foreach ($rule in $acl.Access)
117+
{
118+
if ($rule.IdentityReference -is [System.Security.Principal.NTAccount]) { continue }
119+
if ($rule.IdentityReference.AccountDomainSID.Value -in $ExcludeDomainSID) { continue }
120+
if ($IncludeDomainSID -and ($rule.IdentityReference.AccountDomainSID.Value -notin $IncludeDomainSID)) { continue }
121+
122+
try { $null = $rule.IdentityReference.Translate([System.Security.Principal.NTAccount]) }
123+
catch
124+
{
125+
$null = $acl.RemoveAccessRule($rule)
126+
$rule
127+
}
128+
}
129+
if (-not $rulesToPurge)
130+
{
131+
Write-PSFMessage -Level Verbose -String 'Remove-AdsOrphanAce.NoOrphans' -StringValues $pathItem
132+
continue
133+
}
134+
135+
Invoke-PSFProtectedCommand -ActionString 'Remove-AdsOrphanAce.Removing' -ActionStringValues ($rulesToPurge | Measure-Object).Count -Target $pathItem -ScriptBlock {
136+
try
137+
{
138+
Set-ADObject @adParameters -Identity $pathItem -Replace @{ ntSecurityDescriptor = $acl } -ErrorAction Stop
139+
foreach ($rule in $rulesToPurge) { Write-Result -Path $pathItem -AccessRule $rule -Action Deleted }
140+
}
141+
catch
142+
{
143+
foreach ($rule in $rulesToPurge) { Write-Result -Path $pathItem -AccessRule $rule -Action Failed -ErrorRecord $_ }
144+
throw
145+
}
146+
} -EnableException $EnableException.ToBool() -PSCmdlet $PSCmdlet -Continue
147+
}
148+
}
149+
end
150+
{
151+
$getAdsAcl.End()
152+
}
153+
}

0 commit comments

Comments
 (0)