Private/Wissen/X_Technology/X08_Technology_ADS.ps1

# ? TITEL Active Directory Services
# ? DESCRIPTION PowerShell trifft ADS
# ? TAGS ADS ActiveDirectory
# ? VERSION 2020.01.19

# TODO Weiterführende und Nachschlage-Informationen

# Active Directory-Verwaltungscenter ($env:windir\system32\dsac.exe) https://docs.microsoft.com/de-de/windows-server/identity/ad-ds/get-started/adac/advanced-ad-ds-management-using-active-directory-administrative-center--level-200-
Find-Module PSADHealth

#region #TODO 1. AD Forest aufsetzen und Clients in der Domäne aufnehmen

# ! DC01:
Add-WindowsFeature -Name AD-Domain-Services -IncludeAllSubFeature -IncludeManagementTools -LogPath C:\Users\Administrator\Desktop\AddWinFeature.log
$safeModeAdministratorPassword = "P@ssw0rd" | ConvertTo-SecureString -AsPlainText -Force
Import-Module ADDSDeployment
$params = @{
    CreateDnsDelegation           = $false
    DatabasePath                  = "C:\Windows\NTDS"
    DomainMode                    = "Win2012R2"
    DomainName                    = "abc.local"
    DomainNetbiosName             = "ABC"
    ForestMode                    = "Win2012R2"
    InstallDns                    = $true
    LogPath                       = "C:\Windows\NTDS"
    NoRebootOnCompletion          = $false
    SysvolPath                    = "C:\Windows\SYSVOL"
    Force                         = $true
    SafeModeAdministratorPassword = $safeModeAdministratorPassword
}
Install-ADDSForest @params

# ! Client01:
$cred = Get-Credential -Message "Domänenadministrator" -UserName "administrator@abc.local"
Add-Computer -DomainName "abc" -Credential $cred

#endregion

# ! 1. Lokal das RSAT-Packet für Windows 10 auf einem Windows-10-Domain-Client installieren, oder
#https://www.microsoft.com/de-DE/download/details.aspx?id=45520
$cred = Get-Credential -Message "DC1" -UserName "Administrator@abc.local"
Get-ADUser -Server "DC01" -Credential $cred -Filter "*"

# ! 1. Auf den DC per Remote zugreifen:
Enable-PSRemoting -SkipNetworkProfileCheck
Get-NetConnectionProfile 
Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
Test-Connection dc01
$cred = Get-Credential -Message "DC1" -UserName "Administrator@abc.local"
Enter-PSSession dc01 -Credential $cred

# ! 2. PowerShell-Module für ActiveDirectory auf einem Domain-Mitglieds-Server installieren:
Install-WindowsFeature -Name "RSAT-AD-PowerShell", "RSAT-AD-Tools", "RSAT-ADDS" -IncludeAllSubFeature -IncludeManagementTools -Verbose
Get-WindowsFeature -Name "RSAT-AD-PowerShell", "RSAT-AD-Tools", "RSAT-ADDS"

# ! 3. ActiveDirectory Module vorhanden
Get-Module -Name ActiveDirectory -ListAvailable

# ! 4. ActiveDirectory Module importieren
Import-Module -Name ActiveDirectory -Force

# ! 5. ActiveDirectory-Laufwerk vorhanden?
Get-PSDrive -PSProvider ActiveDirectory
Get-ChildItem -Path "AD:\DC=abc,DC=local"

# ! 6. PowerShell-Hilfe aktualisieren
Update-Help -Name * -UICulture en-US -Force

# ! 7. Übersicht der AD-Cmdlets
Get-Command -Module ActiveDirectory | Out-GridView

#region Forest

