functions/Import-GptPermission.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
function Import-GptPermission
{
<#
    .SYNOPSIS
        Import permissions to GPOs.
     
    .DESCRIPTION
        Import permissions to GPOs.
        This tries to restore the same permissions that existed on the GPOs before the export.
        Notes:
        - It is highly recommended to perform this before executing Import-GptLink.
        - Executing this requires the identities to have been imported (Import-GptIdentity)
     
    .PARAMETER Path
        The path where the permission export file is stored.
     
    .PARAMETER Name
        Only restore permissions for GPOs with a matching name.
     
    .PARAMETER GpoObject
        Select the GPOs to restore permissions to by specifying their full object.
     
    .PARAMETER ExcludeInherited
        Do not import permissions that were inherited permissions on the source GPO
     
    .PARAMETER Domain
        The domain to restore the GPO permissions to.
     
    .EXAMPLE
        PS C:\> Import-GptPermission -Path '.'
     
        Import GPO permissions from the current path.
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateScript({ Test-Path -Path $_ })]
        [string]
        $Path,
        
        [string[]]
        $Name = '*',
        
        [Parameter(ValueFromPipeline = $true)]
        $GpoObject,
        
        [switch]
        $ExcludeInherited,
        
        [string]
        $Domain = $env:USERDNSDOMAIN
    )
    
    begin
    {
        #region Utility Functions
        function Update-GpoPermission
        {
            [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
            [CmdletBinding()]
            param (
                $ADObject,
                
                $Permission,
                
                $GpoObject,
                
                $DomainObject
            )
            
            try
            {
                $accessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList @(
                    (ConvertFrom-ImportedIdentity -Permission $Permission -DomainObject $DomainObject),
                    $Permission.ActiveDirectoryRights,
                    $Permission.AccessControlType,
                    $Permission.ObjectType,
                    $Permission.InheritanceType,
                    $Permission.InheritedObjectType
                )
            }
            catch
            {
                New-ImportResult -Action 'Update Gpo Permission' -Step 'Resolving Identity' -Target $Permission.GpoName -Success $false -Data $Permission -ErrorData $_
                return
            }
            
            $matchingRule = $null
            $matchingRule = $ADObject.ntSecurityDescriptor.Access | Where-Object {
                $accessRule.IdentityReference -eq $_.IdentityReference -and
                $accessRule.ActiveDirectoryRights -eq $_.ActiveDirectoryRights -and
                $accessRule.AccessControlType -eq $_.AccessControlType -and
                $accessRule.ObjectType -eq $_.ObjectType -and
                $accessRule.InheritanceType -eq $_.InheritanceType -and
                $accessRule.InheritedObjectType -eq $_.InheritedObjectType
            }
            
            if ($matchingRule)
            {
                New-ImportResult -Action 'Update Gpo Permission' -Step 'Skipped, already exists' -Target $Permission.GpoName -Success $true -Data $Permission, $accessRule
                return
            }
            
            #region Set AD Permissions
            try
            {
                Write-Verbose "Updating ACL on GPO $($ADObject.DistinguishedName)"
                $acl = Get-Acl -Path "AD:\$($ADObject.DistinguishedName)" -ErrorAction Stop
                $acl.AddAccessRule($accessRule)
                $acl | Set-Acl -Path "AD:\$($ADObject.DistinguishedName)" -ErrorAction Stop
            }
            catch
            {
                New-ImportResult -Action 'Update Gpo Permission' -Step 'Apply AD Permission' -Target $Permission.GpoName -Success $false -Data $Permission, $accessRule -ErrorData $_
                continue
            }
            #endregion Set AD Permissions
            
            #region Set File Permissions
            if (-not (Test-Path $ADObject.gPCFileSysPath))
            {
                New-ImportResult -Action 'Update Gpo Permission' -Step 'Apply File Permission' -Target $Permission.GpoName -Success $false -Data $Permission, $accessRule -ErrorData "Path not found"
                continue
            }
            try
            {
                $rights = 'Read'
                if ($accessRule.ActiveDirectoryRights -eq 983295) { $rights = 'FullControl' }
                $fileRule = New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList @(
                    $accessRule.IdentityReference
                    $rights
                    $accessRule.AccessControlType
                )
                
                
                $acl = Get-Acl -Path $ADObject.gPCFileSysPath -ErrorAction Stop
                $acl.AddAccessRule($fileRule)
                $acl | Set-Acl -Path $ADObject.gPCFileSysPath -ErrorAction Stop
            }
            catch
            {
                New-ImportResult -Action 'Update Gpo Permission' -Step 'Apply File Permission' -Target $Permission.GpoName -Success $false -Data $Permission, $accessRule -ErrorData $_
                continue
            }
            #endregion Set File Permissions
            
            New-ImportResult -Action 'Update Gpo Permission' -Step Success -Target $Permission.GpoName -Success $true -Data $Permission, $accessRule
        }
        #endregion Utility Functions
        
        $pathItem = Get-Item -Path $Path
        if ($pathItem.Extension -eq '.csv') { $resolvedPath = $pathItem.FullName }
        else { $resolvedPath = (Get-ChildItem -Path $pathItem.FullName -Filter 'gp_permissions_*.csv' | Select-Object -First 1).FullName }
        if (-not $resolvedPath) { throw "Could not find permissions file in $($pathItem.FullName)" }
        
        if (-not $script:identityMapping)
        {
            throw 'Could not find imported identities to match. Please run Import-GptIdentity first!'
        }
        
        $domainObject = Get-ADDomain -Server $Domain
        $allPermissionData = Import-Csv -Path $resolvedPath
    }
    process
    {
        $gpoObjects = $GpoObject
        if (-not $GpoObject)
        {
            $gpoObjects = Get-GPO -All -Domain $Domain
        }
        
        foreach ($gpoItem in $gpoObjects)
        {
            if (-not (Test-Overlap -ReferenceObject $gpoItem.DisplayName -DifferenceObject $Name -Operator Like))
            {
                continue
            }
            $adObject = Get-ADObject -Identity $gpoItem.Path -Server $gpoItem.DomainName -Properties ntSecurityDescriptor, gPCFileSysPath
            
            foreach ($permission in $allPermissionData)
            {
                # Skip items that do not apply
                if ($permission.GpoName -ne $gpoItem.DisplayName) { continue }
                if ($ExcludeInherited -and $permission.IsInherited -eq "True") { continue }
                
                Update-GpoPermission -ADObject $adObject -Permission $permission -GpoObject $gpoItem -DomainObject $domainObject
            }
        }
    }
}