Private/Wissen/X_Technology/X24_ActiveDirectory.ps1

<#
 
# Active Directory
 
PowerShell und Active Directory
 
- **Hashtags** ADS Forest OU Domain
- **Version** 2018.12.10
 
#>


#region GFU Orga

# PAUSEN: 10:30 12:15 14:30

\\SRV00\disk\Raum4 # Share

#endregion

#region Agenda

Start-Process "http://www.gfu.net/seminare-schulungen-kurse/erweiterungen_sk60/powershell_active_directory_administratoren_s1317.html"

# Grundlagen der PowerShell
# Was ist PowerShell?
# Parsing und PowerShell
# Pipelines und Befehle
#
# Active Directory Verwaltung mit der Powershell
# Verwaltung von Active Directory Objekten (OU, User, Computer, Group)
# Gruppenrichtlinien in der PowerShell
# Anlegen und Verwalten von Password Settings Objects
# Anlegen und Verwendung des Active Directory Papierkorbs
# Active Directory-Verwaltungscenter
# Verwaltung von Active Directory Standorten
# ADSI und die Powershell
#
# Arbeiten mit Typen, Operatoren und Ausdrücke
# Array-Operatoren
# Flusskontrolle und Funktionen
# .NET und WinForms

#endregion

#region Vorbereitung

#region ADS Forest aufsetzen

Add-WindowsFeature -Name AD-Domain-Services -IncludeAllSubFeature -IncludeManagementTools -LogPath C:\Users\Administrator\Desktop\AddWinFeature.log

Import-Module ADDSDeployment
Install-ADDSForest -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 (Read-Host -AsSecureString)

#endregion

Update-Help -Module * -UICulture de-DE, en-US -Force

#evtl. dcpromo

$cred = Get-Credential
Add-Computer -DomainName "abc" -Credential $cred

#endregion

#region Active Directory-Objekte

Get-Command -Module ActiveDirectory | Out-GridView

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

Show-Command New-ADUser
New-ADUser -Name sauer2 -Path "OU=AK, DC=abc, DC=local"
$ms = New-ADUser -Name mittelsauer -Path "OU=AK, DC=abc, DC=local" -PassThru
$ms | Get-Member

New-ADUser -Name sauer5 -Path "OU=AK, DC=abc, DC=local" -Enabled $true -AccountPassword (ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force)

# 1. Anmeldung Pwd ändern
# 2. Anmeldename fehlt
# 3. Job-Titel fehlt

New-ADUser -Name sauer6 -UserPrincipalName "sauer6" `
                        -ChangePasswordAtLogon $true `
                        -Title "Supporter" `
                        -Path "OU=AK, DC=abc, DC=local" -Enabled $true -AccountPassword (ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force)

#
# Benutzer über CSV hinzufügen
#

@"
UserName;InitialPassword
Uwe;P@ssw0rd
Inge;P@ssw0rd
Horst;P@ssw0rd
"@
 | Set-Content -Path c:\temp\NewUsers.csv

Import-Csv -Path C:\Temp\NewUsers.csv -Delimiter ";" | ForEach-Object {
    New-ADUser -Name $_.UserName `
               -UserPrincipalName $_.UserName `
               -Path "OU=AK, DC=abc, DC=local" `
               -Enabled $true -AccountPassword (ConvertTo-SecureString -String $_.InitialPassword `
                                                                       -AsPlainText `
                                                                       -Force)
}

Get-ADUser -Identity "lustig" | Get-Member
(Get-ADUser -Identity "lustig").gettype()

$Identity = "lustig"
$InitPassword = [System.IO.Path]::GetRandomFileName() -replace "\.", "@"
$bx = Get-ADUser -Identity $Identity | Set-ADAccountPassword -Reset -NewPassword (ConvertTo-SecureString $InitPassword -A -f) -PassThru
$bx | Set-ADUser -ChangePasswordAtLogon $true -AccountExpirationDate (Get-Date).AddMinutes(3)

