Get-GroupSendAsPermission.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
<#
    .SYNOPSIS
 
    This function extracts the send as ACLs of the group to be migrated.
     
    .DESCRIPTION
 
    This function extracts the send as ACLs of the group to be migrated.
 
    .PARAMETER adGlobalCatalogPowershellSessionName
 
    The powershell session to invoke the get-ACL call remotely - ensures we use the specified DC.
 
    .PARAMETER globalCatalogServer
 
    The global catalog server to feed into the normalization command.
 
    .PARAMETER DN
 
    The DN of the object to pass to normalize.
 
    .PARAMETER adCredential
 
    The credential for the AD get operations.
 
    .OUTPUTS
 
    This returns the normalized list of SMTP addresses assigned send as permissions.
 
    .EXAMPLE
 
    get-GroupSendAsPermissions -DN DN -globalCatalog GC -adGlobalCatalogPowershellSessionName NAME -adCredential $cred
 
    #>

    Function get-GroupSendAsPermissions
     {
        [cmdletbinding()]

        Param
        (
            [Parameter(Mandatory = $true)]
            [string]$adGlobalCatalogPowershellSessionName,
            [Parameter(Mandatory = $true)]
            [string]$DN,
            [Parameter(Mandatory = $true)]
            [string]$globalCatalogServer,
            [Parameter(Mandatory = $true)]
            $adCredential,
            [Parameter(Mandatory = $true)]
            $groupSMTPAddress
        )

        #Output all parameters bound or unbound and their associated values.

        write-functionParameters -keyArray $MyInvocation.MyCommand.Parameters.Keys -parameterArray $PSBoundParameters -variableArray (Get-Variable -Scope Local -ErrorAction Ignore)

        #Declare function variables.

        $functionPSSession = $null
        [array]$functionACLS = @()
        [array]$functionSendAsRight=@()
        [array]$functionSendAsRightName=@()
        [array]$functionSendAsRightDN=@()
        [array]$functionSendAsObjects=@()
        [boolean]$success=$FALSE

        #Start function processing.

        Out-LogFile -string "********************************************************************************"
        Out-LogFile -string "BEGIN GET-GroupSendAsPermissions"
        Out-LogFile -string "********************************************************************************"
        
        #Getting the working powershell session for commands that do not support specifying domain controllers.

        try 
        {
            out-logfile -string "Obtaining remote powershell session for the global catalog server."

            $functionPSSession = Get-PSSession -Name $adGlobalCatalogPowershellSessionName
        }
        catch 
        {
            out-logfile -string "Unable to retrieve the global catalog remote powershell session."
            out-logfile -string $_ -isError:$TRUE
        }


        #Get ACL and the ability to work varies greatly with windows versions.
        #We'll implement a home grown try catch here.

        #Get the ACLS on the object building the path without dll in the name.


        out-logfile -string ("Obtaining the ACLS on DN = "+$dn)

        $objectPath = "Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/$DN"

        out-logfile -string $objectPath

        $functionACLS = invoke-command -session $functionPSSession -ScriptBlock {import-module ActiveDirectory ; (get-ACL $args).access} -ArgumentList $objectPath *>&1

        #If the call includes an exception - this variation did not work.

        if ($functionACLS.exception -ne $NULL)
        {
            out-logfile -string "Error attempting first send as acl call."
            out-logfile -string $functionACLS.exception
        }
        else 
        {
            out-logfile -string "Send as acls gathered first try - setting success."
            $success=$TRUE    
        }

        #If the previous call was not successful - this time try with DLL.

        if ($success -eq $FALSE)
        {
            $objectPath = "Microsoft.ActiveDirectory.Management.dll\ActiveDirectory:://RootDSE/$DN"

            out-logfile -string $objectPath

            $functionACLS = invoke-command -session $functionPSSession -ScriptBlock {import-module ActiveDirectory ; (get-ACL $args).access} -ArgumentList $objectPath *>&1

            #If the call includes an exception - this variation did not work.

            if ($functionACLS.exception -ne $NULL)
            {
                out-logfile -string "Error attempting second send as acl call."
                out-logfile -string $functionACLS.exception
            }
            else 
            {
                out-logfile -string "Send as acls gathered second try - setting success."
                $success=$TRUE    
            }
        }

        #If the previos call was not successful - we'll try with just get-acl.
        #This is prone to failure with special characters and different windows versions.

        if ($success -eq $FALSE)
        {
            $objectPath = $dn

            out-logfile -string $objectPath

            $functionACLS = invoke-command -session $functionPSSession -ScriptBlock {import-module ActiveDirectory ; (get-ACL $args).access} -ArgumentList $objectPath *>&1

            #If the call includes an exception - this variation did not work.

            if ($functionACLS.exception -ne $NULL)
            {
                out-logfile -string "Error attempting third send as acl call."
                out-logfile -string $functionACLS.exception
            }
            else 
            {
                out-logfile -string "Send as acls gathered third try - setting success."
                $success=$TRUE    
            }
        }
    
        #At this time we've made three attempts to capture send as permissions on the group to be migrated.
        #If success is not true throw exception.

        if ($success -eq $FALSE)
        {
            out-logfile -string "Unable to obtain send as permissions using three known methods."
            out-logfile -string "Send As Failure" -isError:$TRUE
        }
        else 
        {
            out-logfile -string "Success gathering send as - proceeding..."    
        }

        #The ACLS object has been extracted.
        #We want all perms that are extended, allowed, and match the object type for send as.

        $functionSendAsRight = $functionACLS | ?{($_.ActiveDirectoryRights -eq "ExtendedRight") -and ($_.objectType -eq "ab721a54-1e2f-11d0-9819-00aa0040529b") -and ($_.AccessControlType -eq "Allow")}

        #At this time we have all of the function send as rights. If the array is empty - there are no rights.
        #If a send as right is present - it is stored on the object as DOMAIN\NAME format. This is not something that we can work with.
        #We need to normalize this list over to distinguished names.

        if ($functionSendAsRight.count -ne 0)
        {
            out-logfile -string "Send as rights were detected - normalizing identity."

            foreach ($sendAsRight in $functionSendAsRight)
            {
                if ($sendAsRight.identityReference.toString() -notlike "S-1-5*")
                {
                    out-logfile -string "Processing ACL"
                    out-logfile -string $sendAsRight

                    $functionSendAsRightName+=$sendAsRight.identityreference.tostring().split("\")[1]
                }
                else 
                {
                    out-logfile -string "ACL skipped - SID found - orphaned ACL."    
                    out-logfile -string $sendAsRight
                }
            }
        }
        else 
        {
            out-logfile -string "There were no send as rights on the object - disregard identities."
        }

        #At this time we have an array of names that were split of the identity reference.
        #We now have to normalize those names over to distinguished names so we can then normalize them to SMTP addresses.

        if ($functionSendAsRightName.count -ne 0)
        {
            out-logfile -string "We have send as names that require distinguished names."

            foreach ($sendAsName in $functionSendAsRightName)
            {
                out-logfile -string ("Processing identity = "+$sendAsName)

                out-logfile -string "Testing for NTAuthority\Self"

                if ($sendAsName -eq "Self")
                {
                    out-logfile -string "Self right found on distribution group."

                    $functionSendAsRightDN += $dn
                }

                else
                {
                    $stopLoop = $FALSE
                    [int]$loopCounter = 0

                    do 
                    {
                        try 
                        {
                            $functionSendAsRightDN+=(get-adobject -filter {SAMAccountName -eq $sendAsName} -server $globalCatalogServer -credential $adCredential).distinguishedName

                            $stopLoop = $TRUE
                        }
                        catch 
                        {
                            if ($loopCounter -gt 4)
                            {
                                out-logfile -string "Unablet to retrive the object by name."
                                out-logfile -string $_ -isError:$TRUE
                            }
                            else 
                            {
                                out-logfile -string "Error with get-adObject -> sleep and retry."
                                $loopCounter=$loopCounter+1
                                start-sleepProgress -sleepString "Error with get-adobject -> sleep and retry." -sleepSeconds 5

                            }
                        }    
                    } until ($stopLoop -eq $TRUE)
                }
            }
        }
        else 
        {
            out-logfile -string  "There are no send as rights DNs to process."   
        }

        #At this time we have an array of all the DNs.
        #The DNs need to be normalized as any of the other DNs we work with.

        if ($functionSendAsRightDN.count -ne 0)
        {
            out-logfile -string "There are DNs to be normalized."

            foreach ($dnToNormalize in $functionSendAsRightDN)
            {
                out-logfile -string ("Processing DN = "+$dnToNormalize)

                try 
                {
                    #$functionSendAsTest+=get-normalizedDN -globalCatalogServer $globalCatalogServer -DN $dnToNormalize -adCredential $activeDirectoryCredential -originalGroupDN $dn -errorAction STOP -cn "None"

                    $normalizedTest=get-normalizedDN -globalCatalogServer $globalCatalogServer -DN $dnToNormalize -adCredential $activeDirectoryCredential -originalGroupDN $dn -activeDirectoryAttribute "SendAs" -activeDirectoryAttributeCommon "SendAsPermissionOnGroup" -groupSMTPAddress $groupSMTPAddress -errorAction STOP -cn "None"

                    out-logfile -string $normalizedTest

                    if ($normalizedTest.isError -eq $TRUE)
                    {
                        $global:preCreateErrors+=$normalizedTest
                    }
                    else 
                    {
                        $functionSendAsObjects+=$normalizedTest
                    }
                }
                catch 
                {
                    out-logfile -string "Unable to normalize the DN to an object with SMTP."
                    out-logfile -string $_ -isError:$TRUE
                }
            }
        }
        else 
        {
            out-logfile -string "There were no DNs to process."    
        }

        if ($functionSendAsObjects -ne $NULL)
        {
            foreach ($object in $functionSendAsObjects)
            {
                out-logfile -string "This is an object to be returned."
                out-logfile -string $object
            }
        }

        Out-LogFile -string "END GET-GroupSendAsPermissions"
        Out-LogFile -string "********************************************************************************"
        
        return $functionSendAsObjects
        
        #This function is designed to open local and remote powershell sessions.
        #If the session requires import - for example exchange - return the session for later work.
        #If not no return is required.
    
    }