Get-ADForest
# oder so
[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()

#endregion

#region Active Directory Standorten

Get-Command "*ADReplication*" -Module ActiveDirectory

New-ADReplicationSite -Name "Würzburg"

$Schedule = New-Object -TypeName System.DirectoryServices.ActiveDirectory.ActiveDirectorySchedule
$Schedule.ResetSchedule()
$Schedule.SetDailySchedule("Twenty","Zero","TwentyTwo","Thirty");
New-ADReplicationSite -Name "München" -ReplicationSchedule $schedule

New-ADReplicationSiteLink -Name "Würzburg-München" -SitesIncluded Würzburg, München -Cost 100 -ReplicationFrequencyInMinutes 15 -InterSiteTransportProtocol IP

New-ADReplicationSubnet -Name "192.168.50.0/24" -Site (Get-ADReplicationSite -Identity "Würzburg")
New-ADReplicationSubnet -Name "192.168.51.0/24" -Site (Get-ADReplicationSite -Identity "München")

Get-ADReplicationSite -Filter *
Get-ADReplicationSiteLink -Filter *
Get-ADReplicationSubnet -Filter *

## Alle DC-Server an einem Standort
$serverContainerDN = “CN=Servers, CN=Default-First-Site-Name, CN=Sites, CN=Configuration, DC=abc, DC=local”
Get-ADObject -SearchBase $serverContainerDN -SearchScope OneLevel -Filter "ObjectClass -eq 'server'" -Properties “DNSHostName”, “Description” | Select-Object Name, DNSHostName, Description

# Get replication metadata for the attributes of a group
Get-ADReplicationAttributeMetadata -Object "CN=Domänen-Admins, CN=Users, DC=abc, DC=local" -Server localhost -ShowAllLinkedValues

# Get filtered replication metadata for all groups
Get-ADObject -Filter 'objectclass -eq "group"' | 
    Get-ADReplicationAttributeMetadata -Server localhost | 
    Where-Object {$_.LastOriginatingChangeTime -like "*2017*"} | 
    Format-Table object

Get-ADReplicationConnection -Filter *

Get-ADReplicationFailure -Target localhost

#endregion

#region GPO

Import-Module GroupPolicy -Verbose 
Get-Command -Module GroupPolicy

Backup-GPO                 # Mit diesem Cmdlet sichert man das angegebene Gruppenrichtlinienobjekt (GPO) oder alle Gruppenrichtlinienobjekte in einer angegebenen Domäne in ein Sicherungsverzeichnis. Dabei muss das Sicherungsverzeichnis bereits existieren.
Restore-GPO                # Dieses Cmdlet stellt eine GPO-Sicherung in der Domäne wieder her, in der sie ursprünglich gespeichert wurde. Ist die ursprüngliche Domäne oder die GPO nicht mehr in der Domäne vorhanden, tritt ein Fehler auf.
Get-GPO                    # Eine bestimmte GPO oder alle GPOs innerhalb einer Domäne kann man sich mit diesem Cmdlet anzeigen lassen.
Copy-GPO                   # Dieses Cmdlet erstellt eine neue GPO und kopiert die Einstellungen aus der Quell-GPO in die neue GPO. Mit diesem Cmdlet kann eine GPO aus einer Domäne in eine andere Domäne innerhalb der gleichen Gesamtstruktur kopiert werden.
New-GPO                    # Eine neue GPO wird mit diesem Cmdlet erstellt.
Remove-GPO                 # Eine GPO wird mit samt allen Verlinkungen, mit diesem Cmdlet gelöscht.
Import-GPO                 # Dieses Cmdlet importiert die Einstellungen aus einer gesicherten GPO in die angegebene Ziel-GPO. Dabei kann sich das Ziel-GPO in einer anderen Domäne oder in einer anderen Gesamtstruktur befinden als die Sicherungs-GPO und muss vorher nicht existieren.
Rename-GPO                 # Mit diesem Cmdlet kann man eine GPO umbenennen bzw. der GPO einen anderen Anzeigenamen zuweisen. Dabei bleibt die GUID der umbenannten GPO erhalten.
Get-GPInheritance          # Informationen zur Gruppenrichtlinienvererbung für eine angegebene Domäne oder Organisationseinheit kann man sich mit diesem Cmdlet ausgeben lassen.
Get-GPOReport              # Hiermit wird ein Bericht im XML- oder HTML-Format generiert, in dem die Eigenschaften und Richtlinieneinstellungen für eine angegebene GPO oder für alle GPOs einer Domäne angezeigt werden. Dieses Cmdlet eignet sich ideal zu Dokumentationszwecken. Möchte man alle Richtlinieneinstellungen aller GPOs innerhalb der Domäne in eine HTML Datei exportieren, so gilt es diesen Befehl auszuführen: Get-GPOReport -All -Domain <Domäne.de> -ReportType HTML -Path C:\GPOReport\GPOReport.html. Das Zielverzeichnis muss bereits existieren, sonst erhält man eine Fehlermeldung.
Get-GPPermissions          # Die Berechtigungen für einen oder mehrere Sicherheitsprinzipale kann man mit diesem Cmdlet in der angegebenen GPO abrufen.
Get-GPPrefRegistryValue    # Dieses Cmdlet zeigt eine oder mehrere Registrierungseinstellungen die unterhalb der Computerkonfiguration oder der Benutzerkonfiguration in einer GPO getätigt wurden an.
Get-GPRegistryValue        # Bei diesem Cmdlet werden eine oder mehrere registrierungsbasierte Richtlinieneinstellungen aus der Computerkonfiguration oder der Benutzerkonfiguration in einer GPO abgerufen.
Get-GPResultantSetOfPolicy # Mit diesem Cmdlet kann man die Richtlinienergebnissatz-Informationen für einen Benutzer, einen Computer oder für beide in eine Datei im HTML- oder XML-Format ausgeben lassen.
Get-GPStarterGPO           # Ein bestimmtes oder alle Starter-GPOs werden mit diesem Cmdlet angezeigt.
New-GPLink                 # Eine GPO wird auf eine Organisationseinheit (OU), einen AD-Standort oder auf die Domäne mit diesem Cmdlet verlinkt.
New-GPStarterGPO           # Mit diesem Cmdlet wird eine neue Starter-GPO erstellt.
Remove-GPLink              # Dieses Cmdlet entfernt eine GPO-Verklinkung von einer OU, einem AD-Standort oder von der Domäne.
Remove-GPPrefRegistryValue # Eine oder mehrere Registrierungseinstellungen werden aus der Benutzerkonfiguration oder Computerkonfiguration innerhalb einer GPO mit diesem Cmdlet entfernt.
Remove-GPRegistryValue     # Um eine oder mehrere Registrierungsbasierte Richtlinieneinstellungen aus der Benutzerkonfiguration oder Computerkonfiguration innerhalb einer GPO zu entfernen, muss dazu dieses Cmdlet verwendet werden.
Set-GPInheritance          # Die Vererbung einer GPO kann mit diesem Cmdlet deaktiviert werden. Oder die Deaktivierung der Vererbung für eine angegebene OU oder Domäne lässt sich ebenfalls mit diesem Cmdlet aufheben.
Set-GPLink                 # Die Eigenschaften einer GPO-Verknüpfung lassen sich mit diesem Cmdlet festlegen.
Set-GPPermissions          # Die Berechtigungen einer GPO oder für alle GPOs innerhalb einer Domäne lassen sich mit diesem Cmdlet bearbeiten.
Set-GPPrefRegistryValue    # Dieses Cmdlet konfiguriert eine Registrierungseinstellung unter der Benutzerkonfiguration oder der Computerkonfiguration in einer GPO.
Set-GPRegistryValue        # Mit diesem Cmdlet konfiguriert man eine oder mehrere registrierungsbasierte Richtlinieneinstellungen unter der Benutzerkonfiguration oder der Computerkonfiguration in einer GPO.

Get-GPO -Name "Default Domain Policy" 
Get-GPO -Name "Default Domain Policy" | Get-GPOReport -ReportType Html | Out-File -Encoding utf8 -FilePath .\ddp_report.html 

# Kennwort muss Komplexitätsvoraussetzungen entsprechen?
$xmlDoc = [xml](Get-GPO -Name "Default Domain Policy" | Get-GPOReport -ReportType Xml)
$xmlDoc.GPO.Computer.ExtensionData.Extension.Account | Where-Object Name -EQ PasswordComplexity | Select-Object -ExpandProperty SettingBoolean

# Oder nativ in den Richtlinien lesen
$gpo = Get-GPO -Name "Default Domain Policy" 
Get-ChildItem "\\lunar80\SYSVOL\abc.local\Policies\{$($gpo.Id)}\MACHINE\"

#endregion

#region Domain Controller

Get-ADDomainController

#endregion

#region Password Settings Objects

New-ADFineGrainedPasswordPolicy -Name "DomainUsersPSO" -Precedence 500 -ComplexityEnabled $true -Description "The Domain Users Password Policy" -DisplayName "Domain Users PSO" -LockoutDuration "0.12:00:00" -LockoutObservationWindow "0.00:15:00" -LockoutThreshold 10 
Set-ADFineGrainedPasswordPolicy -Identity ‘DomainUsersPSO’ -Replace @{‘msDS-PSOAppliesTo’=’CN=PSOTest, OU=AK, DC=abc, DC=local’}

$allPSOUsers = Get-ADFineGrainedPasswordPolicySubject "DomainUsersPSO" | 
                Where-Object {$_.objectClass -eq "group"}| 
                ForEach-Object {Get-ADGroupMember $_.Name -Recursive} | 
               Where-Object {$_.objectClass -eq "user"} | 
               Select-Object -Unique

$allUsers = Get-AdUser -Filter *

$allUsersNotinPSO = Compare-Object -ReferenceObject $allUsers -DifferenceObject $allPSOUsers -PassThru | Select-Object Name
$allUsersNotinPSO

#endregion

#region Active Directory Papierkorbs

Get-Command -Noun ADOptionalFeature

Get-ADOptionalFeature -Filter *

Enable-ADOptionalFeature -Identity "Recycle Bin Feature" -Scope ForestOrConfigurationSet -Target "abc.local"

Get-ADObject -Filter {name -like "Inge*"} –IncludeDeletedObjects
Get-ADObject -Filter {name -like "Inge*" -and Deleted -eq $true} –IncludeDeletedObjects | Restore-ADObject



# PowerShell and Active Directory Recycle Bin
# Papierkorb Active Directory https://docs.microsoft.com/de-de/windows-server/identity/ad-ds/get-started/adac/introduction-to-active-directory-administrative-center-enhancements--level-100-
$oDomain = Get-ADDomain
$DeletedObjects = $oDomain.DeletedObjectsContainer
$DeletedObjects
Restore-ADObject









#endregion

#region Organization Unit

New-ADOrganizationalUnit -Name "Edv" -Path "DC=abc, DC=local"

#endregion

#region AD User

# User erstellen

$pl = New-ADUser -GivenName "Peter" -Name "Peter Lustig" -Path "CN=Users, DC=abc, DC=local" -PassThru
$pl | Get-Member

New-ADUser -Name "Pavel Sauer" -Path "OU=Edv, DC=abc, DC=local" -GivenName "Pavel" -UserPrincipalName "p.sauer" -Enabled $true -AccountPassword (Read-Host -Prompt "Passwort für Pavel Sauer" -AsSecureString)

$newUserParam = @{
    GivenName             = "Petra"
    Surname               = "Süß"
    Name                  = "Petra Süß"    # Vollständige Name
    UserPrincipalName     = "p.suess"    # Anmeldename
    Title                 = "Supporter"
    ChangePasswordAtLogon = $true
    Enabled               = $true
    Path                  = "OU=Edv, DC=abc, DC=local"
    AccountPassword       = Read-Host -Prompt "Initialpasswort" -AsSecureString
}
New-ADUser @newUserParam 

# ? User finden:

Get-ADUser -Identity Administrator
Get-ADUser -Identity "Peter Lustig"
Get-ADUser -Filter {GivenName -like 'P*'}
Get-ADUser -Filter {GivenName -like 'p*'} -SearchBase "OU=Edv, DC=abc, DC=local"
Get-ADUser -Filter {GivenName -eq 'Petra'} -Properties *

# User ändern

Get-ADUser -Filter {GivenName -eq 'Petra'} | Set-ADUser -StreetAddress "Rosenweg 1" -Verbose
Get-ADUser -Filter {GivenName -eq 'Petra'} -SearchBase "OU=Edv, DC=abc, DC=local" | Set-ADUser -Manager "CN=Pavel Sauer,OU=Edv,DC=abc,DC=local" -PassThru

# User-Password zurücksetzen

$InitPassword = [System.IO.Path]::GetRandomFileName() -replace "\.", "@" 
"Initialpasswort für die erste Anmeldung lautet: $InitPassword"
$InitPassword = $InitPassword | ConvertTo-SecureString -AsPlainText -Force
Get-ADUser -Identity "Peter Lustig" | 
    Set-ADAccountPassword -Reset -NewPassword $InitPassword -PassThru | 
    Set-ADUser -ChangePasswordAtLogon $true -AccountExpirationDate (Get-Date).AddMinutes(3)

#endregion

#region AD Group

Get-ADGroup -Identity Administratoren
Get-ADGroup -Identity S-1-5-32-544 -Properties member | Select-Object -ExpandProperty member
Get-ADGroup -Filter 'GroupCategory -eq "Security" -and GroupScope -ne "DomainLocal"'
Get-ADGroup -Server localhost -Filter {GroupScope -eq "DomainLocal"} -SearchBase "DC=abc, DC=local"

# ? Gruppen ohne Member:
Get-ADGroup -Properties member -Filter * | 
    Where-Object -FilterScript {$_.member.Count -eq 0} | 
    Select-Object -Property Name

# ? Wo ist der Administrator mitglied:
Get-ADPrincipalGroupMembership -Identity Administrator | Select-Object -Property distinguishedName

# ? Wo ist Wer mitglied:
Get-ADUser -Filter * -PipelineVariable user | 
    ForEach-Object -Process {
        $user | Get-ADPrincipalGroupMembership -PipelineVariable group | 
            ForEach-Object -Process {
                [PSCustomObject]@{
                    Username  = $user.Name;
                    GoupNamen = $group.Name
                }
            }
    }
 
#endregion

#region AD Computer

Get-ADComputer -Filter "Name -eq 'DC01'"

#endregion

#region AD Objekt

Search-ADAccount -PasswordNeverExpires -UsersOnly

#endregion

#region ADSI & LDAP

$rootDSE = [ADSI]"LDAP://rootDSE"
$adRootPath = $rootDSE.defaultNamingContext
$ad = [ADSI]"LDAP://$adRootPath"
$ad

$adComputer = [ADSI]'LDAP://CN=Computers,DC=abc,DC=local' 
$adComputer.Children

$User = [ADSI]"LDAP://cn=lustig, ou=ak, dc=abc, dc=local"
$UAC = $User.UserAccountControl[0] -bor 65536                                                                                             # Password never expire
$User.Put("userAccountControl",$UAC)
$User.SetInfo()


$admin = [ADSI]"LDAP://cn=Administrator,cn=Users,dc=abc,dc=local"
$admin.class
$admin.objectclass

$admin = [ADSI]"LDAP://cn=Administrator,cn=Users,dc=abc,dc=local"
$groups = $admin.MemberOf | ForEach-Object {[ADSI]"LDAP://$_"} 
$groups

([ADSI]'WinNT://lunar80/Administratoren,group').Add('WinNT://DOMAIN/USER,user')                                                            # Add a domain user to a remote server local group, if your current user has admin over the remote machine
([ADSI]'WinNT://lunar80,computer').psbase.children | Where-Object { $_.psbase.schemaClassName -eq 'group' } | ForEach-Object { ($_.name)[0]}              # Get all local groups on a remote server
([ADSI]'WinNT://lunar80/Administratoren,group').psbase.Invoke('Members') | ForEach-Object { $_.GetType().InvokeMember('ADspath', 'GetProperty', $null, $_, $null).Replace('WinNT://', '') }  # Find members of the local Administrators group on a remote server

$a=([ADSI]'WinNT://lunar80/Administrator,user');
$a.UserFlags=2; # Enable the local Administrator account on a remote server
$a.CommitChanges() 
 
$a=([ADSI]'WinNT://SERVER/Administrator,user');
$a.UserFlags=512; # Disable the local Administrator account on a remote server
$a.CommitChanges()

Start-Process https://technet.microsoft.com/en-us/library/ff730967.aspx

Get-ADObject -LDAPFilter "(&(operatingSystem=Windows Server 2012 R2 Datacenter)(objectClass=computer))" -SearchBase "dc=abc,dc=local" -SearchScope Subtree
Search-ADAccount -PasswordExpired -UsersOnly -SearchBase "dc=abc,dc=local" -SearchScope OneLevel 

$adSearcher = New-Object -TypeName DirectoryServices.DirectorySearcher
$adSearcher.Filter = "(objectCategory=user)"
$adSearcher.SearchRoot = "LDAP://DC=abc,DC=local"
$result = $adSearcher.FindAll()
$result | Get-Member
$result | Format-List *

$ACCOUNTDISABLE       = 0x000002
$DONT_EXPIRE_PASSWORD = 0x010000
$PASSWORD_EXPIRED     = 0x800000
$searcher = [adsisearcher]"(&(objectClass=user)(objectCategory=person))"
$searcher.FindAll() | ForEach-Object {
  $user = [adsi]$_.Properties.adspath[0]
  [PSCustomObject]@{
    SamAccountName       = $user.sAMAccountName[0]
    Name                 = $user.name[0]
    Mail                 = $user.mail[0]
    PasswordLastSet      = [DateTime]::FromFileTime($_.Properties.pwdlastset[0])
    Enabled              = -not [bool]($user.userAccountControl[0] -band $ACCOUNTDISABLE)
    PasswordNeverExpires =      [bool]($user.userAccountControl[0] -band $DONT_EXPIRE_PASSWORD)
    PasswordExpired      =      [bool]($user.userAccountControl[0] -band $PASSWORD_EXPIRED)
  }
}

#
# ODER per ActiveDirectory-Module:
#

Import-Module ActiveDirectory
$attributes = 'SamAccountName', 'Name', 'Mail', 'PasswordLastSet', 'Enabled','PasswordNeverExpires', 'PasswordExpired'
Get-ADUser -Filter * -Properties $attributes | Select-Object $attributes

#endregion

#region Tipps und Tricks

#region Zeigt vereinfacht ob die Rechte-Vererbung aktiviert ist oder nicht:

$result = Get-ChildItem -Path 'C:\Program Files' -Recurse -Force -Directory -ErrorAction SilentlyContinue | ForEach-Object {
    $acl = $_.FullName | Get-Acl
    [PSCustomObject]@{
        IsInherited    = $acl.Access[0].IsInherited; # ACHTUNG !!!!
        Name           = $_.Name;
        FullName       = $_.FullName;
        DeleteMe       = $false;
        AccessToString = $acl.AccessToString;
    }
}

$result | ForEach-Object {
    if($_.IsInherited)
    {
        $parenPath = Split-Path -Path $_.FullName -Parent
        $parent = $result | Where-Object { $_.FullName -eq $parenPath -and $_.DeleteMe -eq $false} 
        if($parent.IsInherited)
        {
            $_.DeleteMe = $true
        }
    }
}

$result | Out-GridView
$result | Where-Object DeleteMe -EQ $false | Out-GridView

#endregion

#endregion