Gruppenrichtlinien mit PowerShell verwalten

Trotz Intune, DSC und Entra ID (Azure AD); Gruppenrichtlinien sind in vielen Firmen immer noch ein weit verbreitete Methode um Windows Clients und Server zu verwalten. Die MMC ist aber nicht wirklich dazu geeignet mehrere hundert GPOs zu verwalten. Doch dafür gibt es PowerShell.
Die meisten werden Get-GPO
schon genutzt haben, aber Microsoft liefert noch 25 weitere cmdlets und zwei Alias im Modul GroupPolicy
.
|
CommandType Name Version Source
----------- ---- ------- ------
Alias Get-GPPermissions 1.0.0.0 GroupPolicy
Alias Set-GPPermissions 1.0.0.0 GroupPolicy
Cmdlet Backup-GPO 1.0.0.0 GroupPolicy
Cmdlet Copy-GPO 1.0.0.0 GroupPolicy
Cmdlet Get-GPInheritance 1.0.0.0 GroupPolicy
Cmdlet Get-GPO 1.0.0.0 GroupPolicy
Cmdlet Get-GPOReport 1.0.0.0 GroupPolicy
Cmdlet Get-GPPermission 1.0.0.0 GroupPolicy
Cmdlet Get-GPPrefRegistryValue 1.0.0.0 GroupPolicy
Cmdlet Get-GPRegistryValue 1.0.0.0 GroupPolicy
Cmdlet Get-GPResultantSetOfPolicy 1.0.0.0 GroupPolicy
Cmdlet Get-GPStarterGPO 1.0.0.0 GroupPolicy
Cmdlet Import-GPO 1.0.0.0 GroupPolicy
Cmdlet Invoke-GPUpdate 1.0.0.0 GroupPolicy
Cmdlet New-GPLink 1.0.0.0 GroupPolicy
Cmdlet New-GPO 1.0.0.0 GroupPolicy
Cmdlet New-GPStarterGPO 1.0.0.0 GroupPolicy
Cmdlet Remove-GPLink 1.0.0.0 GroupPolicy
Cmdlet Remove-GPO 1.0.0.0 GroupPolicy
Cmdlet Remove-GPPrefRegistryValue 1.0.0.0 GroupPolicy
Cmdlet Remove-GPRegistryValue 1.0.0.0 GroupPolicy
Cmdlet Rename-GPO 1.0.0.0 GroupPolicy
Cmdlet Restore-GPO 1.0.0.0 GroupPolicy
Cmdlet Set-GPInheritance 1.0.0.0 GroupPolicy
Cmdlet Set-GPLink 1.0.0.0 GroupPolicy
Cmdlet Set-GPPermission 1.0.0.0 GroupPolicy
Cmdlet Set-GPPrefRegistryValue 1.0.0.0 GroupPolicy
Cmdlet Set-GPRegistryValue 1.0.0.0 GroupPolicy
Gruppenrichtlinien finden
Leider unterstützt Get-Gpo
keinerlei Suchfilter sondern kann nur alle oder eine GPO ausgeben. Dabei kann man über -Id
oder -Name
einzelne Gruppenrichtlinien angeben, muss aber die Werte exakt kennen. Mit dem Parameter -All
wird eine Liste aller GPOs ausgeben.
Eine Filter kann daher immer erst im Nachgang angewendet werden.
|
Gruppenrichtlinien erstellen
Um eine neue, leere Gruppenrichtlinie anzulegen muss man nicht viel Informationen liefern. Ein sprechender Name ist ausreichend, ein beschreibender Kommentar wünschenswert.
|
DisplayName : MSFT Windows Server 2022 - Member Server
DomainName : lab.bader.cloud
Owner : LAB\Domain Admins
Id : 0ef52ff6-0ef0-42e1-9273-508463a69a44
GpoStatus : AllSettingsEnabled
Description : Microsoft Security Baseline
CreationTime : 11/15/2021 8:07:55 PM
ModificationTime : 11/15/2021 8:07:55 PM
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
WmiFilter :
Einstellungen importieren
Bei z.B. Security Baselines werden häufig Exporte von Gruppenrichtlinien als Vorlagen geliefert. So macht es auch Microsoft mit Ihrem Microsoft Security Compliance Toolkit. Dieses enthält für alle gängigen Betriebssysteme und Browser die von Microsoft empfohlenen Einstellungen.
Um diese Vorlagen zu importieren kann Import-GPO
genutzt werden. Dieses cmdlet überschreibt alle in der Gruppenrichtlinie vorhandenen Einstellungen
|
Anstatt die GPO schon vorher anzulegen kann dies mit dem Parameter -CreateIfNeeded
in einem Schritt gemacht werden.
|
Beim Import einer GPO kann auch eine Mapping Datei angegeben werden. Diese übersetzt z.B. SIDs von einer Domäne in die andere.
|
Die benötigte .migtable
Datei muss dabei manuell erstellt werden. Hier empfiehlt es sich eventuell doch einmal die GUI zu nutzen und das entsprechende Mapping für die zukünftige Nutzung zu speichern. Wer darauf keine Lust hat kann die Datei auch leicht von Hand erstellen. Es handelt sich um eine XML Datei wie in diesem Beispiel zu sehen.
|
Report erstellen
Ähnlich wie in der GUI kann man sich die Konfiguration einer Gruppenrichtlinie ausgeben lassen. Dabei können jedoch unterschiedliche Formate gewählt werden.
- HTML = Der aus der MMC bekannt Report der im Browser angesehen werden kann
- XML = Ausgabe im XML Formart. Dies ermöglicht es z.B. die Informationen mittels PowerShell weiter zu verarbeiten.
|
Get-GPOReport
ist leider nicht sehr performant, weswegen ich das cmdlet nicht für Auswertungen über viele Gruppenrichtlinien empfehlen kann.OU Link erstellen und verändern
Damit eine GPO überhaupt erst angewendet wird, muss diese mit einer oder mehrerer OUs, Domänen oder Sites verknüpft werden. New-GPLink
erledigt dies zuverlässig. Will man anschließend diese Verknüpfung anpassen ist dies mit Set-GPLink
leicht möglich. Das erleichtert z.B. die Anpassung der Link Order ungemein.
|
Enforced
wird die Einstellungen dieser Gruppenrichtlinie immer angewendet unabhängig von der “Link Order” oder unterbrochener Vererbung.
|
Link entfernen
Ebenso einfach lässt sich eine solche Verknüpfung wieder entfernen.
|
Zugewiesene Gruppenrichtlinien ermitteln
Um herauszufinden welche GPO an einer bestimmten OU überhaupt wirken wird Get-GPInheritance
genutzt.
|
Name : demoou
ContainerType : OU
Path : ou=demoou,dc=lab,dc=bader,dc=cloud
GpoInheritanceBlocked : No
GpoLinks : {}
InheritedGpoLinks : {Default Domain Policy}
Vererbung unterbrechen
|
Name : demoou
ContainerType : OU
Path : ou=demoou,dc=lab,dc=bader,dc=cloud
GpoInheritanceBlocked : Yes
GpoLinks : {}
InheritedGpoLinks : {}
WMI Filter zuweisen
Das Erstellen von WMI Filtern ist leider über die PowerShell nicht mit nativen cmdlets möglich. Natürlich hat die Community nachgelegt und ein entsprechendes Modul zu Verfügung gestellt. GPWmiFilter von Friedrich Weinmann.
Was nativ jedoch möglich ist, ist es wenn ein WMI schon in Verwendung ist, diesen einer weiteren GPO zuzuweisen.
|
Berechtigungen auslesen
Um die Berechtigungen auszulesen die einer Gruppenrichtlinie zugewiesen sind, sollte Get-GPPermission
genutzt werden. Auch hier ist wieder möglich alle auszulesen, oder nur für eine benannte Gruppe oder AD Objekt.
|
Trustee : Authenticated Users
TrusteeType : WellKnownGroup
Permission : GpoApply
Inherited : False
Trustee : Domain Admins
TrusteeType : Group
Permission : GpoEditDeleteModifySecurity
Inherited : False
Trustee : Enterprise Admins
TrusteeType : Group
Permission : GpoEditDeleteModifySecurity
Inherited : False
Trustee : ENTERPRISE DOMAIN CONTROLLERS
TrusteeType : WellKnownGroup
Permission : GpoRead
Inherited : False
Trustee : SYSTEM
TrusteeType : WellKnownGroup
Permission : GpoEditDeleteModifySecurity
Inherited : False
|
Trustee : Authenticated Users
TrusteeType : WellKnownGroup
Permission : GpoApply
Inherited : False
Berechtigungen setzen
Soll eine Gruppenrichtlinie nur einer speziellen Gruppe an Personen zugewiesen werden muss z.B. immer die Berechtigung der Authenticated Users verändert werden. Diese dürfen unter keinen Umständen einfach entfernt werden.
Der Standardmodus des cmdlets Set-GPPermission
ist additiv, die benannten Rechte werden hinzugefügt. Sollten schon höhere Rechte vorhanden sein, bleiben diese bestehen. Daher ist die korrekte Verwendung des Parameters -Replace
wichtig.
|
Dasselbe cmdlet wird auch verwendet wenn Berechtigungen entfernt werden sollen. Hier wird als PermissionLevel
None angegeben und der Parameter -Replace
genutzt.
|
Backup
Eine Sicherung der Gruppenrichtlinien ist mit Backup-GPO
sehr einfach. Es wird für jedes Backup ein neues Verzeichnis mit einer GUID erstellt und alle relevanten Daten in diesem Verzeichnis gespeichert. Eine regelmäßige Sicherung aller GPOs ist damit kein Problem.
|
Werte auslesen
Um einzelne Werte aus einer GPO auszulesen gibt es zwei cmdlets: Get-GPPrefRegistryValue
und Get-GPRegistryValue
.
Der Unterschied der beiden cmdlets besteht darin, Art von Registry Wert sie aus der Gruppenrichtlinie auslesen.
Get-GPPrefRegistryValue
liest Werte aus, die unterhalb von Computer -> Preferences -> Windows Settings -> Registry angelegt wurden. Dies sind nicht die Werte die in der GUI über ADMX Dateien gesteuert werden, sondern Werte die man manuell hinzufügt. Sie sind nicht auf HKEY_LOCAL_(MACHINE|USER)\SOFTWARE\Policies\
beschränkt.
Get-GPRegistryValue
ist alles was über eine ADMX Datei in der registry.pol
gespeichert wird. Dies ist in den meisten Fällen der Bereich den man auch bearbeiten möchte.
Unter Angabe des Registry -Key
können alle Werte in diesem ausgelesen werden.
|
KeyPath : SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
FullKeyPath : HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
Hive : LocalMachine
PolicyState : Set
Value : 0
Type : DWord
ValueName : AllowBasic
HasValue : True
KeyPath : SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
FullKeyPath : HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
Hive : LocalMachine
PolicyState : Set
Value : 0
Type : DWord
ValueName : AllowUnencryptedTraffic
HasValue : True
KeyPath : SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
FullKeyPath : HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
Hive : LocalMachine
PolicyState : Set
Value : 1
Type : DWord
ValueName : DisableRunAs
HasValue : True
|
KeyPath : SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
FullKeyPath : HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service
Hive : LocalMachine
PolicyState : Set
Value : 0
Type : DWord
ValueName : AllowBasic
HasValue : True
Werte setzen
Mittels Set-GPRegistryValue
lassen sich einzelne Werte in der GPO auch verändern. Somit ist zum setzen von neuen Einstellungen nicht mehr die MMC notwendig, sondern nur noch das Wissen in welchem Registry Key sich welche Einstellung verbirgt.
Hierbei ist die Webseite admx.help eine große Hilfe. Für fast alle ADMX Dateien werden die entsprechenden Werte aufbereitet dargestellt und die notwendigen Informationen zu “Registry Path” und Value Name/Type und möglichen Werten aufgeschlüsselt.
Hier am Beispiel der Einstellung Turn off real-time protection
|
Werte recursive auslesen
Da es mit dem nativen cmdlet Get-GPRegistryValue
nicht möglich ist mehr als eine Ebene auszulesen, habe ich inspiriert von diesem Snippet eine Funktion erstellt die dies erlaubt. So können alle Einstellungen einer Gruppenrichtlinie als PolicyRegistrySetting Objekte auszugeben und direkt weiterverarbeitet werden. Dies ist um ein vielfaches schneller als das cmdlet Get-GPOReport
.
|
Beispielhafte Anwendung mit Pipelining
|
Gruppenrichtlinien zusammenführen
Mit dem eben Gelernten lässt sich auch ein weiteres Problem leicht lösen: Wie kann man zwei Gruppenrichtlinien in zusammenführen?
Da die GUI nur den Import anbietet, diese Funktion aber alle bestehenden Einstellungen überschreibt bleibt auch hier nur der Griff zur PowerShell.
Im folgenden Beispiel lese ich erst rekursiv alle Werte unterhalb des Registry Keys HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\
aus, um diese anschließend mittels Set-GPRegistryValue
in die schon bestehenden GPO “MSFT Windows Server 2022 - Member Server” zu übernehmen.
|
Jedoch nicht alle Werte, sondern nur Werte die in Konflikt mit der Quell GPO stehen.
Dieses Beispiel lässt sich sehr leicht anpassen um alle “Computer” Werte zu übernehmen.
|
Firewalleinstellungen bearbeiten
Um die Windows Defender Firewall Einstellungen bearbeiten zu können taugt keiner der oben genannten Befehle. Jedoch hat Microsoft noch zwei weitere cmdlets, besser gesagt Function, im Petto.
|
CommandType Name Version Source
----------- ---- ------- ------
Function Open-NetGPO 2.0.0.0 NetSecurity
Function Save-NetGPO 2.0.0.0 NetSecurity
Application chgport.exe 10.0.22... C:\Windows\system32\chgport.exe
Open-NetGPO
erstellt eine WMI Session zu einer bestehenden Gruppenrichtlinie und erlaubt es dann, diese mit den normalen cmdlets um Firewallregeln zu verwalten zu nutzen. Die WMI Session muss dabei immer an den Parameter -GPOSession
übergeben werden.
-GPOSession
in der Windows 11 von Get-NetFirewallRule
nicht mehr vorhanden. Hier kann alternativ -PolicyStore
genutzt werden.
|
Auswertungen über alle GPOs
Mir kam immer wieder folgende Problemstellung unter: In welcher Gruppenrichtlinie ist einer oder mehrere Einstellungen gesetzt und wenn ja mit welchem Wert.
Die einzige Antwort die ich bisher im Internet gefunden habe, war die Nutzung von Get-GPOReport
mit der Umwandlung als XML und anschließender Auswertung der XML Dateien. Leider ist das sehr sehr langsam, bei mehreren hundert, vielleicht sogar tausenden GPOs in der Umgebung ist dies keine echte Lösung.
Daher habe ich das Skript CheckGPOSettings.ps1
erstellt.
Dieses Skript analysiert anhand einer übergebenen Hashtable alle Gruppenrichtlinien in einer oder auch mehrere Domains nach einem oder mehrere Werte und liefert die Ergebnisse als PowerShell Objekt zurück. Dadurch können diese sehr einfach weiter verarbeitet werden. Und das Beste ist, es werden alle typischen Speicherorte innerhalb der GPO durchsucht. Egal ob Get-GPRegistryValue
, GptTmpl.inf
oder Get-GPPrefRegistryValue
, das Script findet sie alle.
audit.csv
nicht unterstützt.Query Hashtable
Die Hashtable die für die Suche genutzt wird, besteht aus zwei verschachtelten Hashtables. Die äußere nutzt als Key einen frei wählbaren Namen für den gesuchten Wert. Hier sollte z.B. der sprechende Name der Einstellung genutzt werden.
Als Value wird ein weiteres Hashtable verwendet, dieses beschreibt den zu suchenden Wert. Als Key wird hier der Registry Key genutzt und als Value den Value Name des Registry Items.
|
In folgendem Beispiel suche ich zwei verschiedene Registry Settings. Das erste ist das LAN Manager Authentication Level (steht hoffentlich auf 5) und das zweite ist der Wert für den Service MrxSmb10
besser bekannt als SMBv1. hier ist als Wert 4 wünschenswert (Deaktiviert).
|
Anschließend starte ich die Funktion Get-SettingsFromGPOs
und übergebe die zu prüfenden Domain und das eben erstelle Hashtable.
|
Als Ergebnis bekomme ich folgenden Informationen geliefert:
- In welcher Domäne ist die Gruppenrichtlinie vorhanden
- Wie lautet der Name der Gruppenrichtlinie
- Wo ist diese Gruppenrichtlinie verknüpft*
- Angewendeten WMI Filter
- Den Pfad zur GPO
- aktueller Status der GPO (Enabled/Disabled)
- Den selbstgewählten Namen für die Einstellung
- Den Registry Key
- Den Namen des RegistryItem
- Den Wert des RegistryItem
- Den Typ des RegistryItem
DomainName : lab.bader.cloud
GPO : MSFT Windows Server 2022 - Domain Controller
GPOLinks :
Setting : Network security: LAN Manager authentication level
ValueName : LmCompatibilityLevel
Hive : HKLM\System\CurrentControlSet\Control\Lsa
WmiFilter :
PolicyState :
Value : 5
Type : REG_DWORD
Path : cn={1C09EB8B-1EB0-488B-A92C-34030213F58B},cn=policies,cn=system,DC=lab,DC=bader,DC=cloud
DomainName : lab.bader.cloud
GPO : MSFT Windows Server 2022 - Domain Controller
GPOLinks :
Setting : SMBv1 service state
ValueName : Start
Hive : HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\MrxSmb10
WmiFilter :
PolicyState : Set
Value : 4
Type : DWord
Path : cn={1C09EB8B-1EB0-488B-A92C-34030213F58B},cn=policies,cn=system,DC=lab,DC=bader,DC=cloud
* Die GPLinks kann ich aktuell nur unter Verwendung des cmdlets Get-GPReport
herausfinden. Dieses wird aber immer nur dann gestartet, wenn der gesuchte Wert in der Gruppenrichtlinie gefunden wurde. Für zusätzliche Performance habe ich den Schalten -NoGPLink
eingebaut. Dieser hat in meiner kleinen Demoumgebung die Ausführungszeit von 776ms auf 568ms verbessert. In besonders großen Umgebungen kann sich das also lohnen.
In diesem diesem GitHub Repository findet Ihr weitere Beispiele und das Repository steht für Pull Requests offen. So kann über die Zeit eine Sammlung an Suchparametern zusammengetragen werden.
Fazit
Mit der PowerShell lassen sich Gruppenrichtlinien sehr umfangreich manipulieren und wie so häufig spart dies viel Zeit. Leider ist der Einstieg nicht ganz so einfach wie bei anderen cmdlets, aber wenn man das Grundkonzept durchschaut hat lassen sich damit viele tolle Sache realisieren.
Wer genau aufgepasst hat, wird bemerkt haben das es bestimmte cmdlets nicht in den Blogartikel geschafft haben. Das hat entweder den Grund das diese selbsterklärend sind (Copy-GPO
), der Gegenpart vorgestellt wurde (Remove-GPRegistryValue
) oder ich diese einfach nicht nutze (*-GPStarterGPO
).
Daher fehlen Beispiele für folgende cmdlets
Copy-GPO
Get-GPStarterGPO
Invoke-GPUpdate
New-GPStarterGPO
Remove-GPPrefRegistryValue
Remove-GPRegistryValue
Rename-GPO
Restore-GPO