functions/acl/Set-AdsOwner.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
function Set-AdsOwner
{
<#
    .SYNOPSIS
        Changes the owner of the specified AD object to the target identity.
     
    .DESCRIPTION
        Changes the owner of the specified AD object to the target identity.
     
    .PARAMETER Path
        Path to the object to update
     
    .PARAMETER Identity
        Identity to make the new owner.
     
    .PARAMETER WinRMFailover
        Whether on execution error it should try again using WinRM.
        Default-Value determined using the configuration setting 'ADSec.WinRM.FailOver'
     
    .PARAMETER Server
        The server / domain to connect to.
     
    .PARAMETER Credential
        The credentials to use for AD operations.
     
    .PARAMETER EnableException
        This parameters disables user-friendly warnings and enables the throwing of exceptions.
        This is less user friendly, but allows catching exceptions in calling scripts.
     
    .PARAMETER Confirm
        If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
     
    .PARAMETER WhatIf
        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.
     
    .EXAMPLE
        PS C:\> Set-AdsOwner -Path $dn -Identity 'contoso\Domain Admins'
         
        Makes the domain admins owner of the path specified in $dn
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '')]
    [CmdletBinding(SupportsShouldProcess = $true)]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [Alias('DistinguishedName')]
        [string[]]
        $Path,
        
        [Parameter(Mandatory = $true)]
        [string]
        $Identity,
        
        [switch]
        $WinRMFailover = (Get-PSFConfigValue -FullName 'ADSec.WinRM.FailOver'),
        
        [string]
        $Server,
        
        [System.Management.Automation.PSCredential]
        $Credential,
        
        [switch]
        $EnableException
    )
    
    begin
    {
        $adParameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Credential
        Assert-ADConnection @adParameters -Cmdlet $PSCmdlet
        
        if ($Identity -as [System.Security.Principal.SecurityIdentifier])
        {
            $idReference = [System.Security.Principal.SecurityIdentifier]$Identity
        }
        else
        {
            $idReference = [System.Security.Principal.NTAccount]$Identity
            try { $null = $idReference.Translate([System.Security.Principal.SecurityIdentifier]) }
            catch
            {
                Stop-PSFFunction -String 'Set-AdsOwner.UnresolvedIdentity' -StringValues $Identity -EnableException $EnableException -ErrorRecord $_ -OverrideExceptionMessage
                return
            }
        }
        
        $basePath = 'LDAP://{0}'
        if ($Server) { $basePath = "LDAP://$Server/{0}" }
    }
    process
    {
        if (Test-PSFFunctionInterrupt) { return }
        
        foreach ($pathItem in $Path)
        {
            $aclObject = Get-AdsAcl @adParameters -Path $pathItem
            if ($aclObject.Owner -eq $idReference)
            {
                Write-PSFMessage -String 'Set-AdsOwner.AlreadyOwned' -StringValues $pathItem, $idReference
                continue
            }
            
            # Switching to LDAP as owner changes don't work using AD Module
            if ($Credential) { $directoryEntry = New-Object System.DirectoryServices.DirectoryEntry(($basePath -f $pathItem), $Credential.UserName, $Credential.GetNetworkCredential().Password) }
            else { $directoryEntry = New-Object System.DirectoryServices.DirectoryEntry(($basePath -f $pathItem)) }
            
            Invoke-PSFProtectedCommand -ActionString 'Set-AdsOwner.UpdatingOwner' -ActionStringValues $idReference -ScriptBlock {
                try {
                    $secDescriptor = $directoryEntry.InvokeGet('nTSecurityDescriptor')
                    if (-not $secDescriptor) { throw 'Failed to access security information' }
                    $secDescriptor.Owner = "$idReference"
                    $directoryEntry.InvokeSet('nTSecurityDescriptor', $secDescriptor)
                    $directoryEntry.CommitChanges()
                }
                catch {
                    if (-not $WinRMFailover) { throw }
                    
                    #region Fallback to WinRM
                    $domainController = Get-ADDomainController @adParameters
                    $credParam = $PSBoundParameters | ConvertTo-PSFHashtable -Include Credential
                    $ldapPath = "LDAP://localhost/$($pathItem)"
                    
                    Invoke-Command -ComputerName $domainController.HostName @credParam -ScriptBlock {
                        param (
                            $Identity,
                            
                            $LdapPath
                        )
                        try {
                            $directoryEntry = New-Object System.DirectoryServices.DirectoryEntry($LdapPath)
                            $secDescriptor = $directoryEntry.InvokeGet('nTSecurityDescriptor')
                            if (-not $secDescriptor) { throw 'Failed to access security information' }
                            $secDescriptor.Owner = $Identity
                            $directoryEntry.InvokeSet('nTSecurityDescriptor', $secDescriptor)
                            $directoryEntry.CommitChanges()
                        }
                        catch { throw }
                    } -ArgumentList "$idReference", $ldapPath -ErrorAction Stop
                    #endregion Fallback to WinRM
                }
            } -Target $pathItem -EnableException $EnableException.ToBool() -Continue -PSCmdlet $PSCmdlet
        }
    }
}