function Reset-ADUserPassword
{
    <#
        .SYNOPSIS
            bla bla bla
 
        .DESCRIPTION
            hmmm hmmm hmm
 
        .EXAMPLE
            Reset-ADUserPassword -Identity "lustig"
            bla bla bla
 
    #>

    param
    (
        # Geben Sie .....
        [Parameter(Mandatory=$true)]
        [string]$Identity
    )
    $InitPassword = [System.IO.Path]::GetRandomFileName() -replace "\.", "@0G"
    $bx = Get-ADUser -Identity $Identity | Set-ADAccountPassword -Reset -NewPassword (ConvertTo-SecureString $InitPassword -A -f) -PassThru
    $bx | Set-ADUser -ChangePasswordAtLogon $true -AccountExpirationDate (Get-Date).AddMinutes(3)
    [pscustomobject]@{"Initial Passwort für die erste Anmeldung"=$InitPassword}
}

Reset-ADUserPassword -Identity "lustig" | Out-GridView
Show-Command Reset-ADUserPassword  -ErrorPopup

#
# AD Gruppen
#

Get-ADGroup -Identity administratoren

$a = Get-ADGroup -Identity S-1-5-32-544 -Properties member
$a.member | Get-Member
$a.member[0]
$a.member | Get-ADObject
Get-ADGroup -Filter 'GroupCategory -eq "Security" -and GroupScope -ne "DomainLocal"'
Get-ADGroup -Server localhost  -Filter {GroupScope -eq "DomainLocal"} -SearchBase "DC=abc,DC=local"

$zeroGrps = @()
$a = Get-ADGroup -Properties member -Filter *
foreach ($item in $a)
{
    if($item.member.Count -eq 0)
    {
        $zeroGrps += $item
    }
}
$filename = "LeereGruppen_vom_{0:yyyy-MM-dd}.html" -f (Get-Date)
$zeroGrps | ConvertTo-Html -Property Name -PreContent "Leere AD-Gruppen vom $(Get-Date)" | Out-File ".\$filename"

# vs.

Get-ADGroup -Properties member -Filter * |
    Where-Object {$_.member.Count -eq 0} |
    ConvertTo-Html -Property Name -PreContent "Leere AD-Gruppen vom $(Get-Date)"


Get-ADUser -Identity Administrator

Get-Command -Name *group* -Module ActiveDirectory

# Wo ist der Administrator mitglied?
Get-ADPrincipalGroupMembership -Identity Administrator | Format-Table Name

# Wo ist Wer mitglied?
Get-ADUser -Filter * | ForEach-Object {
    $user = $_
    $_ | Get-ADPrincipalGroupMembership | ForEach-Object {
        [PSCustomObject]@{Username=$user.Name;GoupName=$_.Name }
    }
} | ConvertTo-Html | Out-File .\UsersGroups.html

#endregion

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

#region ADSI & LDAP

Start-Process http://www.powershellpraxis.de/index.php/active-directory/activedirectory-provider

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

$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 { $_.psbase.schemaClassName -eq 'group' } | foreach { ($_.name)[0]}              # Get all local groups on a remote server
([ADSI]'WinNT://lunar80/Administratoren,group').psbase.Invoke('Members') | foreach { $_.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 | fl *

$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 $attributes

#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 | ? Name -EQ PasswordComplexity | select -ExpandProperty SettingBoolean

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

#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" |
               ? {$_.objectClass -eq "group"}|
               % {Get-ADGroupMember $_.Name -Recursive} |
               ? {$_.objectClass -eq "user"} |
               select -Unique

$allUsers = Get-AdUser -Filter *

$allUsersNotinPSO = Compare-Object -ReferenceObject $allUsers -DifferenceObject $allPSOUsers -PassThru | select 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

#endregion

#region Active Directory-Verwaltungscenter

# Siehe "Windows PowerShell-Verlauf History"

"$env:windir\system32\dsac.exe"

# siehe auch: https://technet.microsoft.com/de-de/library/jj574144(v=ws.11).aspx

#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 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 TODO AUFBEREITEN

<#
 
# Active Directory Services
 
PowerShell trifft ADS
 
- **Hashtags** ADS ActiveDirectory
- **Version** 2020.01.19
 
#>


# TODO Weiterführende und Nachschlage-Informationen

Get-Help -Name "about_Group_Policy_Settings" -ShowWindow # Beschreibt die Gruppenrichtlinieneinstellungen für Windows PowerShell

# 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


#endregion