GPOZaurr.psm1
function ConvertFrom-DistinguishedName { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER DistinguishedName Parameter description .PARAMETER ToOrganizationalUnit Parameter description .EXAMPLE $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToOrganizationalUnit Output: OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName Output: Przemyslaw Klys .NOTES General notes #> [CmdletBinding()] param([string[]] $DistinguishedName, [switch] $ToOrganizationalUnit, [switch] $ToDC, [switch] $ToDomainCN) if ($ToDomainCN) { $DN = $DistinguishedName -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1' $CN = $DN -replace ',DC=', '.' -replace "DC=" $CN } elseif ($ToOrganizationalUnit) { return [Regex]::Match($DistinguishedName, '(?=OU=)(.*\n?)(?<=.)').Value } elseif ($ToDC) { $DistinguishedName -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1' } else { $Regex = '^CN=(?<cn>.+?)(?<!\\),(?<ou>(?:(?:OU|CN).+?(?<!\\),)+(?<dc>DC.+?))$' $Output = foreach ($_ in $DistinguishedName) { $_ -match $Regex $Matches } $Output.cn } } function ConvertFrom-SID { [cmdletbinding()] param([string[]] $SID, [switch] $OnlyWellKnown, [switch] $OnlyWellKnownAdministrative) $WellKnownAdministrative = @{'S-1-5-18' = 'NT AUTHORITY\SYSTEM' } $wellKnownSIDs = @{'S-1-0' = 'Null AUTHORITY' 'S-1-0-0' = 'NULL SID' 'S-1-1' = 'WORLD AUTHORITY' 'S-1-1-0' = 'Everyone' 'S-1-2' = 'LOCAL AUTHORITY' 'S-1-2-0' = 'LOCAL' 'S-1-2-1' = 'CONSOLE LOGON' 'S-1-3' = 'CREATOR AUTHORITY' 'S-1-3-0' = 'CREATOR OWNER' 'S-1-3-1' = 'CREATOR GROUP' 'S-1-3-2' = 'CREATOR OWNER SERVER' 'S-1-3-3' = 'CREATOR GROUP SERVER' 'S-1-3-4' = 'OWNER RIGHTS' 'S-1-5-80-0' = 'NT SERVICE\ALL SERVICES' 'S-1-4' = 'Non-unique Authority' 'S-1-5' = 'NT AUTHORITY' 'S-1-5-1' = 'NT AUTHORITY\DIALUP' 'S-1-5-2' = 'NT AUTHORITY\NETWORK' 'S-1-5-3' = 'NT AUTHORITY\BATCH' 'S-1-5-4' = 'NT AUTHORITY\INTERACTIVE' 'S-1-5-6' = 'NT AUTHORITY\SERVICE' 'S-1-5-7' = 'NT AUTHORITY\ANONYMOUS LOGON' 'S-1-5-8' = 'NT AUTHORITY\PROXY' 'S-1-5-9' = 'NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS' 'S-1-5-10' = 'NT AUTHORITY\SELF' 'S-1-5-11' = 'NT AUTHORITY\Authenticated Users' 'S-1-5-12' = 'NT AUTHORITY\RESTRICTED' 'S-1-5-13' = 'NT AUTHORITY\TERMINAL SERVER USER' 'S-1-5-14' = 'NT AUTHORITY\REMOTE INTERACTIVE LOGON' 'S-1-5-15' = 'NT AUTHORITY\This Organization' 'S-1-5-17' = 'NT AUTHORITY\IUSR' 'S-1-5-18' = 'NT AUTHORITY\SYSTEM' 'S-1-5-19' = 'NT AUTHORITY\NETWORK SERVICE' 'S-1-5-20' = 'NT AUTHORITY\NETWORK SERVICE' 'S-1-5-32-544' = 'BUILTIN\Administrators' 'S-1-5-32-545' = 'BUILTIN\Users' 'S-1-5-32-546' = 'BUILTIN\Guests' 'S-1-5-32-547' = 'BUILTIN\Power Users' 'S-1-5-32-548' = 'BUILTIN\Account Operators' 'S-1-5-32-549' = 'BUILTIN\Server Operators' 'S-1-5-32-550' = 'BUILTIN\Print Operators' 'S-1-5-32-551' = 'BUILTIN\Backup Operators' 'S-1-5-32-552' = 'BUILTIN\Replicators' 'S-1-5-64-10' = 'NT AUTHORITY\NTLM Authentication' 'S-1-5-64-14' = 'NT AUTHORITY\SChannel Authentication' 'S-1-5-64-21' = 'NT AUTHORITY\Digest Authentication' 'S-1-5-80' = 'NT SERVICE' 'S-1-5-83-0' = 'NT VIRTUAL MACHINE\Virtual Machines' 'S-1-16-0' = 'Untrusted Mandatory Level' 'S-1-16-4096' = 'Low Mandatory Level' 'S-1-16-8192' = 'Medium Mandatory Level' 'S-1-16-8448' = 'Medium Plus Mandatory Level' 'S-1-16-12288' = 'High Mandatory Level' 'S-1-16-16384' = 'System Mandatory Level' 'S-1-16-20480' = 'Protected Process Mandatory Level' 'S-1-16-28672' = 'Secure Process Mandatory Level' 'S-1-5-32-554' = 'BUILTIN\Pre-Windows 2000 Compatible Access' 'S-1-5-32-555' = 'BUILTIN\Remote Desktop Users' 'S-1-5-32-556' = 'BUILTIN\Network Configuration Operators' 'S-1-5-32-557' = 'BUILTIN\Incoming Forest Trust Builders' 'S-1-5-32-558' = 'BUILTIN\Performance Monitor Users' 'S-1-5-32-559' = 'BUILTIN\Performance Log Users' 'S-1-5-32-560' = 'BUILTIN\Windows Authorization Access Group' 'S-1-5-32-561' = 'BUILTIN\Terminal Server License Servers' 'S-1-5-32-562' = 'BUILTIN\Distributed COM Users' 'S-1-5-32-569' = 'BUILTIN\Cryptographic Operators' 'S-1-5-32-573' = 'BUILTIN\Event Log Readers' 'S-1-5-32-574' = 'BUILTIN\Certificate Service DCOM Access' 'S-1-5-32-575' = 'BUILTIN\RDS Remote Access Servers' 'S-1-5-32-576' = 'BUILTIN\RDS Endpoint Servers' 'S-1-5-32-577' = 'BUILTIN\RDS Management Servers' 'S-1-5-32-578' = 'BUILTIN\Hyper-V Administrators' 'S-1-5-32-579' = 'BUILTIN\Access Control Assistance Operators' 'S-1-5-32-580' = 'BUILTIN\Remote Management Users' } foreach ($S in $SID) { if ($OnlyWellKnownAdministrative) { if ($WellKnownAdministrative[$S]) { [PSCustomObject] @{Name = $WellKnownAdministrative[$S] SID = $S Type = 'WellKnownAdministrative' Error = '' } } } elseif ($OnlyWellKnown) { if ($wellKnownSIDs[$S]) { [PSCustomObject] @{Name = $wellKnownSIDs[$S] SID = $S Type = 'WellKnownGroup' Error = '' } } } else { if ($wellKnownSIDs[$S]) { [PSCustomObject] @{Name = $wellKnownSIDs[$S] SID = $S Type = 'WellKnownGroup' Error = '' } } else { try { [PSCustomObject] @{Name = (([System.Security.Principal.SecurityIdentifier]::new($S)).Translate([System.Security.Principal.NTAccount])).Value SID = $S Type = 'Standard' Error = '' } } catch { [PSCustomObject] @{Name = $S SID = $S Error = $_.Exception.Message -replace [environment]::NewLine, ' ' Type = 'Unknown' } } } } } } function Get-ADACL { [cmdletbinding()] param([Parameter(ValueFromPipeline)][Array] $ADObject, [string] $Domain = $Env:USERDNSDOMAIN, [Object] $Server, [string] $ForestName, [switch] $Extended, [switch] $ResolveTypes, [switch] $Inherited, [switch] $NotInherited, [switch] $Bundle, [System.DirectoryServices.ActiveDirectoryRights[]] $IncludeActiveDirectoryRights, [System.DirectoryServices.ActiveDirectoryRights[]] $ExcludeActiveDirectoryRights, [System.DirectoryServices.ActiveDirectorySecurityInheritance[]] $IncludeActiveDirectorySecurityInheritance, [System.DirectoryServices.ActiveDirectorySecurityInheritance[]] $ExcludeActiveDirectorySecurityInheritance) Begin { if (-not $Script:ForestGUIDs) { Write-Verbose "Get-ADACL - Gathering Forest GUIDS" $Script:ForestGUIDs = Get-WinADForestGUIDs } if ($ResolveTypes) { if (-not $Script:ForestCache) { Write-Verbose "Get-ADACL - Building Cache" $Script:ForestCache = Get-WinADCache -ByNetBiosName } } } Process { foreach ($Object in $ADObject) { if ($Object -is [Microsoft.ActiveDirectory.Management.ADOrganizationalUnit] -or $Object -is [Microsoft.ActiveDirectory.Management.ADEntity]) { [string] $DistinguishedName = $Object.DistinguishedName [string] $CanonicalName = $Object.CanonicalName [string] $ObjectClass = $Object.ObjectClass } elseif ($Object -is [string]) { [string] $DistinguishedName = $Object [string] $CanonicalName = '' [string] $ObjectClass = '' } else { Write-Warning "Get-ADACL - Object not recognized. Skipping..." continue } $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToDC) -replace '=' -replace ',' if (-not (Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { Write-Verbose "Get-ADACL - Enabling PSDrives for $DistinguishedName to $DNConverted" New-ADForestDrives -ForestName $ForestName if (-not (Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { Write-Warning "Get-ADACL - Drive $DNConverted not mapped. Terminating..." return } } Write-Verbose "Get-ADACL - Getting ACL from $DistinguishedName" try { $PathACL = "$DNConverted`:\$($DistinguishedName)" $ACLs = Get-Acl -Path $PathACL -ErrorAction Stop } catch { Write-Warning "Get-ADACL - Path $PathACL - Error: $($_.Exception.Message)" } $AccessObjects = foreach ($ACL in $ACLs.Access) { [Array] $ADRights = $ACL.ActiveDirectoryRights -split ', ' if ($Inherited) { if ($ACL.IsInherited -eq $false) { continue } } if ($NotInherited) { if ($ACL.IsInherited -eq $true) { continue } } if ($IncludeActiveDirectoryRights) { $FoundInclude = $false foreach ($Right in $ADRights) { if ($IncludeActiveDirectoryRights -contains $Right) { $FoundInclude = $true break } } if (-not $FoundInclude) { continue } } if ($ExcludeActiveDirectoryRights) { foreach ($Right in $ADRights) { $FoundExclusion = $false if ($ExcludeActiveDirectoryRights -contains $Right) { $FoundExclusion = $true break } if ($FoundExclusion) { continue } } } if ($IncludeActiveDirectorySecurityInheritance) { if ($IncludeActiveDirectorySecurityInheritance -notcontains $ACL.InheritanceType) { continue } } if ($ExcludeActiveDirectorySecurityInheritance) { if ($ExcludeActiveDirectorySecurityInheritance -contains $ACL.InheritanceType) { continue } } if ($ACL.IdentityReference -like '*\*') { if ($ResolveTypes -and $Script:ForestCache) { $TemporaryIdentity = $Script:ForestCache["$($ACL.IdentityReference)"] $IdentityReferenceType = $TemporaryIdentity.ObjectClass $IdentityReference = $ACL.IdentityReference.Value } else { $IdentityReferenceType = '' $IdentityReference = $ACL.IdentityReference.Value } } elseif ($ACL.IdentityReference -like '*-*-*-*') { $ConvertedSID = ConvertFrom-SID -SID $ACL.IdentityReference if ($ResolveTypes -and $Script:ForestCache) { $TemporaryIdentity = $Script:ForestCache["$($ConvertedSID.Name)"] $IdentityReferenceType = $TemporaryIdentity.ObjectClass } else { $IdentityReferenceType = '' } $IdentityReference = $ConvertedSID.Name } else { $IdentityReference = $ACL.IdentityReference $IdentityReferenceType = 'Unknown' } $ReturnObject = [ordered] @{} $ReturnObject['DistinguishedName' ] = $DistinguishedName if ($CanonicalName) { $ReturnObject['CanonicalName'] = $CanonicalName } if ($ObjectClass) { $ReturnObject['ObjectClass'] = $ObjectClass } $ReturnObject['AccessControlType'] = $ACL.AccessControlType $ReturnObject['Principal'] = $IdentityReference if ($ResolveTypes) { $ReturnObject['PrincipalType'] = $IdentityReferenceType } $ReturnObject['ObjectTypeName'] = $Script:ForestGUIDs["$($ACL.objectType)"] $ReturnObject['InheritedObjectTypeName'] = $Script:ForestGUIDs["$($ACL.inheritedObjectType)"] $ReturnObject['ActiveDirectoryRights'] = $ACL.ActiveDirectoryRights $ReturnObject['InheritanceType'] = $ACL.InheritanceType $ReturnObject['IsInherited'] = $ACL.IsInherited if ($Extended) { $ReturnObject['ObjectType'] = $ACL.ObjectType $ReturnObject['InheritedObjectType'] = $ACL.InheritedObjectType $ReturnObject['ObjectFlags'] = $ACL.ObjectFlags $ReturnObject['InheritanceFlags'] = $ACL.InheritanceFlags $ReturnObject['PropagationFlags'] = $ACL.PropagationFlags } if ($Bundle) { $ReturnObject['Bundle'] = $ACL } [PSCustomObject] $ReturnObject } if ($Bundle) { [PSCustomObject] @{DistinguishedName = $DistinguishedName CanonicalName = $Object.CanonicalName ACL = $ACLs ACLAccessRules = $AccessObjects Path = $PathACL } } else { $AccessObjects } } } End {} } function Get-ADACLOwner { [cmdletBinding()] param([Array] $ADObject, [switch] $Resolve, [System.Collections.IDictionary] $ADAdministrativeGroups, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation) Begin { if (-not $ADAdministrativeGroups -and $Resolve) { $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ForestInformation } } Process { foreach ($Object in $ADObject) { if ($Object -is [Microsoft.ActiveDirectory.Management.ADOrganizationalUnit] -or $Object -is [Microsoft.ActiveDirectory.Management.ADEntity]) { [string] $DistinguishedName = $Object.DistinguishedName [string] $CanonicalName = $Object.CanonicalName [string] $ObjectClass = $Object.ObjectClass } elseif ($Object -is [string]) { [string] $DistinguishedName = $Object [string] $CanonicalName = '' [string] $ObjectClass = '' } else { Write-Warning "Get-ADACLOwner - Object not recognized. Skipping..." continue } $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToDC) -replace '=' -replace ',' if (-not (Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { Write-Verbose "Get-ADACLOwner - Enabling PSDrives for $DistinguishedName to $DNConverted" New-ADForestDrives -ForestName $ForestName if (-not (Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { Write-Warning "Set-ADACLOwner - Drive $DNConverted not mapped. Terminating..." return } } $PathACL = "$DNConverted`:\$($DistinguishedName)" try { $ACLs = Get-Acl -Path $PathACL -ErrorAction Stop $Hash = [ordered] @{DistinguishedName = $DistinguishedName Owner = $ACLs.Owner ACLs = $ACLs } $ErrorMessage = '' } catch { $Hash = [ordered] @{DistinguishedName = $DistinguishedName Owner = $null ACLs = $null } $ErrorMessage = $_.Exception.Message } if ($Resolve) { if ($null -eq $Hash.Owner) { $Identity = $null } else { $Identity = Convert-Identity -Identity $Hash.Owner } if ($Identity) { $Hash['OwnerName'] = $Identity.Name $Hash['OwnerSid'] = $Identity.SID $Hash['OwnerType'] = $Identity.Type } else { $Hash['OwnerName'] = '' $Hash['OwnerSid'] = '' $Hash['OwnerType'] = '' } } $Hash['Error'] = $ErrorMessage [PSCustomObject] $Hash } } End {} } function Get-ADADministrativeGroups { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Type Parameter description .PARAMETER Forest Parameter description .PARAMETER ExcludeDomains Parameter description .PARAMETER IncludeDomains Parameter description .PARAMETER ExtendedForestInformation Parameter description .EXAMPLE Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins Output (Where VALUE is Get-ADGroup output): Name Value ---- ----- ByNetBIOS {EVOTEC\Domain Admins, EVOTEC\Enterprise Admins, EVOTECPL\Domain Admins} ad.evotec.xyz {DomainAdmins, EnterpriseAdmins} ad.evotec.pl {DomainAdmins} .NOTES General notes #> [cmdletBinding()] param([parameter(Mandatory)][validateSet('DomainAdmins', 'EnterpriseAdmins')][string[]] $Type, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation) $ADDictionary = [ordered] @{} $ADDictionary['ByNetBIOS'] = [ordered] @{} $ADDictionary['BySID'] = [ordered] @{} $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $ADDictionary[$Domain] = [ordered] @{} $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer if ($Type -contains 'DomainAdmins') { Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-512'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ $ADDictionary[$Domain]['DomainAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" $ADDictionary['BySID'][$_.SID.Value] = $_ } } } foreach ($Domain in $ForestInformation.Forest.Domains) { if (-not $ADDictionary[$Domain]) { $ADDictionary[$Domain] = [ordered] @{} } if ($Type -contains 'EnterpriseAdmins') { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-519'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ $ADDictionary[$Domain]['EnterpriseAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" $ADDictionary['BySID'][$_.SID.Value] = $_ } } } return $ADDictionary } function Get-FileMetaData { <# .SYNOPSIS Small function that gets metadata information from file providing similar output to what Explorer shows when viewing file .DESCRIPTION Small function that gets metadata information from file providing similar output to what Explorer shows when viewing file .PARAMETER File FileName or FileObject .EXAMPLE Get-ChildItem -Path $Env:USERPROFILE\Desktop -Force | Get-FileMetaData | Out-HtmlView -ScrollX -Filtering -AllProperties .EXAMPLE Get-ChildItem -Path $Env:USERPROFILE\Desktop -Force | Where-Object { $_.Attributes -like '*Hidden*' } | Get-FileMetaData | Out-HtmlView -ScrollX -Filtering -AllProperties .NOTES #> [CmdletBinding()] param ([Parameter(Position = 0, ValueFromPipeline)][Object] $File, [ValidateSet('None', 'MACTripleDES', 'MD5', 'RIPEMD160', 'SHA1', 'SHA256', 'SHA384', 'SHA512')][string] $HashAlgorithm = 'None', [switch] $Signature) Process { foreach ($F in $File) { $MetaDataObject = [ordered] @{} if ($F -is [string]) { if ($F -and (Test-Path -LiteralPath $F)) { $FileInformation = Get-ItemProperty -Path $F if ($FileInformation -is [System.IO.DirectoryInfo]) { continue } } else { Write-Warning "Get-FileMetaData - Doesn't exists. Skipping $F." continue } } elseif ($F -is [System.IO.DirectoryInfo]) { continue } elseif ($F -is [System.IO.FileInfo]) { $FileInformation = $F } else { Write-Warning "Get-FileMetaData - Only files are supported. Skipping $F." continue } $ShellApplication = New-Object -ComObject Shell.Application $ShellFolder = $ShellApplication.Namespace($FileInformation.Directory.FullName) $ShellFile = $ShellFolder.ParseName($FileInformation.Name) $MetaDataProperties = [ordered] @{} 0..400 | ForEach-Object -Process { $DataValue = $ShellFolder.GetDetailsOf($null, $_) $PropertyValue = (Get-Culture).TextInfo.ToTitleCase($DataValue.Trim()).Replace(' ', '') if ($PropertyValue -ne '') { $MetaDataProperties["$_"] = $PropertyValue } } foreach ($Key in $MetaDataProperties.Keys) { $Property = $MetaDataProperties[$Key] $Value = $ShellFolder.GetDetailsOf($ShellFile, [int] $Key) if ($Property -in 'Attributes', 'Folder', 'Type', 'SpaceFree', 'TotalSize', 'SpaceUsed') { continue } If (($null -ne $Value) -and ($Value -ne '')) { $MetaDataObject["$Property"] = $Value } } if ($FileInformation.VersionInfo) { $SplitInfo = ([string] $FileInformation.VersionInfo).Split([char]13) foreach ($Item in $SplitInfo) { $Property = $Item.Split(":").Trim() if ($Property[0] -and $Property[1] -ne '') { if ($Property[1] -in 'False', 'True') { $MetaDataObject["$($Property[0])"] = [bool] $Property[1] } else { $MetaDataObject["$($Property[0])"] = $Property[1] } } } } $MetaDataObject["Attributes"] = $FileInformation.Attributes $MetaDataObject['IsReadOnly'] = $FileInformation.IsReadOnly $MetaDataObject['IsHidden'] = $FileInformation.Attributes -like '*Hidden*' $MetaDataObject['IsSystem'] = $FileInformation.Attributes -like '*System*' if ($Signature) { $DigitalSignature = Get-AuthenticodeSignature -FilePath $FileInformation.Fullname $MetaDataObject['SignatureCertificateSubject'] = $DigitalSignature.SignerCertificate.Subject $MetaDataObject['SignatureCertificateIssuer'] = $DigitalSignature.SignerCertificate.Issuer $MetaDataObject['SignatureCertificateSerialNumber'] = $DigitalSignature.SignerCertificate.SerialNumber $MetaDataObject['SignatureCertificateNotBefore'] = $DigitalSignature.SignerCertificate.NotBefore $MetaDataObject['SignatureCertificateNotAfter'] = $DigitalSignature.SignerCertificate.NotAfter $MetaDataObject['SignatureCertificateThumbprint'] = $DigitalSignature.SignerCertificate.Thumbprint $MetaDataObject['SignatureStatus'] = $DigitalSignature.Status $MetaDataObject['IsOSBinary'] = $DigitalSignature.IsOSBinary } if ($HashAlgorithm -ne 'None') { $MetaDataObject[$HashAlgorithm] = (Get-FileHash -LiteralPath $FileInformation.FullName -Algorithm $HashAlgorithm).Hash } [PSCustomObject] $MetaDataObject } } } function Get-FileOwner { [cmdletBinding()] param([Array] $Path, [switch] $Recursive, [switch] $JustPath, [switch] $Resolve) Begin {} Process { foreach ($P in $Path) { if ($P -is [System.IO.FileSystemInfo]) { $FullPath = $P.FullName } elseif ($P -is [string]) { $FullPath = $P } if ($FullPath -and (Test-Path -Path $FullPath)) { if ($JustPath) { $FullPath | ForEach-Object -Process { $ACL = Get-Acl -Path $_ $Object = [ordered]@{FullName = $_ Owner = $ACL.Owner } if ($Resolve) { $Identity = Convert-Identity -Identity $ACL.Owner if ($Identity) { $Object['OwnerName'] = $Identity.Name $Object['OwnerSid'] = $Identity.SID $Object['OwnerType'] = $Identity.Type } else { $Object['OwnerName'] = '' $Object['OwnerSid'] = '' $Object['OwnerType'] = '' } } [PSCustomObject] $Object } } else { Get-ChildItem -LiteralPath $FullPath -Recurse:$Recursive | ForEach-Object -Process { $File = $_ $ACL = Get-Acl -Path $File.FullName $Object = [ordered] @{FullName = $_.FullName Extension = $_.Extension CreationTime = $_.CreationTime LastAccessTime = $_.LastAccessTime LastWriteTime = $_.LastWriteTime Attributes = $_.Attributes Owner = $ACL.Owner } if ($Resolve) { $Identity = Convert-Identity -Identity $ACL.Owner if ($Identity) { $Object['OwnerName'] = $Identity.Name $Object['OwnerSid'] = $Identity.SID $Object['OwnerType'] = $Identity.Type } else { $Object['OwnerName'] = '' $Object['OwnerSid'] = '' $Object['OwnerType'] = '' } } [PSCustomObject] $Object } } } } } End {} } function Get-WinADForestDetails { [CmdletBinding()] param([alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [string[]] $ExcludeDomainControllers, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers, [switch] $SkipRODC, [string] $Filter = '*', [switch] $TestAvailability, [ValidateSet('All', 'Ping', 'WinRM', 'PortOpen', 'Ping+WinRM', 'Ping+PortOpen', 'WinRM+PortOpen')] $Test = 'All', [int[]] $Ports = 135, [int] $PortsTimeout = 100, [int] $PingCount = 1, [switch] $Extended, [System.Collections.IDictionary] $ExtendedForestInformation) if ($Global:ProgressPreference -ne 'SilentlyContinue') { $TemporaryProgress = $Global:ProgressPreference $Global:ProgressPreference = 'SilentlyContinue' } if (-not $ExtendedForestInformation) { $Findings = [ordered] @{} try { if ($Forest) { $ForestInformation = Get-ADForest -ErrorAction Stop -Identity $Forest } else { $ForestInformation = Get-ADForest -ErrorAction Stop } } catch { Write-Warning "Get-WinADForestDetails - Error discovering DC for Forest - $($_.Exception.Message)" return } if (-not $ForestInformation) { return } $Findings['Forest'] = $ForestInformation $Findings['ForestDomainControllers'] = @() $Findings['QueryServers'] = @{} $Findings['DomainDomainControllers'] = @{} [Array] $Findings['Domains'] = foreach ($_ in $ForestInformation.Domains) { if ($IncludeDomains) { if ($_ -in $IncludeDomains) { $_.ToLower() } continue } if ($_ -notin $ExcludeDomains) { $_.ToLower() } } foreach ($Domain in $ForestInformation.Domains) { try { $DC = Get-ADDomainController -DomainName $Domain -Discover -ErrorAction Stop $OrderedDC = [ordered] @{Domain = $DC.Domain Forest = $DC.Forest HostName = [Array] $DC.HostName IPv4Address = $DC.IPv4Address IPv6Address = $DC.IPv6Address Name = $DC.Name Site = $DC.Site } } catch { Write-Warning "Get-WinADForestDetails - Error discovering DC for domain $Domain - $($_.Exception.Message)" continue } if ($Domain -eq $Findings['Forest']['Name']) { $Findings['QueryServers']['Forest'] = $OrderedDC } $Findings['QueryServers']["$Domain"] = $OrderedDC } [Array] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) { $QueryServer = $Findings['QueryServers'][$Domain]['HostName'][0] [Array] $AllDC = try { try { $DomainControllers = Get-ADDomainController -Filter $Filter -Server $QueryServer -ErrorAction Stop } catch { Write-Warning "Get-WinADForestDetails - Error listing DCs for domain $Domain - $($_.Exception.Message)" continue } foreach ($S in $DomainControllers) { if ($IncludeDomainControllers.Count -gt 0) { If (-not $IncludeDomainControllers[0].Contains('.')) { if ($S.Name -notin $IncludeDomainControllers) { continue } } else { if ($S.HostName -notin $IncludeDomainControllers) { continue } } } if ($ExcludeDomainControllers.Count -gt 0) { If (-not $ExcludeDomainControllers[0].Contains('.')) { if ($S.Name -in $ExcludeDomainControllers) { continue } } else { if ($S.HostName -in $ExcludeDomainControllers) { continue } } } $Server = [ordered] @{Domain = $Domain HostName = $S.HostName Name = $S.Name Forest = $ForestInformation.RootDomain Site = $S.Site IPV4Address = $S.IPV4Address IPV6Address = $S.IPV6Address IsGlobalCatalog = $S.IsGlobalCatalog IsReadOnly = $S.IsReadOnly IsSchemaMaster = ($S.OperationMasterRoles -contains 'SchemaMaster') IsDomainNamingMaster = ($S.OperationMasterRoles -contains 'DomainNamingMaster') IsPDC = ($S.OperationMasterRoles -contains 'PDCEmulator') IsRIDMaster = ($S.OperationMasterRoles -contains 'RIDMaster') IsInfrastructureMaster = ($S.OperationMasterRoles -contains 'InfrastructureMaster') OperatingSystem = $S.OperatingSystem OperatingSystemVersion = $S.OperatingSystemVersion OperatingSystemLong = ConvertTo-OperatingSystem -OperatingSystem $S.OperatingSystem -OperatingSystemVersion $S.OperatingSystemVersion LdapPort = $S.LdapPort SslPort = $S.SslPort DistinguishedName = $S.ComputerObjectDN Pingable = $null WinRM = $null PortOpen = $null Comment = '' } if ($TestAvailability) { if ($Test -eq 'All' -or $Test -like 'Ping*') { $Server.Pingable = Test-Connection -ComputerName $Server.IPV4Address -Quiet -Count $PingCount } if ($Test -eq 'All' -or $Test -like '*WinRM*') { $Server.WinRM = (Test-WinRM -ComputerName $Server.HostName).Status } if ($Test -eq 'All' -or '*PortOpen*') { $Server.PortOpen = (Test-ComputerPort -Server $Server.HostName -PortTCP $Ports -Timeout $PortsTimeout).Status } } [PSCustomObject] $Server } } catch { [PSCustomObject]@{Domain = $Domain HostName = '' Name = '' Forest = $ForestInformation.RootDomain IPV4Address = '' IPV6Address = '' IsGlobalCatalog = '' IsReadOnly = '' Site = '' SchemaMaster = $false DomainNamingMasterMaster = $false PDCEmulator = $false RIDMaster = $false InfrastructureMaster = $false LdapPort = '' SslPort = '' DistinguishedName = '' Pingable = $null WinRM = $null PortOpen = $null Comment = $_.Exception.Message -replace "`n", " " -replace "`r", " " } } if ($SkipRODC) { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC } [Array] $Findings['DomainDomainControllers'][$Domain] } if ($Extended) { $Findings['DomainsExtended'] = @{} $Findings['DomainsExtendedNetBIOS'] = @{} foreach ($DomainEx in $Findings['Domains']) { try { $Findings['DomainsExtended'][$DomainEx] = Get-ADDomain -Server $Findings['QueryServers'][$DomainEx].HostName[0] | ForEach-Object { [ordered] @{AllowedDNSSuffixes = $_.AllowedDNSSuffixes | ForEach-Object -Process { $_ } ChildDomains = $_.ChildDomains | ForEach-Object -Process { $_ } ComputersContainer = $_.ComputersContainer DeletedObjectsContainer = $_.DeletedObjectsContainer DistinguishedName = $_.DistinguishedName DNSRoot = $_.DNSRoot DomainControllersContainer = $_.DomainControllersContainer DomainMode = $_.DomainMode DomainSID = $_.DomainSID.Value ForeignSecurityPrincipalsContainer = $_.ForeignSecurityPrincipalsContainer Forest = $_.Forest InfrastructureMaster = $_.InfrastructureMaster LastLogonReplicationInterval = $_.LastLogonReplicationInterval LinkedGroupPolicyObjects = $_.LinkedGroupPolicyObjects | ForEach-Object -Process { $_ } LostAndFoundContainer = $_.LostAndFoundContainer ManagedBy = $_.ManagedBy Name = $_.Name NetBIOSName = $_.NetBIOSName ObjectClass = $_.ObjectClass ObjectGUID = $_.ObjectGUID ParentDomain = $_.ParentDomain PDCEmulator = $_.PDCEmulator PublicKeyRequiredPasswordRolling = $_.PublicKeyRequiredPasswordRolling | ForEach-Object -Process { $_ } QuotasContainer = $_.QuotasContainer ReadOnlyReplicaDirectoryServers = $_.ReadOnlyReplicaDirectoryServers | ForEach-Object -Process { $_ } ReplicaDirectoryServers = $_.ReplicaDirectoryServers | ForEach-Object -Process { $_ } RIDMaster = $_.RIDMaster SubordinateReferences = $_.SubordinateReferences | ForEach-Object -Process { $_ } SystemsContainer = $_.SystemsContainer UsersContainer = $_.UsersContainer } } $NetBios = $Findings['DomainsExtended'][$DomainEx]['NetBIOSName'] $Findings['DomainsExtendedNetBIOS'][$NetBios] = $Findings['DomainsExtended'][$DomainEx] } catch { Write-Warning "Get-WinADForestDetails - Error gathering Domain Information for domain $DomainEx - $($_.Exception.Message)" continue } } } if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress } $Findings } else { $Findings = Copy-DictionaryManual -Dictionary $ExtendedForestInformation [Array] $Findings['Domains'] = foreach ($_ in $Findings.Domains) { if ($IncludeDomains) { if ($_ -in $IncludeDomains) { $_.ToLower() } continue } if ($_ -notin $ExcludeDomains) { $_.ToLower() } } foreach ($_ in [string[]] $Findings.DomainDomainControllers.Keys) { if ($_ -notin $Findings.Domains) { $Findings.DomainDomainControllers.Remove($_) } } foreach ($_ in [string[]] $Findings.DomainsExtended.Keys) { if ($_ -notin $Findings.Domains) { $Findings.DomainsExtended.Remove($_) $NetBiosName = $Findings.DomainsExtended.$_.'NetBIOSName' if ($NetBiosName) { $Findings.DomainsExtendedNetBIOS.Remove($NetBiosName) } } } [Array] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) { [Array] $AllDC = foreach ($S in $Findings.DomainDomainControllers["$Domain"]) { if ($IncludeDomainControllers.Count -gt 0) { If (-not $IncludeDomainControllers[0].Contains('.')) { if ($S.Name -notin $IncludeDomainControllers) { continue } } else { if ($S.HostName -notin $IncludeDomainControllers) { continue } } } if ($ExcludeDomainControllers.Count -gt 0) { If (-not $ExcludeDomainControllers[0].Contains('.')) { if ($S.Name -in $ExcludeDomainControllers) { continue } } else { if ($S.HostName -in $ExcludeDomainControllers) { continue } } } $S } if ($SkipRODC) { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC } [Array] $Findings['DomainDomainControllers'][$Domain] } $Findings } } function Get-WinADSharePermission { [cmdletBinding(DefaultParameterSetName = 'Path')] param([Parameter(ParameterSetName = 'Path', Mandatory)][string] $Path, [Parameter(ParameterSetName = 'ShareType', Mandatory)][validateset('NetLogon', 'SYSVOL')][string[]] $ShareType, [switch] $Owner, [string[]] $Name, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation) if ($ShareType) { $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $Path = -join ("\\", $Domain, "\$ShareType") @(Get-Item -Path $Path) + @(Get-ChildItem -Path $Path -Recurse:$true) | ForEach-Object -Process { if ($Owner) { Get-FileOwner -JustPath -Path $_ -Resolve } else { Get-FilePermission -Path $_ -ResolveTypes -Extended } } } } else { if ($Path -and (Test-Path -Path $Path)) { @(Get-Item -Path $Path) + @(Get-ChildItem -Path $Path -Recurse:$true) | ForEach-Object -Process { if ($Owner) { Get-FileOwner -JustPath -Path $_ -Resolve } else { Get-FilePermission -Path $_ -ResolveTypes -Extended } } } } } function Remove-ADACL { [cmdletBinding(SupportsShouldProcess)] param([Array] $ACL, [string] $Principal, [System.DirectoryServices.ActiveDirectoryRights] $AccessRule, [System.Security.AccessControl.AccessControlType] $AccessControlType = [System.Security.AccessControl.AccessControlType]::Allow) foreach ($SubACL in $ACL) { $OutputRequiresCommit = @(if ($Principal -like '*-*-*-*') { $Identity = [System.Security.Principal.SecurityIdentifier]::new($Principal) } else { [System.Security.Principal.IdentityReference] $Identity = [System.Security.Principal.NTAccount]::new($Principal) } if (-not $AccessRule) { Write-Verbose "Remove-ADACL - Removing access for $($Identity) / All Rights" try { $SubACL.ACL.RemoveAccess($Identity, $AccessControlType) $true } catch { Write-Warning "Remove-ADACL - Removing permissions for $($SubACL.DistinguishedName) failed: $($_.Exception.Message)" $false } } else { foreach ($Rule in $AccessRule) { $AccessRuleToRemove = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($Identity, $Rule, $AccessControlType) Write-Verbose "Remove-ADACL - Removing access for $($AccessRuleToRemove.IdentityReference) / $($AccessRuleToRemove.ActiveDirectoryRights)" $SubACL.ACL.RemoveAccessRule($AccessRuleToRemove) } }) if ($OutputRequiresCommit -notcontains $false -and $OutputRequiresCommit -contains $true) { Write-Verbose "Remove-ADACL - Saving permissions for $($SubACL.DistinguishedName)" Set-Acl -Path $SubACL.Path -AclObject $SubACL.ACL -ErrorAction Stop } elseif ($OutputRequiresCommit -contains $false) { Write-Warning "Remove-ADACL - Skipping saving permissions for $($SubACL.DistinguishedName) due to errors." } } } function Select-Properties { [CmdLetBinding()] param([Array] $Objects, [string[]] $Property, [string[]] $ExcludeProperty, [switch] $AllProperties) function Select-Unique { [CmdLetBinding()] param([System.Collections.IList] $Object) $New = $Object.ToLower() | Select-Object -Unique $Selected = foreach ($_ in $New) { $Index = $Object.ToLower().IndexOf($_) if ($Index -ne -1) { $Object[$Index] } } $Selected } if ($Objects.Count -eq 0) { Write-Warning 'Select-Properties - Unable to process. Objects count equals 0.' return } if ($Objects[0] -is [System.Collections.IDictionary]) { if ($AllProperties) { [Array] $All = foreach ($_ in $Objects) { $_.Keys } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $Objects[0].Keys } if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_ -and $ExcludeProperty -notcontains $_) { $_ continue } } } elseif ($Property.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_) { $_ continue } } } elseif ($ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($ExcludeProperty -notcontains $_) { $_ continue } } } } else { if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $Objects = $Objects | Select-Object -Property $Property -ExcludeProperty $ExcludeProperty } elseif ($Property.Count -gt 0) { $Objects = $Objects | Select-Object -Property $Property } elseif ($ExcludeProperty.Count -gt 0) { $Objects = $Objects | Select-Object -Property '*' -ExcludeProperty $ExcludeProperty } if ($AllProperties) { [Array] $All = foreach ($_ in $Objects) { $_.PSObject.Properties.Name } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $Objects[0].PSObject.Properties.Name } } return $FirstObjectProperties } function Set-ADACLOwner { [cmdletBinding(SupportsShouldProcess)] param([Array] $ADObject, [Parameter(Mandatory)][string] $Principal) Begin { if ($Principal -is [string]) { if ($Principal -like '*/*') { $SplittedName = $Principal -split '/' [System.Security.Principal.IdentityReference] $Identity = [System.Security.Principal.NTAccount]::new($SplittedName[0], $SplittedName[1]) } else { [System.Security.Principal.IdentityReference] $Identity = [System.Security.Principal.NTAccount]::new($Principal) } } else { return } } Process { foreach ($Object in $ADObject) { if ($Object -is [Microsoft.ActiveDirectory.Management.ADOrganizationalUnit] -or $Object -is [Microsoft.ActiveDirectory.Management.ADEntity]) { [string] $DistinguishedName = $Object.DistinguishedName [string] $CanonicalName = $Object.CanonicalName [string] $ObjectClass = $Object.ObjectClass } elseif ($Object -is [string]) { [string] $DistinguishedName = $Object [string] $CanonicalName = '' [string] $ObjectClass = '' } else { Write-Warning "Set-ADACLOwner - Object not recognized. Skipping..." continue } $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToDC) -replace '=' -replace ',' if (-not (Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { Write-Verbose "Set-ADACLOwner - Enabling PSDrives for $DistinguishedName to $DNConverted" New-ADForestDrives -ForestName $ForestName if (-not (Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { Write-Warning "Set-ADACLOwner - Drive $DNConverted not mapped. Terminating..." return } } $PathACL = "$DNConverted`:\$($DistinguishedName)" $ACLs = Get-Acl -Path $PathACL -ErrorAction Stop $CurrentOwner = $ACLs.Owner Write-Verbose "Set-ADACLOwner - Changing owner from $($CurrentOwner) to $Identity for $($ACLs.Path)" try { $ACLs.SetOwner($Identity) } catch { Write-Warning "Set-ADACLOwner - Unable to change owner from $($CurrentOwner) to $Identity for $($ACLs.Path): $($_.Exception.Message)" break } try { Set-Acl -Path $PathACL -AclObject $ACLs -ErrorAction Stop } catch { Write-Warning "Set-ADACLOwner - Unable to change owner from $($CurrentOwner) to $Identity for $($ACLs.Path): $($_.Exception.Message)" } } } End {} } function Set-FileOwner { [cmdletBinding(SupportsShouldProcess)] param([Array] $Path, [switch] $Recursive, [string] $Owner, [string[]] $Exlude, [switch] $JustPath) Begin {} Process { foreach ($P in $Path) { if ($P -is [System.IO.FileSystemInfo]) { $FullPath = $P.FullName } elseif ($P -is [string]) { $FullPath = $P } $OwnerTranslated = [System.Security.Principal.NTAccount]::new($Owner) if ($FullPath -and (Test-Path -Path $FullPath)) { if ($JustPath) { $FullPath | ForEach-Object -Process { $File = $_ $ACL = Get-Acl -Path $File if ($ACL.Owner -notin $Exlude -and $ACL.Owner -ne $OwnerTranslated) { if ($PSCmdlet.ShouldProcess($File, "Replacing owner $($ACL.Owner) to $OwnerTranslated")) { try { $ACL.SetOwner($OwnerTranslated) Set-Acl -Path $File -AclObject $ACL } catch { Write-Warning "Set-FileOwner - Replacing owner $($ACL.Owner) to $OwnerTranslated failed with error: $($_.Exception.Message)" } } } } } else { Get-ChildItem -LiteralPath $FullPath -Recurse:$Recursive | ForEach-Object -Process { $File = $_ $ACL = Get-Acl -Path $File.FullName if ($ACL.Owner -notin $Exlude -and $ACL.Owner -ne $OwnerTranslated) { if ($PSCmdlet.ShouldProcess($File.FullName, "Replacing owner $($ACL.Owner) to $OwnerTranslated")) { try { $ACL.SetOwner($OwnerTranslated) Set-Acl -Path $File.FullName -AclObject $ACL } catch { Write-Warning "Set-FileOwner - Replacing owner $($ACL.Owner) to $OwnerTranslated failed with error: $($_.Exception.Message)" } } } } } } } } End {} } function Convert-Identity { [cmdletBinding(DefaultParameterSetName = 'Identity')] param([parameter(ParameterSetName = 'Identity')][string[]] $Identity, [parameter(ParameterSetName = 'SID', Mandatory)][System.Security.Principal.SecurityIdentifier[]] $SID, [parameter(ParameterSetName = 'Name', Mandatory)][string[]] $Name) Begin { if (-not $Script:GlobalCacheSidConvert) { $Script:GlobalCacheSidConvert = @{'S-1-0' = 'Null AUTHORITY' 'S-1-0-0' = 'NULL SID' 'S-1-1' = 'WORLD AUTHORITY' 'S-1-1-0' = 'Everyone' 'S-1-2' = 'LOCAL AUTHORITY' 'S-1-2-0' = 'LOCAL' 'S-1-2-1' = 'CONSOLE LOGON' 'S-1-3' = 'CREATOR AUTHORITY' 'S-1-3-0' = 'CREATOR OWNER' 'S-1-3-1' = 'CREATOR GROUP' 'S-1-3-2' = 'CREATOR OWNER SERVER' 'S-1-3-3' = 'CREATOR GROUP SERVER' 'S-1-3-4' = 'OWNER RIGHTS' 'S-1-5-80-0' = 'NT SERVICE\ALL SERVICES' 'S-1-4' = 'Non-unique Authority' 'S-1-5' = 'NT AUTHORITY' 'S-1-5-1' = 'NT AUTHORITY\DIALUP' 'S-1-5-2' = 'NT AUTHORITY\NETWORK' 'S-1-5-3' = 'NT AUTHORITY\BATCH' 'S-1-5-4' = 'NT AUTHORITY\INTERACTIVE' 'S-1-5-6' = 'NT AUTHORITY\SERVICE' 'S-1-5-7' = 'NT AUTHORITY\ANONYMOUS LOGON' 'S-1-5-8' = 'NT AUTHORITY\PROXY' 'S-1-5-9' = 'NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS' 'S-1-5-10' = 'NT AUTHORITY\SELF' 'S-1-5-11' = 'NT AUTHORITY\Authenticated Users' 'S-1-5-12' = 'NT AUTHORITY\RESTRICTED' 'S-1-5-13' = 'NT AUTHORITY\TERMINAL SERVER USER' 'S-1-5-14' = 'NT AUTHORITY\REMOTE INTERACTIVE LOGON' 'S-1-5-15' = 'NT AUTHORITY\This Organization' 'S-1-5-17' = 'NT AUTHORITY\IUSR' 'S-1-5-18' = 'NT AUTHORITY\SYSTEM' 'S-1-5-19' = 'NT AUTHORITY\NETWORK SERVICE' 'S-1-5-20' = 'NT AUTHORITY\NETWORK SERVICE' 'S-1-5-32-544' = 'BUILTIN\Administrators' 'S-1-5-32-545' = 'BUILTIN\Users' 'S-1-5-32-546' = 'BUILTIN\Guests' 'S-1-5-32-547' = 'BUILTIN\Power Users' 'S-1-5-32-548' = 'BUILTIN\Account Operators' 'S-1-5-32-549' = 'BUILTIN\Server Operators' 'S-1-5-32-550' = 'BUILTIN\Print Operators' 'S-1-5-32-551' = 'BUILTIN\Backup Operators' 'S-1-5-32-552' = 'BUILTIN\Replicators' 'S-1-5-64-10' = 'NT AUTHORITY\NTLM Authentication' 'S-1-5-64-14' = 'NT AUTHORITY\SChannel Authentication' 'S-1-5-64-21' = 'NT AUTHORITY\Digest Authentication' 'S-1-5-80' = 'NT SERVICE' 'S-1-5-83-0' = 'NT VIRTUAL MACHINE\Virtual Machines' 'S-1-16-0' = 'Untrusted Mandatory Level' 'S-1-16-4096' = 'Low Mandatory Level' 'S-1-16-8192' = 'Medium Mandatory Level' 'S-1-16-8448' = 'Medium Plus Mandatory Level' 'S-1-16-12288' = 'High Mandatory Level' 'S-1-16-16384' = 'System Mandatory Level' 'S-1-16-20480' = 'Protected Process Mandatory Level' 'S-1-16-28672' = 'Secure Process Mandatory Level' 'S-1-5-32-554' = 'BUILTIN\Pre-Windows 2000 Compatible Access' 'S-1-5-32-555' = 'BUILTIN\Remote Desktop Users' 'S-1-5-32-556' = 'BUILTIN\Network Configuration Operators' 'S-1-5-32-557' = 'BUILTIN\Incoming Forest Trust Builders' 'S-1-5-32-558' = 'BUILTIN\Performance Monitor Users' 'S-1-5-32-559' = 'BUILTIN\Performance Log Users' 'S-1-5-32-560' = 'BUILTIN\Windows Authorization Access Group' 'S-1-5-32-561' = 'BUILTIN\Terminal Server License Servers' 'S-1-5-32-562' = 'BUILTIN\Distributed COM Users' 'S-1-5-32-569' = 'BUILTIN\Cryptographic Operators' 'S-1-5-32-573' = 'BUILTIN\Event Log Readers' 'S-1-5-32-574' = 'BUILTIN\Certificate Service DCOM Access' 'S-1-5-32-575' = 'BUILTIN\RDS Remote Access Servers' 'S-1-5-32-576' = 'BUILTIN\RDS Endpoint Servers' 'S-1-5-32-577' = 'BUILTIN\RDS Management Servers' 'S-1-5-32-578' = 'BUILTIN\Hyper-V Administrators' 'S-1-5-32-579' = 'BUILTIN\Access Control Assistance Operators' 'S-1-5-32-580' = 'BUILTIN\Remote Management Users' } } $wellKnownSIDs = @{'S-1-0' = 'WellKnown' 'S-1-0-0' = 'WellKnown' 'S-1-1' = 'WellKnown' 'S-1-1-0' = 'WellKnown' 'S-1-2' = 'WellKnown' 'S-1-2-0' = 'WellKnown' 'S-1-2-1' = 'WellKnown' 'S-1-3' = 'WellKnown' 'S-1-3-0' = 'WellKnown' 'S-1-3-1' = 'WellKnown' 'S-1-3-2' = 'WellKnown' 'S-1-3-3' = 'WellKnown' 'S-1-3-4' = 'WellKnown' 'S-1-5-80-0' = 'WellKnown' 'S-1-4' = 'WellKnown' 'S-1-5' = 'WellKnown' 'S-1-5-1' = 'WellKnown' 'S-1-5-2' = 'WellKnown' 'S-1-5-3' = 'WellKnown' 'S-1-5-4' = 'WellKnown' 'S-1-5-6' = 'WellKnown' 'S-1-5-7' = 'WellKnown' 'S-1-5-8' = 'WellKnown' 'S-1-5-9' = 'WellKnown' 'S-1-5-10' = 'WellKnown' 'S-1-5-11' = 'WellKnown' 'S-1-5-12' = 'WellKnown' 'S-1-5-13' = 'WellKnown' 'S-1-5-14' = 'WellKnown' 'S-1-5-15' = 'WellKnown' 'S-1-5-17' = 'WellKnown' 'S-1-5-18' = 'WellKnownAdministrative' 'S-1-5-19' = 'WellKnown' 'S-1-5-20' = 'WellKnown' 'S-1-5-32-544' = 'WellKnownAdministrative' 'S-1-5-32-545' = 'WellKnown' 'S-1-5-32-546' = 'WellKnown' 'S-1-5-32-547' = 'WellKnown' 'S-1-5-32-548' = 'WellKnown' 'S-1-5-32-549' = 'WellKnown' 'S-1-5-32-550' = 'WellKnown' 'S-1-5-32-551' = 'WellKnown' 'S-1-5-32-552' = 'WellKnown' 'S-1-5-64-10' = 'WellKnown' 'S-1-5-64-14' = 'WellKnown' 'S-1-5-64-21' = 'WellKnown' 'S-1-5-80' = 'WellKnown' 'S-1-5-83-0' = 'WellKnown' 'S-1-16-0' = 'WellKnown' 'S-1-16-4096' = 'WellKnown' 'S-1-16-8192' = 'WellKnown' 'S-1-16-8448' = 'WellKnown' 'S-1-16-12288' = 'WellKnown' 'S-1-16-16384' = 'WellKnown' 'S-1-16-20480' = 'WellKnown' 'S-1-16-28672' = 'WellKnown' 'S-1-5-32-554' = 'WellKnown' 'S-1-5-32-555' = 'WellKnown' 'S-1-5-32-556' = 'WellKnown' 'S-1-5-32-557' = 'WellKnown' 'S-1-5-32-558' = 'WellKnown' 'S-1-5-32-559' = 'WellKnown' 'S-1-5-32-560' = 'WellKnown' 'S-1-5-32-561' = 'WellKnown' 'S-1-5-32-562' = 'WellKnown' 'S-1-5-32-569' = 'WellKnown' 'S-1-5-32-573' = 'WellKnown' 'S-1-5-32-574' = 'WellKnown' 'S-1-5-32-575' = 'WellKnown' 'S-1-5-32-576' = 'WellKnown' 'S-1-5-32-577' = 'WellKnown' 'S-1-5-32-578' = 'WellKnown' 'S-1-5-32-579' = 'WellKnown' 'S-1-5-32-580' = 'WellKnown' } } Process { if ($Identity) { foreach ($Ident in $Identity) { if ($Ident -like '*-*-*') { if ($Script:GlobalCacheSidConvert[$Ident]) { if ($Script:GlobalCacheSidConvert[$Ident] -is [string]) { [ordered] @{Name = $Script:GlobalCacheSidConvert[$Ident] SID = $Ident Type = $wellKnownSIDs[$Ident] Error = '' } } else { $Script:GlobalCacheSidConvert[$Ident] } } else { try { [string] $Name = (([System.Security.Principal.SecurityIdentifier]::new($Ident)).Translate([System.Security.Principal.NTAccount])).Value $ErrorMessage = '' if ($Ident -like "S-1-5-21-*-519" -or $Ident -like "S-1-5-21-*-512") { $Type = 'Administrative' } elseif ($wellKnownSIDs[$Ident]) { $Type = $wellKnownSIDs[$Ident] } else { $Type = 'NotAdministrative' } } catch { [string] $Name = '' $ErrorMessage = $_.Exception.Message $Type = 'Unknown' } $Script:GlobalCacheSidConvert[$Ident] = [PSCustomObject] @{Name = $Name SID = $Ident Type = $Type Error = $ErrorMessage } $Script:GlobalCacheSidConvert[$Ident] } } else { if ($Script:GlobalCacheSidConvert[$Ident]) { $Script:GlobalCacheSidConvert[$Ident] } else { try { $SIDValue = ([System.Security.Principal.NTAccount] $Ident).Translate([System.Security.Principal.SecurityIdentifier]).Value if ($SIDValue -like "S-1-5-21-*-519" -or $SIDValue -like "S-1-5-21-*-512") { $Type = 'Administrative' } elseif ($wellKnownSIDs[$SIDValue]) { $Type = $wellKnownSIDs[$SIDValue] } else { $Type = 'NotAdministrative' } $ErrorMessage = '' } catch { $Type = 'Unknown' $ErrorMessage = $_.Exception.Message } $Script:GlobalCacheSidConvert[$Ident] = [PSCustomObject] @{Name = $Ident SID = $SIDValue Type = $Type Error = $ErrorMessage } $Script:GlobalCacheSidConvert[$Ident] } } } } else { if ($SID) { foreach ($S in $SID) { if ($Script:GlobalCacheSidConvert[$S]) { $Script:GlobalCacheSidConvert[$S] } else { $Script:GlobalCacheSidConvert[$S] = (([System.Security.Principal.SecurityIdentifier]::new($S)).Translate([System.Security.Principal.NTAccount])).Value $Script:GlobalCacheSidConvert[$S] } } } else { foreach ($Ident in $Name) { if ($Script:GlobalCacheSidConvert[$Ident]) { $Script:GlobalCacheSidConvert[$Ident] } else { $Script:GlobalCacheSidConvert[$Ident] = ([System.Security.Principal.NTAccount] $Ident).Translate([System.Security.Principal.SecurityIdentifier]).Value $Script:GlobalCacheSidConvert[$Ident] } } } } } End {} } function ConvertTo-OperatingSystem { [CmdletBinding()] param([string] $OperatingSystem, [string] $OperatingSystemVersion) if ($OperatingSystem -like '*Windows 10*') { $Systems = @{'10.0 (18363)' = "Windows 10 1909" '10.0 (18362)' = "Windows 10 1903" '10.0 (17763)' = "Windows 10 1809" '10.0 (17134)' = "Windows 10 1803" '10.0 (16299)' = "Windows 10 1709" '10.0 (15063)' = "Windows 10 1703" '10.0 (14393)' = "Windows 10 1607" '10.0 (10586)' = "Windows 10 1511" '10.0 (10240)' = "Windows 10 1507" '10.0 (18898)' = 'Windows 10 Insider Preview' '10.0.18363' = "Windows 10 1909" '10.0.18362' = "Windows 10 1903" '10.0.17763' = "Windows 10 1809" '10.0.17134' = "Windows 10 1803" '10.0.16299' = "Windows 10 1709" '10.0.15063' = "Windows 10 1703" '10.0.14393' = "Windows 10 1607" '10.0.10586' = "Windows 10 1511" '10.0.10240' = "Windows 10 1507" '10.0.18898' = 'Windows 10 Insider Preview' } $System = $Systems[$OperatingSystemVersion] if (-not $System) { $System = $OperatingSystem } } elseif ($OperatingSystem -like '*Windows Server*') { $Systems = @{'5.2 (3790)' = 'Windows Server 2003' '6.1 (7601)' = 'Windows Server 2008 R2' '10.0 (18362)' = "Windows Server, version 1903 (Semi-Annual Channel) 1903" '10.0 (17763)' = "Windows Server 2019 (Long-Term Servicing Channel) 1809" '10.0 (17134)' = "Windows Server, version 1803 (Semi-Annual Channel) 1803" '10.0 (14393)' = "Windows Server 2016 (Long-Term Servicing Channel) 1607" '10.0.18362' = "Windows Server, version 1903 (Semi-Annual Channel) 1903" '10.0.17763' = "Windows Server 2019 (Long-Term Servicing Channel) 1809" '10.0.17134' = "Windows Server, version 1803 (Semi-Annual Channel) 1803" '10.0.14393' = "Windows Server 2016 (Long-Term Servicing Channel) 1607" } $System = $Systems[$OperatingSystemVersion] if (-not $System) { $System = $OperatingSystem } } else { $System = $OperatingSystem } if ($System) { $System } else { 'Unknown' } } function Copy-DictionaryManual { [CmdletBinding()] param([System.Collections.IDictionary] $Dictionary) $clone = @{} foreach ($Key in $Dictionary.Keys) { $value = $Dictionary.$Key $clonedValue = switch ($Dictionary.$Key) { { $null -eq $_ } { $null continue } { $_ -is [System.Collections.IDictionary] } { Copy-DictionaryManual -Dictionary $_ continue } { $type = $_.GetType() $type.IsPrimitive -or $type.IsValueType -or $_ -is [string] } { $_ continue } default { $_ | Select-Object -Property * } } if ($value -is [System.Collections.IList]) { $clone[$Key] = @($clonedValue) } else { $clone[$Key] = $clonedValue } } $clone } function Get-FilePermission { [alias('Get-PSPermissions', 'Get-FilePermissions')] [cmdletBinding()] param([Array] $Path, [switch] $Inherited, [switch] $NotInherited, [switch] $ResolveTypes, [switch] $Extended, [switch] $IncludeACLObject) foreach ($P in $Path) { if ($P -is [System.IO.FileSystemInfo]) { $FullPath = $P.FullName } elseif ($P -is [string]) { $FullPath = $P } $TestPath = Test-Path -Path $FullPath if ($TestPath) { $ACLS = (Get-Acl -Path $FullPath) $Output = foreach ($ACL in $ACLS.Access) { if ($Inherited) { if ($ACL.IsInherited -eq $false) { continue } } if ($NotInherited) { if ($ACL.IsInherited -eq $true) { continue } } $TranslateRights = Convert-GenericRightsToFileSystemRights -OriginalRights $ACL.FileSystemRights $ReturnObject = [ordered] @{} $ReturnObject['Path' ] = $FullPath $ReturnObject['AccessControlType'] = $ACL.AccessControlType if ($ResolveTypes) { $Identity = Convert-Identity -Identity $ACL.IdentityReference if ($Identity) { $ReturnObject['Principal'] = $ACL.IdentityReference $ReturnObject['PrincipalName'] = $Identity.Name $ReturnObject['PrincipalSid'] = $Identity.Sid $ReturnObject['PrincipalType'] = $Identity.Type } else { $ReturnObject['Principal'] = $Identity $ReturnObject['PrincipalName'] = '' $ReturnObject['PrincipalSid'] = '' $ReturnObject['PrincipalType'] = '' } } else { $ReturnObject['Principal'] = $ACL.IdentityReference.Value } $ReturnObject['FileSystemRights'] = $TranslateRights $ReturnObject['IsInherited'] = $ACL.IsInherited if ($Extended) { $ReturnObject['InheritanceFlags'] = $ACL.InheritanceFlags $ReturnObject['PropagationFlags'] = $ACL.PropagationFlags } if ($IncludeACLObject) { $ReturnObject['ACL'] = $ACL $ReturnObject['AllACL'] = $ACLS } [PSCustomObject] $ReturnObject } $Output } else { Write-Warning "Get-PSPermissions - Path $Path doesn't exists. Skipping." } } } function Get-WinADCache { [alias('Get-ADCache')] [cmdletbinding()] param([switch] $ByDN, [switch] $ByNetBiosName) $ForestObjectsCache = [ordered] @{} $Forest = Get-ADForest foreach ($Domain in $Forest.Domains) { $Server = Get-ADDomainController -Discover -DomainName $Domain try { $DomainInformation = Get-ADDomain -Server $Server.Hostname[0] $Users = Get-ADUser -Filter * -Server $Server.Hostname[0] $Groups = Get-ADGroup -Filter * -Server $Server.Hostname[0] $Computers = Get-ADComputer -Filter * -Server $Server.Hostname[0] } catch { Write-Warning "Get-ADCache - Can't process domain $Domain - $($_.Exception.Message)" continue } if ($ByDN) { foreach ($_ in $Users) { $ForestObjectsCache["$($_.DistinguishedName)"] = $_ } foreach ($_ in $Groups) { $ForestObjectsCache["$($_.DistinguishedName)"] = $_ } foreach ($_ in $Computers) { $ForestObjectsCache["$($_.DistinguishedName)"] = $_ } } elseif ($ByNetBiosName) { foreach ($_ in $Users) { $Identity = -join ($DomainInformation.NetBIOSName, '\', $($_.SamAccountName)) $ForestObjectsCache["$Identity"] = $_ } foreach ($_ in $Groups) { $Identity = -join ($DomainInformation.NetBIOSName, '\', $($_.SamAccountName)) $ForestObjectsCache["$Identity"] = $_ } foreach ($_ in $Computers) { $Identity = -join ($DomainInformation.NetBIOSName, '\', $($_.SamAccountName)) $ForestObjectsCache["$Identity"] = $_ } } else { Write-Warning "Get-ADCache - No choice made." } } $ForestObjectsCache } function Get-WinADForestGUIDs { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Domain Parameter description .PARAMETER RootDSE Parameter description .PARAMETER DisplayNameKey Parameter description .EXAMPLE Get-WinADForestGUIDs .EXAMPLE Get-WinADForestGUIDs -DisplayNameKey .NOTES General notes #> [alias('Get-WinADDomainGUIDs')] [cmdletbinding()] param([string] $Domain = $Env:USERDNSDOMAIN, [Microsoft.ActiveDirectory.Management.ADEntity] $RootDSE, [switch] $DisplayNameKey) if ($null -eq $RootDSE) { $RootDSE = Get-ADRootDSE -Server $Domain } $GUID = @{} $GUID.Add('00000000-0000-0000-0000-000000000000', 'All') $Schema = Get-ADObject -SearchBase $RootDSE.schemaNamingContext -LDAPFilter '(schemaIDGUID=*)' -Properties name, schemaIDGUID foreach ($S in $Schema) { if ($DisplayNameKey) { $GUID["$($S.name)"] = $(([System.GUID]$S.schemaIDGUID).Guid) } else { $GUID["$(([System.GUID]$S.schemaIDGUID).Guid)"] = $S.name } } $Extended = Get-ADObject -SearchBase "CN=Extended-Rights,$($RootDSE.configurationNamingContext)" -LDAPFilter '(objectClass=controlAccessRight)' -Properties name, rightsGUID foreach ($S in $Extended) { if ($DisplayNameKey) { $GUID["$($S.name)"] = $(([System.GUID]$S.rightsGUID).Guid) } else { $GUID["$(([System.GUID]$S.rightsGUID).Guid)"] = $S.name } } return $GUID } function New-ADForestDrives { [cmdletbinding()] param([string] $ForestName, [string] $ObjectDN) if (-not $Global:ADDrivesMapped) { if ($ForestName) { $Forest = Get-ADForest -Identity $ForestName } else { $Forest = Get-ADForest } if ($ObjectDN) { $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $ObjectDN -ToDC) -replace '=' -replace ',' if (-not(Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { try { if ($Server) { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Server.Hostname[0] -Scope Global -WhatIf:$false Write-Verbose "New-ADForestDrives - Mapped drive $Domain / $($Server.Hostname[0])" } else { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Domain -Scope Global -WhatIf:$false } } catch { Write-Warning "New-ADForestDrives - Couldn't map new AD psdrive for $Domain / $($Server.Hostname[0])" } } } else { foreach ($Domain in $Forest.Domains) { try { $Server = Get-ADDomainController -Discover -DomainName $Domain $DomainInformation = Get-ADDomain -Server $Server.Hostname[0] } catch { Write-Warning "New-ADForestDrives - Can't process domain $Domain - $($_.Exception.Message)" continue } $ObjectDN = $DomainInformation.DistinguishedName $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $ObjectDN -ToDC) -replace '=' -replace ',' if (-not(Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { try { if ($Server) { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Server.Hostname[0] -Scope Global -WhatIf:$false Write-Verbose "New-ADForestDrives - Mapped drive $Domain / $Server" } else { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Domain -Scope Global -WhatIf:$false } } catch { Write-Warning "New-ADForestDrives - Couldn't map new AD psdrive for $Domain / $Server $($_.Exception.Message)" } } } } $Global:ADDrivesMapped = $true } } function Test-ComputerPort { [CmdletBinding()] param ([alias('Server')][string[]] $ComputerName, [int[]] $PortTCP, [int[]] $PortUDP, [int]$Timeout = 5000) begin { if ($Global:ProgressPreference -ne 'SilentlyContinue') { $TemporaryProgress = $Global:ProgressPreference $Global:ProgressPreference = 'SilentlyContinue' } } process { foreach ($Computer in $ComputerName) { foreach ($P in $PortTCP) { $Output = [ordered] @{'ComputerName' = $Computer 'Port' = $P 'Protocol' = 'TCP' 'Status' = $null 'Summary' = $null 'Response' = $null } $TcpClient = Test-NetConnection -ComputerName $Computer -Port $P -InformationLevel Detailed -WarningAction SilentlyContinue if ($TcpClient.TcpTestSucceeded) { $Output['Status'] = $TcpClient.TcpTestSucceeded $Output['Summary'] = "TCP $P Successful" } else { $Output['Status'] = $false $Output['Summary'] = "TCP $P Failed" $Output['Response'] = $Warnings } [PSCustomObject]$Output } foreach ($P in $PortUDP) { $Output = [ordered] @{'ComputerName' = $Computer 'Port' = $P 'Protocol' = 'UDP' 'Status' = $null 'Summary' = $null } $UdpClient = [System.Net.Sockets.UdpClient]::new($Computer, $P) $UdpClient.Client.ReceiveTimeout = $Timeout $Encoding = [System.Text.ASCIIEncoding]::new() $byte = $Encoding.GetBytes("Evotec") [void]$UdpClient.Send($byte, $byte.length) $RemoteEndpoint = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any, 0) try { $Bytes = $UdpClient.Receive([ref]$RemoteEndpoint) [string]$Data = $Encoding.GetString($Bytes) If ($Data) { $Output['Status'] = $true $Output['Summary'] = "UDP $P Successful" $Output['Response'] = $Data } } catch { $Output['Status'] = $false $Output['Summary'] = "UDP $P Failed" $Output['Response'] = $_.Exception.Message } $UdpClient.Close() $UdpClient.Dispose() [PSCustomObject]$Output } } } end { if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress } } } function Test-WinRM { [CmdletBinding()] param ([alias('Server')][string[]] $ComputerName) $Output = foreach ($Computer in $ComputerName) { $Test = [PSCustomObject] @{Output = $null Status = $null ComputerName = $Computer } try { $Test.Output = Test-WSMan -ComputerName $Computer -ErrorAction Stop $Test.Status = $true } catch { $Test.Status = $false } $Test } $Output } function Convert-GenericRightsToFileSystemRights { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER OriginalRights Parameter description .EXAMPLE An example .NOTES .LINK Improved https://blog.cjwdev.co.uk/2011/06/28/permissions-not-included-in-net-accessrule-filesystemrights-enum/ #> [cmdletBinding()] param([System.Security.AccessControl.FileSystemRights] $OriginalRights) Begin { $FileSystemRights = [System.Security.AccessControl.FileSystemRights] $GenericRights = @{GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 GENERIC_EXECUTE = 0x20000000 GENERIC_ALL = 0x10000000 FILTER_GENERIC = 0x0FFFFFFF } $MappedGenericRights = @{FILE_GENERIC_EXECUTE = $FileSystemRights::ExecuteFile -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::ReadAttributes -bor $FileSystemRights::Synchronize FILE_GENERIC_READ = $FileSystemRights::ReadAttributes -bor $FileSystemRights::ReadData -bor $FileSystemRights::ReadExtendedAttributes -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::Synchronize FILE_GENERIC_WRITE = $FileSystemRights::AppendData -bor $FileSystemRights::WriteAttributes -bor $FileSystemRights::WriteData -bor $FileSystemRights::WriteExtendedAttributes -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::Synchronize FILE_GENERIC_ALL = $FileSystemRights::FullControl } } Process { $MappedRights = [System.Security.AccessControl.FileSystemRights]::new() if ($OriginalRights -band $GenericRights.GENERIC_EXECUTE) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_EXECUTE } if ($OriginalRights -band $GenericRights.GENERIC_READ) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_READ } if ($OriginalRights -band $GenericRights.GENERIC_WRITE) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_WRITE } if ($OriginalRights -band $GenericRights.GENERIC_ALL) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_ALL } (($OriginalRights -bAND $GenericRights.FILTER_GENERIC) -bOR $MappedRights) -as $FileSystemRights } End {} } # TODO: #2 Identical to ConvertTo-EventLog - decide what to do later on function ConvertTo-AccountPolicies { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Type = $GPOEntry.Type Policy = $GPOEntry.Name } if ($GPOEntry.SettingBoolean) { $CreateGPO['Setting'] = if ($GPOEntry.SettingBoolean -eq 'true') { 'Enabled' } elseif ($GPOEntry.SettingBoolean -eq 'false') { 'Disabled' } else { $null }; #try { [bool]::Parse($GPOEntry.SettingBoolean) } catch { $null }; } elseif ($GPOEntry.SettingNumber) { $CreateGPO['Setting'] = $GPOEntry.SettingNumber } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-Audit { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $SuccessAttempts = try { [bool]::Parse($GPOEntry.SuccessAttempts) } catch { $null }; $FailureAttempts = try { [bool]::Parse($GPOEntry.FailureAttempts) } catch { $null }; if ($SuccessAttempts -and $FailureAttempts) { $Setting = 'Success, Failure' } elseif ($SuccessAttempts) { $Setting = 'Success' } elseif ($FailureAttempts) { $Setting = 'Failure' } else { $Setting = 'No auditing' } $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Policy = $GPOEntry.Name Setting = $Setting SuccessAttempts = $SuccessAttempts FailureAttempts = $FailureAttempts } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-AuditAlternative { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $SuccessAttempts = try { [bool]::Parse($GPOEntry.SuccessAttempts) } catch { $null }; $FailureAttempts = try { [bool]::Parse($GPOEntry.FailureAttempts) } catch { $null }; if ($SuccessAttempts -and $FailureAttempts) { $Setting = 'Success, Failure' } elseif ($SuccessAttempts) { $Setting = 'Success' } elseif ($FailureAttempts) { $Setting = 'Failure' } else { $Setting = 'No auditing' } $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Policy = $GPOEntry.Name Setting = $Setting #SuccessAttempts = $SuccessAttempts #FailureAttempts = $FailureAttempts } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-EventLog { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Type = $GPOEntry.Type Policy = $GPOEntry.Name } if ($GPOEntry.SettingBoolean) { $CreateGPO['Setting'] = if ($GPOEntry.SettingBoolean -eq 'true') { 'Enabled' } elseif ($GPOEntry.SettingBoolean -eq 'false') { 'Disabled' } else { $null }; #try { [bool]::Parse($GPOEntry.SettingBoolean) } catch { $null }; } elseif ($GPOEntry.SettingNumber) { $CreateGPO['Setting'] = $GPOEntry.SettingNumber } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-LocalUserAndGroups { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { foreach ($User in $GPOEntry.User) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Changed = [DateTime] $User.Changed GPOSettingOrder = $User.GPOSettingOrder UserAction = $Script:Actions["$($User.Properties.action)"] #: U UserNewName = $User.Properties.newName #: UserFullName = $User.Properties.fullName #: UserDescription = $User.Properties.description #: UserCpassword = $User.Properties.cpassword #: UserChangeLogon = $User.Properties.changeLogon #: 0 UserNoChange = $User.Properties.noChange #: 0 UserNeverExpires = $User.Properties.neverExpires #: 0 UserAcctDisabled = $User.Properties.acctDisabled #: 0 UserAubAuthority = $User.Properties.subAuthority #: RID_ADMIN UserUserName = $User.Properties.userName #: Administrator (built-in) UserMembers = $User.Properties.Members #: } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } foreach ($Group in $GPOEntry.Group) { # We're mostly interested in Members [Array] $Members = foreach ($Member in $Group.Properties.Members.Member) { [ordered] @{ MemberName = $Member.Name MemberAction = $Member.Action MemberSID = $Member.SID } } # if we have no members we create dummy object to make sure we can use foreach below if ($Members.Count -eq 0) { $Members = @( [ordered] @{ MemberName = $null MemberAction = $null MemberSID = $null } ) } foreach ($Member in $Members) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Changed = [DateTime] $Group.Changed GPOSettingOrder = $Group.GPOSettingOrder GroupUid = $Group.uid #: {8F435B0A-CD15-464E-85F3-B6A55B9E816A}: {8F435B0A-CD15-464E-85F3-B6A55B9E816A} GroupUserContext = $Group.userContext #: 0: 0 GroupRemovePolicy = $Group.removePolicy #: 1: 1 #Properties = $Group.Properties #: Properties: Properties Filters = $Group.Filters #:: GroupAction = $Script:Actions["$($Group.Properties.action)"] #: U GroupNewName = $Group.Properties.newName #: GroupDescription = $Group.Properties.description #: GroupDeleteAllUsers = $Group.Properties.deleteAllUsers #: 0 GroupDeleteAllGroups = $Group.Properties.deleteAllGroups #: 0 GroupRemoveAccounts = $Group.Properties.removeAccounts #: 1 GroupSid = $Group.Properties.groupSid #: S - 1 - 5 - 32 - 544 GroupName = $Group.Properties.groupName #: Administrators (built -in ) } # Merging GPO with Member $CreateGPO = $CreateGPO + $Member $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } } } function ConvertTo-Policies { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions PolicyName = $GPOEntry.Name PolicyState = $GPOEntry.State PolicyCategory = $GPOEntry.Category PolicySupported = $GPOEntry.Supported PolicyExplain = $GPOEntry.Explain PolicyText = $GPOEntry.Text PolicyCheckBox = $GPOEntry.CheckBox PolicyDropDownList = $GPOEntry.DropDownList PolicyEditText = $GPOEntry.EditText } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-RegistryAutologon { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions AutoAdminLogon = $null DefaultDomainName = $null DefaultUserName = $null DefaultPassword = $null } foreach ($Registry in $GPOEntry.Registry) { if ($Registry.Properties.Key -eq 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon') { if ($Registry.Properties.Name -eq 'AutoAdminLogon') { $CreateGPO['AutoAdminLogon'] = [bool] $Registry.Properties.value $CreateGPO['DateChangedAutoAdminLogon'] = [DateTime] $Registry.changed } elseif ($Registry.Properties.Name -eq 'DefaultDomainName') { $CreateGPO['DefaultDomainName'] = $Registry.Properties.value $CreateGPO['DateChangedDefaultDomainName'] = [DateTime] $Registry.changed } elseif ($Registry.Properties.Name -eq 'DefaultUserName') { $CreateGPO['DefaultUserName'] = $Registry.Properties.value $CreateGPO['DateChangedDefaultUserName'] = [DateTime] $Registry.changed } elseif ($Registry.Properties.Name -eq 'DefaultPassword') { $CreateGPO['DefaultPassword'] = $Registry.Properties.value $CreateGPO['DateChangedDefaultPassword'] = [DateTime] $Registry.changed } } } if ($null -ne $CreateGPO['AutoAdminLogon'] -or $null -ne $CreateGPO['DefaultDomainName'] -or $null -ne $CreateGPO['DefaultUserName'] -or $null -ne $CreateGPO['DefaultPassword'] ) { $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } } function ConvertTo-RegistrySettings { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { foreach ($Registry in $GPOEntry.Registry) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Changed = [DateTime] $Registry.changed GPOSettingOrder = $Registry.GPOSettingOrder Hive = $Registry.Properties.hive #: HKEY_LOCAL_MACHINE Key = $Registry.Properties.key #: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon Name = $Registry.Properties.name #: AutoAdminLogon Type = $Registry.Properties.type #: REG_SZ Value = $Registry.Properties.value # Filters = $Registry.Filters } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } } function ConvertTo-RegistrySettingsCollection { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { foreach ($Collection in $GPOEntry.Collection) { $OutputDictionaries = foreach ($Registry in $Collection.Registry) { [ordered] @{ #"$($Registry.Name)FieldName" = $Registry.Name #"$($Registry.Name)FieldStatus" = $Registry.Status "$($Registry.Name)BypassErrors" = try { [bool]::Parse($Registry.BypassErrors) } catch { $null }; "$($Registry.Name)Changed" = [DateTime] $Registry.Changed "$($Registry.Name)UID" = $Registry.UID "$($Registry.Name)GPOSettingOrder" = $Registry.GPOSettingOrder "$($Registry.Name)Action" = $Registry.Properties.action "$($Registry.Name)DisplayDecimal" = $Registry.Properties.displayDecimal "$($Registry.Name)Default" = $Registry.Properties.default "$($Registry.Name)Hive" = $Registry.Properties.hive "$($Registry.Name)Name" = $Registry.Properties.name "$($Registry.Name)Type" = $Registry.Properties.type "$($Registry.Name)Value" = $Registry.Properties.value "$($Registry.Name)Values" = $Registry.Properties.Values } } $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions } foreach ($Dictionary in $OutputDictionaries) { $CreateGPO = $CreateGPO + $Dictionary } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } } function ConvertTo-Scripts { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Command = $GPOEntry.Command Parameters = $GPOEntry.Parameters Type = $GPOEntry.Type Order = $GPOEntry.Order RunOrder = $GPOEntry.RunOrder } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-SecurityOptions { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions KeyName = $GPOEntry.KeyName KeyDisplayName = $GPOEntry.Display.Name KeyDisplayUnits = $GPOEntry.Display.Units KeyDisplayBoolean = try { [bool]::Parse($GPOEntry.Display.DisplayBoolean) } catch { $null }; KeyDisplayString = $GPOEntry.Display.DisplayString SystemAccessPolicyName = $GPOEntry.SystemAccessPolicyName SettingString = $GPOEntry.SettingString SettingNumber = $GPOEntry.SettingNumber } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-SoftwareInstallation { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Identifier = $GPOEntry.Identifier #: { 10495e9e-79c1-4a32-b278-a24cd495437f } Name = $GPOEntry.Name #: Local Administrator Password Solution (2) Path = $GPOEntry.Path #: \\area1.local\SYSVOL\area1.local\Policies\ { 5F5042A0-008F-45E3-8657-79C87BD002E3 }\LAPS.x64.msi MajorVersion = $GPOEntry.MajorVersion #: 6 MinorVersion = $GPOEntry.MinorVersion #: 2 LanguageId = $GPOEntry.LanguageId #: 1033 Architecture = $GPOEntry.Architecture #: 9 IgnoreLanguage = if ($GPOEntry.IgnoreLanguage -eq 'true') { $true } else { $false } #: false Allowx86Onia64 = if ($GPOEntry.Allowx86Onia64 -eq 'true') { $true } else { $false } #: true SupportURL = $GPOEntry.SupportURL #: AutoInstall = if ($GPOEntry.AutoInstall -eq 'true') { $true } else { $false } #: true DisplayInARP = if ($GPOEntry.DisplayInARP -eq 'true') { $true } else { $false } #: true IncludeCOM = if ($GPOEntry.IncludeCOM -eq 'true') { $true } else { $false } #: true SecurityDescriptor = $GPOEntry.SecurityDescriptor #: SecurityDescriptor DeploymentType = $GPOEntry.DeploymentType #: Assign ProductId = $GPOEntry.ProductId #: { ea8cb806-c109 - 4700 - 96b4-f1f268e5036c } ScriptPath = $GPOEntry.ScriptPath #: \\area1.local\SysVol\area1.local\Policies\ { 5F5042A0-008F-45E3-8657-79C87BD002E3 }\Machine\Applications\ { EAC9B821-FB4D - 457A-806F-E5B528D1E41A }.aas DeploymentCount = $GPOEntry.DeploymentCount #: 0 InstallationUILevel = $GPOEntry.InstallationUILevel #: Maximum Upgrades = if ($GPOEntry.Upgrades.Mandatory -eq 'true') { $true } else { $false } #: Upgrades UninstallUnmanaged = if ($GPOEntry.UninstallUnmanaged -eq 'true') { $true } else { $false } #: false LossOfScopeAction = $GPOEntry.LossOfScopeAction #: Unmanage } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-SystemServices { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions ServiceName = $GPOEntry.Name ServiceStartUpMode = $GPOEntry.StartUpMode SecurityAuditingPresent = try { [bool]::Parse($GPOEntry.SecurityDescriptor.AuditingPresent.'#text') } catch { $null }; SecurityPermissionsPresent = try { [bool]::Parse($GPOEntry.SecurityDescriptor.PermissionsPresent.'#text') } catch { $null }; SecurityDescriptor = $GPOEntry.SecurityDescriptor } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } function ConvertTo-SystemServicesNT { [cmdletBinding()] param( [Array] $GPOList ) foreach ($GPOEntry in $GPOList) { foreach ($Service in $GPOEntry.NTService) { $CreateGPO = [ordered]@{ DisplayName = $GPOEntry.DisplayName #: WO_SEC_NTLM_Auth_Level DomainName = $GPOEntry.DomainName #: area1.local GUID = $GPOEntry.GUID #: 364B095E-C7BF-4CC1-9BFA-393BD38975E5 GpoType = $GPOEntry.GpoType #: Computer GpoCategory = $GPOEntry.GpoCategory #: SecuritySettings GpoSettings = $GPOEntry.GpoSettings #: SecurityOptions Changed = [DateTime] $Service.Changed GPOSettingOrder = $Service.GPOSettingOrder #ServiceName = $Service.Name ServiceName = $Service.Properties.serviceName #: AppIDSvc: AppIDSvc ServiceStartupType = $Service.Properties.startupType #: NOCHANGE: NOCHANGE ServiceAction = $Service.Properties.serviceAction #: START: START Timeout = $Service.Properties.timeout #: 50: 50 FirstFailure = $Service.Properties.firstFailure #: REBOOT: REBOOT SecondFailure = $Service.Properties.secondFailure #: REBOOT: REBOOT ThirdFailure = $Service.Properties.thirdFailure #: REBOOT: REBOOT ResetFailCountDelay = $Service.Properties.resetFailCountDelay #: 0: 0 RestartComputerDelay = $Service.Properties.restartComputerDelay #: 60000: 60000 Filter = $Service.Filter } $CreateGPO['Linked'] = $GPOEntry.Linked #: True $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } } } function Find-MissingProperties { [cmdletBinding()] param( [Array] $Objects, [string[]] $PossibleProperties ) $AllProperties = Select-Properties -AllProperties -Objects $Objects $MissingProperties = $AllProperties | Where-Object { $_ -notin 'DisplayName', 'DomainName', 'GUID', 'Linked', 'LinksCount', 'Links', 'GPOType', 'GPOCategory', 'GPOSettings' } [Array] $ConsiderAdding = foreach ($Property in $MissingProperties) { if ($Property -notin $PossibleProperties) { $Property } } $ConsiderAdding } function Get-LinksFromXML { [cmdletBinding()] param( [System.Xml.XmlElement[]] $GPOOutput, [string] $Splitter, [switch] $FullObjects ) $Links = [ordered] @{ Linked = $null LinksCount = $null Links = $null } if ($GPOOutput.LinksTo) { $Links.Linked = $true $Links.LinksCount = ([Array] $GPOOutput.LinksTo).Count $Links.Links = foreach ($Link in $GPOOutput.LinksTo) { if ($FullObjects) { [PSCustomObject] @{ Path = $Link.SOMPath Enabled = if ($Link.Enabled -eq 'true') { $true } else { $false } NoOverride = if ($Link.NoOverride -eq 'true') { $true } else { $false } } } else { if ($Link.Enabled) { $Link.SOMPath } } } if ($Splitter) { $Links.Links = $Links.Links -join $Splitter } } else { $Links.Linked = $false $Links.LinksCount = 0 $Links.Links = $null } [PSCustomObject] $Links } function Get-PrivGPOZaurrLink { [cmdletBinding()] param( [Microsoft.ActiveDirectory.Management.ADObject] $Object, [switch] $Limited, [System.Collections.IDictionary] $GPOCache ) if ($Object.GpLink -and $Object.GpLink.Trim() -ne '') { #$Object.GpLink -split { $_ -eq '[' -or $_ -eq ']' } -replace ';0' -replace 'LDAP://' $Object.GpLink -split '\[LDAP://' -split ';' | ForEach-Object -Process { #Write-Verbose $_ if ($_.Length -gt 10) { $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDomainCN $Output = [ordered] @{ DistinguishedName = $Object.DistinguishedName CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName } Guid = [Regex]::Match( $_, '(?={)(.*)(?<=})').Value -replace '{' -replace '}' } $Search = -join ($DomainCN, $Output['Guid']) if ($GPOCache -and -not $Limited) { if ($GPOCache[$Search]) { $Output['DisplayName'] = $GPOCache[$Search].DisplayName $Output['DomainName'] = $GPOCache[$Search].DomainName $Output['Owner'] = $GPOCache[$Search].Owner $Output['GpoStatus'] = $GPOCache[$Search].GpoStatus $Output['Description'] = $GPOCache[$Search].Description $Output['CreationTime'] = $GPOCache[$Search].CreationTime $Output['ModificationTime'] = $GPOCache[$Search].ModificationTime $Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC $Output['GPODistinguishedName'] = $_ [PSCustomObject] $Output } else { Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping." } } else { $Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC $Output['GPODistinguishedName'] = $_ [PSCustomObject] $Output } } } } elseif ($Object.LinkedGroupPolicyObjects -and $Object.LinkedGroupPolicyObjects.Trim() -ne '') { $Object.LinkedGroupPolicyObjects -split '\[LDAP://' -split ';' | ForEach-Object -Process { if ($_.Length -gt 10) { $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDomainCN $Output = [ordered] @{ DistinguishedName = $Object.DistinguishedName CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName } Guid = [Regex]::Match( $_, '(?={)(.*)(?<=})').Value -replace '{' -replace '}' } $Search = -join ($DomainCN, $Output['Guid']) if ($GPOCache -and -not $Limited) { if ($GPOCache[$Search]) { $Output['Name'] = $GPOCache[$Search].DisplayName $Output['DomainName'] = $GPOCache[$Search].DomainName $Output['Owner'] = $GPOCache[$Search].Owner $Output['GpoStatus'] = $GPOCache[$Search].GpoStatus $Output['Description'] = $GPOCache[$Search].Description $Output['CreationTime'] = $GPOCache[$Search].CreationTime $Output['ModificationTime'] = $GPOCache[$Search].ModificationTime $Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC $Output['GPODistinguishedName'] = $_ [PSCustomObject] $Output } else { Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping." } } else { $Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC $Output['GPODistinguishedName'] = $_ [PSCustomObject] $Output } } } } } function Get-PrivPermission { [cmdletBinding()] param( [Microsoft.GroupPolicy.Gpo] $GPO, [Object] $SecurityRights, [string[]] $Principal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'Sid', [switch] $SkipWellKnown, [switch] $SkipAdministrative, [switch] $IncludeOwner, [Microsoft.GroupPolicy.GPPermissionType[]] $IncludePermissionType, [Microsoft.GroupPolicy.GPPermissionType[]] $ExcludePermissionType, [validateSet('Allow', 'Deny', 'All')][string] $PermitType = 'All', [string[]] $ExcludePrincipal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $ExcludePrincipalType = 'Sid', [switch] $IncludeGPOObject, [System.Collections.IDictionary] $ADAdministrativeGroups, [validateSet('AuthenticatedUsers', 'DomainComputers', 'Unknown', 'WellKnownAdministrative', 'NotWellKnown', 'NotWellKnownAdministrative', 'NotAdministrative', 'Administrative', 'All')][string[]] $Type = 'All', [System.Collections.IDictionary] $Accounts, [System.Collections.IDictionary] $ExtendedForestInformation ) Begin { Write-Verbose "Get-PrivPermission - Processing $($GPO.DisplayName) from $($GPO.DomainName)" } Process { $SecurityRights | ForEach-Object -Process { $GPOPermission = $_ if ($PermitType -ne 'All') { if ($PermitType -eq 'Deny') { if ($GPOPermission.Denied -eq $false) { return } } else { if ($GPOPermission.Denied -eq $true) { return } } } if ($ExcludePermissionType -contains $GPOPermission.Permission) { return } if ($IncludePermissionType) { if ($IncludePermissionType -notcontains $GPOPermission.Permission) { if ($IncludePermissionType -eq 'GpoRead' -and $GPOPermission.Permission -eq 'GpoApply') { # We treat GpoApply as GpoRead as well. This is because when GpoApply is set it becomes GpoRead as well but of course not vice versa } else { return } } } if ($SkipWellKnown.IsPresent -or $Type -contains 'NotWellKnown') { if ($GPOPermission.Trustee.SidType -eq 'WellKnownGroup') { return } } if ($SkipAdministrative.IsPresent -or $Type -contains 'NotAdministrative') { $IsAdministrative = $ADAdministrativeGroups['BySID'][$GPOPermission.Trustee.Sid.Value] if ($IsAdministrative) { return } } if ($Type -contains 'Administrative' -and $Type -notcontains 'All') { $IsAdministrative = $ADAdministrativeGroups['BySID'][$GPOPermission.Trustee.Sid.Value] if (-not $IsAdministrative) { return } } if ($Type -contains 'NotWellKnownAdministrative' -and $Type -notcontains 'All') { # We check for SYSTEM account # Maybe we should make it a function and provide more if ($GPOPermission.Trustee.Sid -eq 'S-1-5-18') { return } } if ($Type -contains 'WellKnownAdministrative' -and $Type -notcontains 'All') { # We check for SYSTEM account # Maybe we should make it a function and provide more if ($GPOPermission.Trustee.Sid -ne 'S-1-5-18') { return } } if ($Type -contains 'Unknown' -and $Type -notcontains 'All') { # May need updates if there's more types if ($GPOPermission.Trustee.SidType -ne 'Unknown') { return } } if ($Type -contains 'AuthenticatedUsers' -and $Type -notcontains 'All') { if ($GPOPermission.Trustee.Sid -ne 'S-1-5-11') { return } } if ($Type -contains 'DomainComputers' -and $Type -notcontains 'All') { $DomainComputersSID = -join ($ExtendedForestInformation['DomainsExtended'][$GPO.DomainName].DomainSID, '-515') if ($GPOPermission.Trustee.Sid -ne $DomainComputersSID) { return } } if ($Principal) { if ($PrincipalType -eq 'Sid') { if ($Principal -notcontains $GPOPermission.Trustee.Sid.Value) { return } } elseif ($PrincipalType -eq 'DistinguishedName') { if ($Principal -notcontains $GPOPermission.Trustee.DSPath) { return } } elseif ($PrincipalType -eq 'Name') { $UserMerge = -join ($GPOPermission.Trustee.Domain, '\', $GPOPermission.Trustee.Name) if ($Principal -notcontains $UserMerge -and $Principal -notcontains $GPOPermission.Trustee.Name) { return } } } if ($ExcludePrincipal) { if ($ExcludePrincipalType -eq 'Sid') { if ($ExcludePrincipal -contains $GPOPermission.Trustee.Sid.Value) { return } } elseif ($ExcludePrincipalType -eq 'DistinguishedName') { if ($ExcludePrincipal -contains $GPOPermission.Trustee.DSPath) { return } } elseif ($ExcludePrincipalType -eq 'Name') { $UserMerge = -join ($GPOPermission.Trustee.Domain, '\', $GPOPermission.Trustee.Name) if ($ExcludePrincipal -contains $UserMerge -or $ExcludePrincipal -contains $GPOPermission.Trustee.Name) { return } } } $ReturnObject = [ordered] @{ DisplayName = $GPO.DisplayName # : ALL | Enable RDP GUID = $GPO.ID DomainName = $GPO.DomainName # : ad.evotec.xyz Enabled = $GPO.GpoStatus Description = $GPO.Description CreationDate = $GPO.CreationTime ModificationTime = $GPO.ModificationTime PermissionType = if ($GPOPermission.Denied -eq $true) { 'Deny' } else { 'Allow' } Permission = $GPOPermission.Permission # : GpoEditDeleteModifySecurity Inherited = $GPOPermission.Inherited # : False Domain = $GPOPermission.Trustee.Domain #: EVOTEC DistinguishedName = $GPOPermission.Trustee.DSPath #: CN = Domain Admins, CN = Users, DC = ad, DC = evotec, DC = xyz Name = $GPOPermission.Trustee.Name #: Domain Admins Sid = $GPOPermission.Trustee.Sid.Value #: S - 1 - 5 - 21 - 853615985 - 2870445339 - 3163598659 - 512 SidType = $GPOPermission.Trustee.SidType #: Group } if ($Accounts) { $A = -join ($GPOPermission.Trustee.Domain, '\', $GPOPermission.Trustee.Name) if ($A -and $Accounts[$A]) { $ReturnObject['UserPrincipalName'] = $Accounts[$A].UserPrincipalName $ReturnObject['AccountEnabled'] = $Accounts[$A].Enabled $ReturnObject['DistinguishedName'] = $Accounts[$A].DistinguishedName $ReturnObject['PasswordLastSet'] = if ($Accounts[$A].PasswordLastSet) { $Accounts[$A].PasswordLastSet } else { '' } $ReturnObject['LastLogonDate'] = if ($Accounts[$A].LastLogonDate ) { $Accounts[$A].LastLogonDate } else { '' } if (-not $ReturnObject['Sid']) { $ReturnObject['Sid'] = $Accounts[$A].Sid.Value } if ($Accounts[$A].ObjectClass -eq 'group') { $ReturnObject['SidType'] = 'Group' } elseif ($Accounts[$A].ObjectClass -eq 'user') { $ReturnObject['SidType'] = 'User' } elseif ($Accounts[$A].ObjectClass -eq 'computer') { $ReturnObject['SidType'] = 'Computer' } else { $ReturnObject['SidType'] = 'EmptyOrUnknown' } } else { $ReturnObject['UserPrincipalName'] = '' $ReturnObject['AccountEnabled'] = '' $ReturnObject['PasswordLastSet'] = '' $ReturnObject['LastLogonDate'] = '' } } if ($IncludeGPOObject) { $ReturnObject['GPOObject'] = $GPO $ReturnObject['GPOSecurity'] = $SecurityRights $ReturnObject['GPOSecurityPermissionItem'] = $GPOPermission } [PSCustomObject] $ReturnObject } if ($IncludeOwner.IsPresent) { if ($GPO.Owner) { $SplittedOwner = $GPO.Owner.Split('\') $DomainOwner = $SplittedOwner[0] #: EVOTEC $DomainUserName = $SplittedOwner[1] #: Domain Admins $SID = $ADAdministrativeGroups['ByNetBIOS']["$($GPO.Owner)"].Sid.Value if ($SID) { $SIDType = 'Group' $DistinguishedName = $ADAdministrativeGroups['ByNetBIOS']["$($GPO.Owner)"].DistinguishedName } else { $SIDType = '' $DistinguishedName = '' } } else { $DomainOwner = $GPO.Owner $DomainUserName = '' $SID = '' $SIDType = 'EmptyOrUnknown' $DistinguishedName = '' } $ReturnObject = [ordered] @{ DisplayName = $GPO.DisplayName # : ALL | Enable RDP GUID = $GPO.Id DomainName = $GPO.DomainName # : ad.evotec.xyz Enabled = $GPO.GpoStatus Description = $GPO.Description CreationDate = $GPO.CreationTime ModificationTime = $GPO.ModificationTime Permission = 'GpoOwner' # : GpoEditDeleteModifySecurity Inherited = $false # : False Domain = $DomainOwner DistinguishedName = $DistinguishedName #: CN = Domain Admins, CN = Users, DC = ad, DC = evotec, DC = xyz Name = $DomainUserName Sid = $SID #: S - 1 - 5 - 21 - 853615985 - 2870445339 - 3163598659 - 512 SidType = $SIDType # #: Group } if ($Accounts) { $A = $GPO.Owner if ($A -and $Accounts[$A]) { $ReturnObject['UserPrincipalName'] = $Accounts[$A].UserPrincipalName $ReturnObject['AccountEnabled'] = $Accounts[$A].Enabled $ReturnObject['DistinguishedName'] = $Accounts[$A].DistinguishedName $ReturnObject['PasswordLastSet'] = if ($Accounts[$A].PasswordLastSet) { $Accounts[$A].PasswordLastSet } else { '' } $ReturnObject['LastLogonDate'] = if ($Accounts[$A].LastLogonDate ) { $Accounts[$A].LastLogonDate } else { '' } if (-not $ReturnObject['Sid']) { $ReturnObject['Sid'] = $Accounts[$A].Sid.Value } if ($Accounts[$A].ObjectClass -eq 'group') { $ReturnObject['SidType'] = 'Group' } elseif ($Accounts[$A].ObjectClass -eq 'user') { $ReturnObject['SidType'] = 'User' } elseif ($Accounts[$A].ObjectClass -eq 'computer') { $ReturnObject['SidType'] = 'Computer' } else { $ReturnObject['SidType'] = 'EmptyOrUnknown' } } else { $ReturnObject['UserPrincipalName'] = '' $ReturnObject['AccountEnabled'] = '' $ReturnObject['PasswordLastSet'] = '' $ReturnObject['LastLogonDate'] = '' } } if ($IncludeGPOObject) { $ReturnObject['GPOObject'] = $GPO $ReturnObject['GPOSecurity'] = $SecurityRights $ReturnObject['GPOSecurityPermissionItem'] = $null } [PSCustomObject] $ReturnObject } } End { } } function Get-XMLGPO { [cmdletBinding()] param( [XML] $XMLContent, [Microsoft.GroupPolicy.Gpo] $GPO, [switch] $PermissionsOnly, [switch] $OwnerOnly, [System.Collections.IDictionary] $ADAdministrativeGroups ) if ($XMLContent.GPO.LinksTo) { $Linked = $true $LinksCount = ([Array] $XMLContent.GPO.LinksTo).Count } else { $Linked = $false $LinksCount = 0 } # Find proper values for enabled/disabled user/computer settings if ($XMLContent.GPO.Computer.Enabled -eq 'False') { $ComputerEnabled = $false } elseif ($XMLContent.GPO.Computer.Enabled -eq 'True') { $ComputerEnabled = $true } if ($XMLContent.GPO.User.Enabled -eq 'False') { $UserEnabled = $false } elseif ($XMLContent.GPO.User.Enabled -eq 'True') { $UserEnabled = $true } # Translate Enabled to same as GPO GUI if ($UserEnabled -eq $True -and $ComputerEnabled -eq $true) { $Enabled = 'Enabled' } elseif ($UserEnabled -eq $false -and $ComputerEnabled -eq $false) { $Enabled = 'All settings disabled' } elseif ($UserEnabled -eq $true -and $ComputerEnabled -eq $false) { $Enabled = 'Computer configuration settings disabled' } elseif ($UserEnabled -eq $false -and $ComputerEnabled -eq $true) { $Enabled = 'User configuration settings disabled' } if (-not $PermissionsOnly) { if ($XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text') { $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text')"] $WellKnown = ConvertFrom-SID -SID $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text' -OnlyWellKnown if ($AdministrativeGroup) { $OwnerType = 'Administrative' } elseif ($WellKnown.Name) { $OwnerType = 'WellKnown' } else { $OwnerType = 'NotAdministrative' } } else { $OwnerType = 'EmptyOrUnknown' } } if ($PermissionsOnly) { [PsCustomObject] @{ 'DisplayName' = $XMLContent.GPO.Name 'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text' 'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}' 'Enabled' = $Enabled 'Name' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text' 'Sid' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text' #'SidType' = if (($XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text').Length -le 10) { 'WellKnown' } else { 'Other' } 'PermissionType' = 'Allow' 'Inherited' = $false 'Permissions' = 'Owner' 'GPODistinguishedName' = $GPO.Path } $XMLContent.GPO.SecurityDescriptor.Permissions.TrusteePermissions | ForEach-Object -Process { if ($_) { [PsCustomObject] @{ 'DisplayName' = $XMLContent.GPO.Name 'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text' 'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}' 'Enabled' = $Enabled 'Name' = $_.trustee.name.'#Text' 'Sid' = $_.trustee.SID.'#Text' #'SidType' = if (($XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text').Length -le 10) { 'WellKnown' } else { 'Other' } 'PermissionType' = $_.type.PermissionType 'Inherited' = if ($_.Inherited -eq 'false') { $false } else { $true } 'Permissions' = $_.Standard.GPOGroupedAccessEnum 'GPODistinguishedName' = $GPO.Path } } } } elseif ($OwnerOnly) { [PsCustomObject] @{ 'DisplayName' = $XMLContent.GPO.Name 'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text' 'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}' 'Enabled' = $Enabled 'Owner' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text' 'OwnerSID' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text' 'OwnerType' = $OwnerType 'GPODistinguishedName' = $GPO.Path } } else { [PsCustomObject] @{ 'DisplayName' = $XMLContent.GPO.Name 'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text' 'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}' 'Linked' = $Linked 'LinksCount' = $LinksCount 'Enabled' = $Enabled 'ComputerEnabled' = $ComputerEnabled 'UserEnabled' = $UserEnabled 'ComputerSettingsAvailable' = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true } 'UserSettingsAvailable' = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true } 'ComputerSettingsStatus' = if ($XMLContent.GPO.Computer.VersionDirectory -eq 0 -and $XMLContent.GPO.Computer.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" } 'ComputerSetttingsVersionIdentical' = if ($XMLContent.GPO.Computer.VersionDirectory -eq $XMLContent.GPO.Computer.VersionSysvol) { $true } else { $false } 'ComputerSettings' = $XMLContent.GPO.Computer.ExtensionData.Extension 'UserSettingsStatus' = if ($XMLContent.GPO.User.VersionDirectory -eq 0 -and $XMLContent.GPO.User.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" } 'UserSettingsVersionIdentical' = if ($XMLContent.GPO.User.VersionDirectory -eq $XMLContent.GPO.User.VersionSysvol) { $true } else { $false } 'UserSettings' = $XMLContent.GPO.User.ExtensionData.Extension ComputerPolicies = $XMLContent.GPO.Computer.ExtensionData.Name -join ", " UserPolicies = $XMLContent.GPO.User.ExtensionData.Name -join ", " 'CreationTime' = [DateTime] $XMLContent.GPO.CreatedTime 'ModificationTime' = [DateTime] $XMLContent.GPO.ModifiedTime 'ReadTime' = [DateTime] $XMLContent.GPO.ReadTime 'WMIFilter' = $GPO.WmiFilter.name 'WMIFilterDescription' = $GPO.WmiFilter.Description 'GPODistinguishedName' = $GPO.Path 'SDDL' = if ($Splitter -ne '') { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' -join $Splitter } else { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' } 'Owner' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text' 'OwnerSID' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text' 'OwnerType' = $OwnerType 'ACL' = @( [PsCustomObject] @{ 'Name' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text' 'Sid' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text' 'PermissionType' = 'Allow' 'Inherited' = $false 'Permissions' = 'Owner' } $XMLContent.GPO.SecurityDescriptor.Permissions.TrusteePermissions | ForEach-Object -Process { if ($_) { [PsCustomObject] @{ 'Name' = $_.trustee.name.'#Text' 'Sid' = $_.trustee.SID.'#Text' 'PermissionType' = $_.type.PermissionType 'Inherited' = if ($_.Inherited -eq 'false') { $false } else { $true } 'Permissions' = $_.Standard.GPOGroupedAccessEnum } } } ) 'Auditing' = if ($XMLContent.GPO.SecurityDescriptor.AuditingPresent.'#text' -eq 'true') { $true } else { $false } 'Links' = $XMLContent.GPO.LinksTo | ForEach-Object -Process { if ($_) { [PSCustomObject] @{ CanonicalName = $_.SOMPath Enabled = $_.Enabled NoOverride = $_.NoOverride } } } <# SOMName SOMPath Enabled NoOverride ------- ------- ------- ---------- ad ad.evotec.xyz true false #> #| Select-Object -ExpandProperty SOMPath } } #break } function Get-XMLStandard { [cmdletBinding()] param( [PSCustomObject] $GPO, [System.Xml.XmlElement[]] $GPOOutput, [string] $Splitter, [switch] $FullObjects ) $LinksInformation = Get-LinksFromXML -GPOOutput $GPOOutput -Splitter $Splitter -FullObjects:$FullObjects foreach ($GpoType in @('User', 'Computer')) { if ($GPOOutput.$GpoType.ExtensionData.Extension) { foreach ($ExtensionType in $GPOOutput.$GpoType.ExtensionData.Extension) { # It's possible that one of the ExtensionType records has value null. Weird but happend. if ($ExtensionType) { $GPOSettingTypeSplit = ($ExtensionType.type -split ':') try { $KeysToLoop = $ExtensionType | Get-Member -MemberType Properties -ErrorAction Stop | Where-Object { $_.Name -notin 'type', $GPOSettingTypeSplit[0] } } catch { Write-Warning "Get-XMLStandard - things went sideways $($_.Exception.Message)" continue } foreach ($GpoSettings in $KeysToLoop.Name) { foreach ($Key in $ExtensionType.$GpoSettings) { $Template = [ordered] @{ DisplayName = $GPO.DisplayName DomainName = $GPO.DomainName GUID = $GPO.Guid GpoType = $GpoType GpoCategory = $GPOSettingTypeSplit[1] GpoSettings = $GpoSettings } try { $Properties = ($Key | Get-Member -MemberType Properties -ErrorAction Stop).Name } catch { Write-Warning "Get-XMLStandard - things went sideways 1 $($_.Exception.Message)" $Properties = $null } foreach ($Property in $Properties) { $Template["$Property"] = $Key.$Property } $Template['Linked'] = $LinksInformation.Linked $Template['LinksCount'] = $LinksInformation.LinksCount $Template['Links'] = $LinksInformation.Links [PSCustomObject] $Template } } } } } } } function Invoke-GPOTranslation { [cmdletBinding()] param( [System.Collections.IDictionary] $InputData, [string] $Report, [string] $Category, [string] $Settings ) if ($Category -and $Settings -and $InputData) { if ($Script:GPODitionary[$Report]['Code']) { $Script:GPOList = $InputData.$Category.$Settings return & $Script:GPODitionary[$Report]['Code'] } } } function New-ADForestDrives { [cmdletbinding()] param( [string] $ForestName, [string] $ObjectDN ) if (-not $Global:ADDrivesMapped) { if ($ForestName) { $Forest = Get-ADForest -Identity $ForestName } else { $Forest = Get-ADForest } if ($ObjectDN) { # This doesn't work because no Domain and no $Server $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $ObjectDN -ToDC) -replace '=' -replace ',' if (-not(Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { try { if ($Server) { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Server.Hostname[0] -Scope Global -WhatIf:$false Write-Verbose "New-ADForestDrives - Mapped drive $Domain / $($Server.Hostname[0])" } else { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Domain -Scope Global -WhatIf:$false } } catch { Write-Warning "New-ADForestDrives - Couldn't map new AD psdrive for $Domain / $($Server.Hostname[0])" } } } else { foreach ($Domain in $Forest.Domains) { try { $Server = Get-ADDomainController -Discover -DomainName $Domain $DomainInformation = Get-ADDomain -Server $Server.Hostname[0] } catch { Write-Warning "New-ADForestDrives - Can't process domain $Domain - $($_.Exception.Message)" continue } $ObjectDN = $DomainInformation.DistinguishedName $DNConverted = (ConvertFrom-DistinguishedName -DistinguishedName $ObjectDN -ToDC) -replace '=' -replace ',' if (-not(Get-PSDrive -Name $DNConverted -ErrorAction SilentlyContinue)) { try { if ($Server) { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Server.Hostname[0] -Scope Global -WhatIf:$false Write-Verbose "New-ADForestDrives - Mapped drive $Domain / $Server" } else { $null = New-PSDrive -Name $DNConverted -Root '' -PSProvider ActiveDirectory -Server $Domain -Scope Global -WhatIf:$false } } catch { Write-Warning "New-ADForestDrives - Couldn't map new AD psdrive for $Domain / $Server $($_.Exception.Message)" } } } } $Global:ADDrivesMapped = $true } } function Remove-PrivPermission { [cmdletBinding(SupportsShouldProcess)] param( [string] $Principal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'DistinguishedName', [PSCustomObject] $GPOPermission, [alias('PermissionType')][Microsoft.GroupPolicy.GPPermissionType[]] $IncludePermissionType ) if ($GPOPermission.Name) { $Text = "Removing SID: $($GPOPermission.Sid), Name: $($GPOPermission.Domain)\$($GPOPermission.Name), SidType: $($GPOPermission.SidType) from domain $($GPOPermission.DomainName)" } else { $Text = "Removing SID: $($GPOPermission.Sid), Name: EMPTY, SidType: $($GPOPermission.SidType) from domain $($GPOPermission.DomainName)" } if ($PrincipalType -eq 'DistinguishedName') { if ($GPOPermission.DistinguishedName -eq $Principal -and $GPOPermission.Permission -eq $IncludePermissionType) { if ($PSCmdlet.ShouldProcess($GPOPermission.DisplayName, $Text)) { try { Write-Verbose "Remove-GPOZaurrPermission - Removing permission $IncludePermissionType for $($Principal) / $($GPOPermission.Name) / Type: $($GPOPermission.PermissionType)" $GPOPermission.GPOSecurity.Remove($GPOPermission.GPOSecurityPermissionItem) $GPOPermission.GPOObject.SetSecurityInfo($GPOPermission.GPOSecurity) } catch { Write-Warning "Remove-GPOZaurrPermission - Removing permission $IncludePermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } } elseif ($PrincipalType -eq 'Sid') { if ($GPOPermission.Sid -eq $Principal -and $GPOPermission.Permission -eq $IncludePermissionType) { if ($PSCmdlet.ShouldProcess($GPOPermission.DisplayName, $Text)) { try { Write-Verbose "Remove-GPOZaurrPermission - Removing permission $IncludePermissionType for $($Principal) / $($GPOPermission.Name) / Type: $($GPOPermission.PermissionType)" $GPOPermission.GPOSecurity.Remove($GPOPermission.GPOSecurityPermissionItem) $GPOPermission.GPOObject.SetSecurityInfo($GPOPermission.GPOSecurity) } catch { if ($_.Exception.Message -like '*The request is not supported. (Exception from HRESULT: 0x80070032)*') { Write-Warning "Remove-GPOZaurrPermission - Bummer! The request is not supported, but lets fix it differently." # This is basically atomic approach. We will totally remove any permissions for that user on ACL level to get rid of this situation. # This situation should only happen if DENY is on FULL Control $ACL = Get-ADACL -ADObject $GPOPermission.GPOObject.Path -Bundle #-Verbose:$VerbosePreference if ($ACL) { Remove-ADACL -ACL $ACL -Principal $Principal -AccessControlType Deny -Verbose:$VerbosePreference } # I've noticed that in situation where Edit settings, delete, modify security is set and then set to Deny we need to fix it once more $ACL = Get-ADACL -ADObject $GPOPermission.GPOObject.Path -Bundle if ($ACL) { Remove-ADACL -ACL $ACL -Principal $Principal -AccessControlType Allow -Verbose:$VerbosePreference } } else { Write-Warning "Remove-GPOZaurrPermission - Removing permission $IncludePermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } } } elseif ($PrincipalType -eq 'Name') { if ($GPOPermission.Name -eq $Principal -and $GPOPermission.Permission -eq $IncludePermissionType) { if ($PSCmdlet.ShouldProcess($GPOPermission.DisplayName, $Text)) { try { Write-Verbose "Remove-GPOZaurrPermission - Removing permission $IncludePermissionType for $($Principal) / $($GPOPermission.Name) / Type: $($GPOPermission.PermissionType)" $GPOPermission.GPOSecurity.Remove($GPOPermission.GPOSecurityPermissionItem) $GPOPermission.GPOObject.SetSecurityInfo($GPOPermission.GPOSecurity) } catch { Write-Warning "Remove-GPOZaurrPermission - Removing permission $IncludePermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } } } $Script:Actions = @{ C = 'Create' D = 'Delete' U = 'Update' R = 'Replace' } $Script:GPODitionary = [ordered] @{ AccountPolicies = [ordered] @{ Category = 'SecuritySettings' Settings = 'Account' GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' Code = { ConvertTo-AccountPolicies -GPOList $GPOList } } Audit = [ordered] @{ Category = 'SecuritySettings' Settings = 'Audit' #GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' Code = { ConvertTo-Audit -GPOList $GPOList } } AuditAlternative = [ordered] @{ Category = 'SecuritySettings' Settings = 'Audit' #GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' Code = { ConvertTo-AuditAlternative -GPOList $GPOList } } Autologon = [ordered] @{ Category = 'RegistrySettings' Settings = 'RegistrySettings' Code = { ConvertTo-RegistryAutologon -GPOList $GPOList } } EventLog = [ordered] @{ Category = 'SecuritySettings' Settings = 'EventLog' #GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' Code = { ConvertTo-EventLog -GPOList $GPOList } } LocalUsersAndGroups = [ordered] @{ Category = 'LugsSettings' Settings = 'LocalUsersAndGroups' Code = { ConvertTo-LocalUserAndGroups -GPOList $GPOList } } Policies = @{ Category = 'RegistrySettings' Settings = 'Policy' Code = { ConvertTo-Policies -GPOList $GPOList } } RegistrySettings = [ordered] @{ Category = 'RegistrySettings' Settings = 'RegistrySettings' Code = { ConvertTo-RegistrySettings -GPOList $GPOList } } RegistrySettingsCollection = [ordered] @{ Category = 'RegistrySettings' Settings = 'RegistrySettings' Code = { ConvertTo-RegistrySettingsCollection -GPOList $GPOList } } Scripts = [ordered] @{ Category = 'Scripts' Settings = 'Script' Code = { ConvertTo-Scripts -GPOList $GPOList } } SecurityOptions = [ordered] @{ Category = 'SecuritySettings' Settings = 'SecurityOptions' Code = { ConvertTo-SecurityOptions -GPOList $GPOList } } SoftwareInstallation = [ordered] @{ Category = 'SoftwareInstallationSettings' Settings = 'MsiApplication' Code = { ConvertTo-SoftwareInstallation -GPOList $GPOList } } SystemServices = [ordered] @{ Description = '' GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> System Services' Category = 'SecuritySettings' Settings = 'SystemServices' Code = { ConvertTo-SystemServices -GPOList $GPOList } } SystemServicesNT = [ordered] @{ Description = '' GPOPath = 'Computer Configuration -> Preferences -> Control Pannel Settings -> Services' Category = 'ServiceSettings' Settings = 'NTServices' Code = { ConvertTo-SystemServicesNT -GPOList $GPOList } } #LugsSettings = @{ # LocalUsersAndGroups = $LugsSettingsLocalUsersAndGroups } $Script:GPOPropetiesComputers = [ordered] @{ 'Account' = '' 'Audit' = '' 'AuditSetting' = '' 'AutoEnrollmentSettings' = '' 'Blocked' = '' 'certSettingsTrustedPublishers' = '' 'DataSourcesSettings' = '' 'DomainProfile' = '' 'Dot3SvcSetting' = '' 'EFSRecoveryAgent' = '' 'EFSSettings' = '' 'EnvironmentVariables' = '' 'EventLog' = '' 'File' = '' 'FilesSettings' = '' 'Folders' = '' 'General' = '' 'Global' = '' 'GlobalSettings' = '' 'InboundFirewallRules' = '' 'IntermediateCACertificate' = '' 'InternetZoneRule' = '' 'LocalUsersAndGroups' = '' 'MsiApplication' = '' 'NetworkOptions' = '' 'NetworkShares' = '' 'NTServices' = '' 'OutboundFirewallRules' = '' 'PathRule' = '' 'Policy' = '' 'PowerOptions' = '' 'PrinterConnection' = '' 'Printers' = '' 'PrivateProfile' = '' 'PublicProfile' = '' 'Registry' = '' 'RegistrySetting' = '' 'RegistrySettings' = '' 'RestrictedGroups' = '' 'RootCertificate' = '' 'RootCertificateSettings' = '' 'ScheduledTasks' = '' 'Script' = '' 'SecurityOptions' = '' 'ShortcutSettings' = '' 'SystemServices' = '' 'TrustedPublishersCertificate' = '' 'type' = '' 'UserRightsAssignment' = '' 'WLanSvcSetting' = '' } $Script:GPOPropertiesUsers = [ordered] @{ 'AutoDetectConfigSettings' = '' 'AutoEnrollmentSettings' = '' 'AutomaticConfiguration' = '' 'AutoSetupSetting' = '' 'Blocked' = '' 'BrowserTitle' = '' 'CustomSetupSetting' = '' 'DataSourcesSettings' = '' 'DefinesConnectionSettings' = '' 'DefinesEscOffSettings' = '' 'DefinesEscOnSettings' = '' 'DeleteChannels' = '' 'DriveMapSettings' = '' 'EscOffLocalSites' = '' 'EscOffSecurityZoneAndPrivacy' = '' 'EscOffTrustedSites' = '' 'EscOnLocalSites' = '' 'EscOnSecurityZoneAndPrivacy' = '' 'EscOnTrustedSites' = '' 'FavoriteURL' = '' 'FilesSettings' = '' 'Folder' = '' 'FolderOptions' = '' 'Folders' = '' 'General' = '' 'HomePage' = '' 'ImportedContentRatings' = '' 'InternetOptions' = '' 'LocalUsersAndGroups' = '' 'MsiApplication' = '' 'NetworkOptions' = '' 'PathRule' = '' 'PlaceFavoritesAtTop' = '' 'Policy' = '' 'PowerOptions' = '' 'PreferenceMode' = '' 'PrinterConnection' = '' 'Printers' = '' 'Programs' = '' 'ProxySettings' = '' 'RegionalOptionsSettings' = '' 'RegistrySetting' = '' 'RegistrySettings' = '' 'RestartSetupSetting' = '' 'ScheduledTasks' = '' 'Script' = '' 'SearchBar' = '' 'ShortcutSettings' = '' 'StartMenuSettings' = '' 'ToolsSetting' = '' 'TrustedPublisherLockdown' = '' 'type' = '' } function Test-SysVolFolders { [cmdletBinding()] param( [Array] $GPOs, [string] $Server, [string] $Domain ) $Differences = @{ } $SysvolHash = @{ } $GPOGUIDS = $GPOs.ID.GUID try { $SYSVOL = Get-ChildItem -Path "\\$($Server)\SYSVOL\$Domain\Policies" -ErrorAction Stop } catch { $Sysvol = $Null } foreach ($_ in $SYSVOL) { $GUID = $_.Name -replace '{' -replace '}' $SysvolHash[$GUID] = $_ } $Files = $SYSVOL.Name -replace '{' -replace '}' if ($Files) { $Comparing = Compare-Object -ReferenceObject $GPOGUIDS -DifferenceObject $Files -IncludeEqual foreach ($_ in $Comparing) { if ($_.SideIndicator -eq '==') { $Found = 'Exists' } elseif ($_.SideIndicator -eq '<=') { $Found = 'Not available on SYSVOL' } elseif ($_.SideIndicator -eq '=>') { $Found = 'Orphaned GPO' } else { $Found = 'Orphaned GPO' } $Differences[$_.InputObject] = $Found } } $GPOSummary = @( foreach ($GPO in $GPOS) { if ($null -ne $SysvolHash[$GPO.Id.GUID].FullName) { $FullPath = $SysvolHash[$GPO.Id.GUID].FullName try { $ACL = Get-Acl -Path $SysvolHash[$GPO.Id.GUID].FullName -ErrorAction Stop $Owner = $ACL.Owner $ErrorMessage = '' } catch { Write-Warning "Get-GPOZaurrSysvol - ACL reading (1) failed for $FullPath with error: $($_.Exception.Message)" $ACL = $null $Owner = '' $ErrorMessage = $_.Exception.Message } } else { $ACL = $null } if ($null -eq $Differences[$GPO.Id.Guid]) { $SysVolStatus = 'Not available on SYSVOL' } else { $SysVolStatus = $Differences[$GPO.Id.Guid] } [PSCustomObject] @{ DisplayName = $GPO.DisplayName Status = $Differences[$GPO.Id.Guid] DomainName = $GPO.DomainName SysvolServer = $Server SysvolStatus = $SysVolStatus Owner = $GPO.Owner FileOwner = $Owner Id = $GPO.Id.Guid GpoStatus = $GPO.GpoStatus Path = $FullPath Description = $GPO.Description CreationTime = $GPO.CreationTime ModificationTime = $GPO.ModificationTime UserVersion = $GPO.UserVersion ComputerVersion = $GPO.ComputerVersion WmiFilter = $GPO.WmiFilter Error = $ErrorMessage } } # Now we need to list thru Sysvol files and fine those that do not exists as GPO and create dummy GPO objects to show orphaned gpos foreach ($_ in $Differences.Keys) { if ($Differences[$_] -eq 'Orphaned GPO') { if ($SysvolHash[$_].BaseName -notcontains 'PolicyDefinitions') { $FullPath = $SysvolHash[$_].FullName try { $ACL = Get-Acl -Path $FullPath -ErrorAction Stop $Owner = $ACL.Owner $ErrorMessage = '' } catch { Write-Warning "Get-GPOZaurrSysvol - ACL reading (2) failed for $FullPath with error: $($_.Exception.Message)" $ACL = $null $Owner = $null $ErrorMessage = $_.Exception.Message } [PSCustomObject] @{ DisplayName = $SysvolHash[$_].BaseName Status = 'Orphaned GPO' DomainName = $Domain SysvolServer = $Server SysvolStatus = $Differences[$GPO.Id.Guid] Owner = '' FileOwner = $Owner Id = $_ GpoStatus = 'Orphaned' Path = $FullPath Description = $null CreationTime = $SysvolHash[$_].CreationTime ModificationTime = $SysvolHash[$_].LastWriteTime UserVersion = $null ComputerVersion = $null WmiFilter = $null Error = $ErrorMessage } } } } ) $GPOSummary | Sort-Object -Property DisplayName } function Add-GPOPermission { [cmdletBinding()] param( [validateset('WellKnownAdministrative', 'Administrative', 'AuthenticatedUsers', 'Default')][string] $Type = 'Default', [Microsoft.GroupPolicy.GPPermissionType] $IncludePermissionType, [alias('Trustee')][Array] $Principal, [alias('TrusteeType')][validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'DistinguishedName', [validateSet('Allow', 'Deny')][string] $PermitType = 'Allow' ) if ($Type -eq 'Default') { @{ Action = 'Add' Type = 'Default' Principal = $Principal IncludePermissionType = $IncludePermissionType PrincipalType = $PrincipalType PermitType = $PermitType } } elseif ($Type -eq 'AuthenticatedUsers') { @{ Action = 'Add' Type = 'AuthenticatedUsers' IncludePermissionType = $IncludePermissionType PermitType = $PermitType } } elseif ($Type -eq 'Administrative') { @{ Action = 'Add' Type = 'Administrative' IncludePermissionType = $IncludePermissionType PermitType = $PermitType } } elseif ($Type -eq 'WellKnownAdministrative') { @{ Action = 'Add' Type = 'WellKnownAdministrative' IncludePermissionType = $IncludePermissionType PermitType = $PermitType } } } function Add-GPOZaurrPermission { [cmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'GPOGUID')] param( [Parameter(ParameterSetName = 'GPOName', Mandatory)] [string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID', Mandatory)] [alias('GUID', 'GPOID')][string] $GPOGuid, [Parameter(ParameterSetName = 'ADObject', Mandatory)] [alias('OrganizationalUnit', 'DistinguishedName')][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject, [validateset('WellKnownAdministrative', 'Administrative', 'AuthenticatedUsers', 'Default')][string] $Type = 'Default', [alias('Trustee')][string] $Principal, [alias('TrusteeType')][validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'DistinguishedName', [Parameter(Mandatory)][alias('IncludePermissionType')][Microsoft.GroupPolicy.GPPermissionType] $PermissionType, [switch] $Inheritable, [validateSet('Allow', 'Deny', 'All')][string] $PermitType = 'All', [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [System.Collections.IDictionary] $ADAdministrativeGroups, [int] $LimitProcessing ) $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Extended if (-not $ADAdministrativeGroups) { $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } if ($GPOName) { $Splat = @{ GPOName = $GPOName } } elseif ($GPOGUID) { $Splat = @{ GPOGUID = $GPOGUID } } else { $Splat = @{} } $Splat['IncludeGPOObject'] = $true $Splat['Forest'] = $Forest $Splat['IncludeDomains'] = $IncludeDomains if ($Type -ne 'Default') { $Splat['Type'] = $Type } $Splat['PermitType'] = $PermitType $Splat['Principal'] = $Principal if ($PrincipalType) { $Splat.PrincipalType = $PrincipalType } $Splat['ExcludeDomains'] = $ExcludeDomains $Splat['ExtendedForestInformation'] = $ExtendedForestInformation #$Splat['ExcludePermissionType'] = $ExcludePermissionType $Splat['IncludePermissionType'] = $PermissionType $Splat['SkipWellKnown'] = $SkipWellKnown.IsPresent $Splat['SkipAdministrative'] = $SkipAdministrative.IsPresent $AdministrativeExists = @{ DomainAdmins = $false EnterpriseAdmins = $false } # This should always return results. When no data is found it should return basic information that will allow us to add credentials. [Array] $GPOPermissions = Get-GPOZaurrPermission @Splat -ReturnSecurityWhenNoData # When it has GPOSecurityPermissionItem property it means it has permissions, if it doesn't it means we have clean object to process if ($GPOPermissions.GPOSecurityPermissionItem) { # Permission exists, but may be incomplete foreach ($GPOPermission in $GPOPermissions) { if ($Type -eq 'Default') { # We were looking for specific principal and we got it. nothing to do # this is for standard users such as przemyslaw.klys / adam.gonzales return } elseif ($Type -eq 'Administrative') { # We are looking for administrative but we need to make sure we got correct administrative if ($GPOPermission.Permission -eq $PermissionType) { $AdministrativeGroup = $ADAdministrativeGroups['BySID'][$GPOPermission.SID] if ($AdministrativeGroup.SID -like '*-519') { $AdministrativeExists['EnterpriseAdmins'] = $true } elseif ($AdministrativeGroup.SID -like '*-512') { $AdministrativeExists['DomainAdmins'] = $true } <# if ($AdministrativeGroup) { $DomainAdminsSID = -join ($ForestInformation['DomainsExtended'][$GPOPermission.DomainName].DomainSID, '-512') $EnterpriseAdminsSID = -join ($ForestInformation['DomainsExtended'][$GPOPermission.DomainName].DomainSID, '-519') if ($GPOPermission.SID -eq $DomainAdminsSID) { $AdministrativeExists['DomainAdmins'] = $true } elseif ($GPOPermission.SID -eq $EnterpriseAdminsSID) { $AdministrativeExists['EnterpriseAdmins'] = $true } } #> } } elseif ($Type -eq 'WellKnownAdministrative') { # this is for SYSTEM account return } elseif ($Type -eq 'AuthenticatedUsers') { # this is for Authenticated Users return } } } if (-not $GPOPermissions) { # This is bad - things went wrong Write-Warning "Add-GPOZaurrPermission - Couldn't get permissions for GPO. Things aren't what they should be. Skipping!" } else { $GPO = $GPOPermissions[0] if ($GPOPermissions.GPOSecurityPermissionItem) { # We asked, we got response, now we need to check if maybe we're missing one of the two administrative groups if ($Type -eq 'Administrative') { # this is a case where something was returned. Be it Domain Admins or Enterprise Admins or both. But we still need to check because it may have been Domain Admins from other domain or just one of the two required groups if ($AdministrativeExists['DomainAdmins'] -eq $false) { $Principal = $ADAdministrativeGroups[$GPO.DomainName]['DomainAdmins'] Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } if ($AdministrativeExists['EnterpriseAdmins'] -eq $false) { $Principal = $ADAdministrativeGroups[$ForestInformation.Forest.RootDomain]['EnterpriseAdmins'] Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } } elseif ($Type -eq 'Default') { # This shouldn't really happen, as if we got response, and it didn't exists it wouldn't be here Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType skipped for $($Principal). This shouldn't even happen!" } } else { # We got no response. That means we either asked incorrectly or we need to fix permission. Trying to do so if ($Type -eq 'Default') { Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal)" $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } elseif ($Type -eq 'Administrative') { # this is a case where both Domain Admins/Enterprise Admins were missing $Principal = $ADAdministrativeGroups[$GPO.DomainName]['DomainAdmins'] Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } $Principal = $ADAdministrativeGroups[$ForestInformation.Forest.RootDomain]['EnterpriseAdmins'] Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) with error: $($_.Exception.Message)" } } } elseif ($Type -eq 'WellKnownAdministrative') { $Principal = 'S-1-5-18' Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal (SYSTEM) / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) (SYSTEM) with error: $($_.Exception.Message)" } } } elseif ($Type -eq 'AuthenticatedUsers') { $Principal = 'S-1-5-11' Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)" if ($PSCmdlet.ShouldProcess($GPO.DisplayName, "Adding $Principal (Authenticated Users) / $PermissionType to $($GPO.DisplayName) at $($GPO.DomainName)")) { try { $AddPermission = [Microsoft.GroupPolicy.GPPermission]::new($Principal, $PermissionType, $Inheritable.IsPresent) $GPO.GPOSecurity.Add($AddPermission) $GPO.GPOObject.SetSecurityInfo($GPO.GPOSecurity) } catch { Write-Warning "Add-GPOZaurrPermission - Adding permission $PermissionType failed for $($Principal) (Authenticated Users) with error: $($_.Exception.Message)" } } } } } } function Backup-GPOZaurr { [cmdletBinding(SupportsShouldProcess)] param( [int] $LimitProcessing, [validateset('All', 'Empty', 'Unlinked')][string[]] $Type = 'All', [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [string[]] $GPOPath, [string] $BackupPath, [switch] $BackupDated ) Begin { if ($BackupDated) { $BackupFinalPath = "$BackupPath\$((Get-Date).ToString('yyyy-MM-dd_HH_mm_ss'))" } else { $BackupFinalPath = $BackupPath } Write-Verbose "Backup-GPOZaurr - Backing up to $BackupFinalPath" $null = New-Item -ItemType Directory -Path $BackupFinalPath -Force $Count = 0 } Process { Get-GPOZaurr -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -GPOPath $GPOPath | ForEach-Object { if ($Type -contains 'All') { Write-Verbose "Backup-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName)" $Count++ try { $BackupInfo = Backup-GPO -Guid $_.GUID -Domain $_.DomainName -Path $BackupFinalPath -ErrorAction Stop #-Server $QueryServer $BackupInfo } catch { Write-Warning "Backup-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" } if ($LimitProcessing -eq $Count) { break } } if ($Type -notcontains 'All' -and $Type -contains 'Empty') { if ($_.ComputerSettingsAvailable -eq $false -and $_.UserSettingsAvailable -eq $false) { Write-Verbose "Backup-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName)" $Count++ try { $BackupInfo = Backup-GPO -Guid $_.GUID -Domain $_.DomainName -Path $BackupFinalPath -ErrorAction Stop #-Server $QueryServer $BackupInfo } catch { Write-Warning "Backup-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" } if ($LimitProcessing -eq $Count) { break } } } if ($Type -notcontains 'All' -and $Type -contains 'Unlinked') { if ($_.Linked -eq $false) { Write-Verbose "Backup-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName)" $Count++ try { $BackupInfo = Backup-GPO -Guid $_.GUID -Domain $_.DomainName -Path $BackupFinalPath -ErrorAction Stop #-Server $QueryServer $BackupInfo } catch { Write-Warning "Backup-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" } if ($LimitProcessing -eq $Count) { break } } } } } End { } } function Get-GPOZaurr { [cmdletBinding()] param( [string] $GPOName, [alias('GUID', 'GPOID')][string] $GPOGuid, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [string[]] $GPOPath, [switch] $PermissionsOnly, [switch] $OwnerOnly, [switch] $Limited, [System.Collections.IDictionary] $ADAdministrativeGroups ) Begin { if (-not $ADAdministrativeGroups) { Write-Verbose "Get-GPOZaurr - Getting ADAdministrativeGroups" $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } if (-not $GPOPath) { $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } } Process { if (-not $GPOPath) { foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation.QueryServers[$Domain]['HostName'][0] if ($GPOName) { Get-GPO -Name $GPOName -Domain $Domain -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { Write-Verbose "Get-GPOZaurr - Getting GPO $($_.DisplayName) / ID: $($_.ID) from $Domain" if (-not $Limited) { try { $XMLContent = Get-GPOReport -ID $_.ID -ReportType XML -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain -ErrorAction Stop } catch { Write-Warning "Get-GPOZaurr - Failed to get GPOReport: $($_.Exception.Message). Skipping." continue } Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups } else { $_ } } } elseif ($GPOGuid) { Get-GPO -Guid $GPOGuid -Domain $Domain -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { Write-Verbose "Get-GPOZaurr - Getting GPO $($_.DisplayName) / ID: $($_.ID) from $Domain" if (-not $Limited) { try { $XMLContent = Get-GPOReport -ID $_.ID -ReportType XML -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain -ErrorAction Stop } catch { Write-Warning "Get-GPOZaurr - Failed to get GPOReport: $($_.Exception.Message). Skipping." continue } Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups } else { $_ } } } else { Get-GPO -All -Server $QueryServer -Domain $Domain -ErrorAction SilentlyContinue | ForEach-Object { Write-Verbose "Get-GPOZaurr - Getting GPO $($_.DisplayName) / ID: $($_.ID) from $Domain" if (-not $Limited) { try { $XMLContent = Get-GPOReport -ID $_.ID -ReportType XML -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain -ErrorAction Stop } catch { Write-Warning "Get-GPOZaurr - Failed to get GPOReport: $($_.Exception.Message). Skipping." continue } Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups } else { $_ } } } } } else { foreach ($Path in $GPOPath) { Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml | ForEach-Object { $XMLContent = [XML]::new() $XMLContent.Load($_.FullName) Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -PermissionsOnly:$PermissionsOnly.IsPresent } } } } End { } } function Get-GPOZaurrAD { [cmdletbinding(DefaultParameterSetName = 'Default')] param( [Parameter(ParameterSetName = 'GPOName')] [string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID')] [alias('GUID', 'GPOID')][string] $GPOGuid, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) Begin { $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } Process { foreach ($Domain in $ForestInformation.Domains) { if ($PSCmdlet.ParameterSetName -eq 'GPOGUID') { if ($GPOGuid) { if ($GPOGUID -notlike '*{*') { $GUID = -join ("{", $GPOGUID, '}') } else { $GUID = $GPOGUID } $Splat = @{ Filter = "(objectClass -eq 'groupPolicyContainer') -and (Name -eq '$GUID')" Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0] } } else { Write-Warning "Get-GPOZaurrAD - GPOGUID parameter is empty. Provide name and try again." continue } } elseif ($PSCmdlet.ParameterSetName -eq 'GPOName') { if ($GPOName) { $Splat = @{ Filter = "(objectClass -eq 'groupPolicyContainer') -and (DisplayName -eq '$GPOName')" Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0] } } else { Write-Warning "Get-GPOZaurrAD - GPOName parameter is empty. Provide name and try again." continue } } else { $Splat = @{ Filter = "(objectClass -eq 'groupPolicyContainer')" Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0] } } Get-ADObject @Splat -Properties DisplayName, Name, Created, Modified, gPCFileSysPath, gPCFunctionalityVersion, gPCWQLFilter, gPCMachineExtensionNames, Description, CanonicalName, DistinguishedName | ForEach-Object -Process { $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_.DistinguishedName -ToDomainCN $GUID = $_.Name -replace '{' -replace '}' if (($GUID).Length -ne 36) { Write-Warning "Get-GPOZaurrAD - GPO GUID ($($($GUID.Replace("`n",' ')))) is incorrect. Skipping $($_.DisplayName) / Domain: $($DomainCN)" } else { $Output = [ordered]@{ } $Output['DisplayName'] = $_.DisplayName $Output['DomainName'] = $DomainCN $Output['Description'] = $_.Description $Output['GUID'] = $GUID $Output['Path'] = $_.gPCFileSysPath $Output['FunctionalityVersion'] = $_.gPCFunctionalityVersion $Output['Created'] = $_.Created $Output['Modified'] = $_.Modified $Output['GPOCanonicalName'] = $_.CanonicalName $Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_.DistinguishedName -ToDC $Output['GPODistinguishedName'] = $_.DistinguishedName [PSCustomObject] $Output } } } } End { } } function Get-GPOZaurrBackupInformation { [cmdletBinding()] param( [string[]] $BackupFolder ) Begin { } Process { foreach ($Folder in $BackupFolder) { if ($Folder) { if ((Test-Path -LiteralPath "$Folder\manifest.xml")) { [xml] $Xml = Get-Content -LiteralPath "$Folder\manifest.xml" $Xml.Backups.BackupInst | ForEach-Object -Process { [PSCustomObject] @{ DisplayName = $_.GPODisplayName.'#cdata-section' DomainName = $_.GPODomain.'#cdata-section' Guid = $_.GPOGUid.'#cdata-section' -replace '{' -replace '}' DomainGuid = $_.GPODomainGuid.'#cdata-section' -replace '{' -replace '}' DomainController = $_.GPODomainController.'#cdata-section' BackupTime = [DateTime]::Parse($_.BackupTime.'#cdata-section') ID = $_.ID.'#cdata-section' -replace '{' -replace '}' Comment = $_.Comment.'#cdata-section' } } } else { Write-Warning "Get-GPOZaurrBackupInformation - No backup information available" } } } } End { } } function Get-GPOZaurrFiles { [cmdletbinding()] param( [ValidateSet('All', 'Netlogon', 'Sysvol')][string[]] $Type = 'All', [ValidateSet('None', 'MACTripleDES', 'MD5', 'RIPEMD160', 'SHA1', 'SHA256', 'SHA384', 'SHA512')][string] $HashAlgorithm = 'None', [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $Path = @( if ($Type -contains 'All') { "\\$Domain\SYSVOL\$Domain" } if ($Type -contains 'Sysvol') { "\\$Domain\SYSVOL\$Domain\policies" } if ($Type -contains 'NetLogon') { "\\$Domain\NETLOGON" } ) Get-ChildItem -Path $Path -ErrorAction SilentlyContinue -Recurse -ErrorVariable err -File | ForEach-Object { Get-FileMetaData -File $_ -Signature -HashAlgorithm $HashAlgorithm } foreach ($e in $err) { Write-Warning "Get-GPOZaurrFiles - $($e.Exception.Message) ($($e.CategoryInfo.Reason))" } } } function Get-GPOZaurrLegacyFiles { [cmdletbinding()] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { Get-ChildItem -Path "\\$Domain\SYSVOL\$Domain\policies" -ErrorAction SilentlyContinue -Recurse -Include '*.adm' -ErrorVariable err | Select-Object Name, FullName, CreationTime, LastWriteTime, Attributes foreach ($e in $err) { Write-Warning "Get-GPOZaurrLegacy - $($e.Exception.Message) ($($e.CategoryInfo.Reason))" } } } function Get-GPOZaurrLink { [cmdletbinding()] param( [parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject, # weirdly enough site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase [parameter(ParameterSetName = 'Filter')][string] $Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')", [parameter(ParameterSetName = 'Filter')][string] $SearchBase, [parameter(ParameterSetName = 'Filter')][Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope, [parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'Site', 'Other')][string] $Linked, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [switch] $Limited, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [switch] $SkipDuplicates, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [System.Collections.IDictionary] $GPOCache, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [alias('ForestName')][string] $Forest, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [string[]] $ExcludeDomains, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [alias('Domain', 'Domains')][string[]] $IncludeDomains, [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [System.Collections.IDictionary] $ExtendedForestInformation ) Begin { $CacheReturnedGPOs = [ordered] @{} $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation if (-not $GPOCache -and -not $Limited) { $GPOCache = @{ } # While initially we used $ForestInformation.Domains but the thing is GPOs can be linked to other domains so we need to get them all so we can use cache of it later on even if we're processing just one domain # That's why we use $ForestInformation.Forest.Domains instead foreach ($Domain in $ForestInformation.Forest.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] Get-GPO -All -DomainName $Domain -Server $QueryServer | ForEach-Object { $GPOCache["$Domain$($_.ID.Guid)"] = $_ } } } } Process { if (-not $ADObject) { if ($Linked) { foreach ($Domain in $ForestInformation.Domains) { $Splat = @{ #Filter = $Filter Properties = 'distinguishedName', 'gplink', 'CanonicalName' # Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')" Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0] } if ($Linked -contains 'DomainControllers') { $SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer'] #if ($SearchBase -notlike "*$DomainDistinguishedName") { # we check if SearchBase is part of domain distinugishname. If it isn't we skip # continue #} $Splat['Filter'] = "(objectClass -eq 'organizationalUnit')" $Splat['SearchBase'] = $SearchBase try { $ADObjectGPO = Get-ADObject @Splat } catch { Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)" } foreach ($_ in $ADObjectGPO) { $OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache foreach ($OutputGPO in $OutputGPOs) { if (-not $SkipDuplicates) { $OutputGPO } else { $UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid) if (-not $CacheReturnedGPOs[$UniqueGuid]) { $CacheReturnedGPOs[$UniqueGuid] = $OutputGPO $OutputGPO } } } } } if ($Linked -contains 'Root') { $SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'] #if ($SearchBase -notlike "*$DomainDistinguishedName") { # we check if SearchBase is part of domain distinugishname. If it isn't we skip # continue # } $Splat['Filter'] = "objectClass -eq 'domainDNS'" $Splat['SearchBase'] = $SearchBase try { $ADObjectGPO = Get-ADObject @Splat } catch { Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)" } foreach ($_ in $ADObjectGPO) { $OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache foreach ($OutputGPO in $OutputGPOs) { if (-not $SkipDuplicates) { $OutputGPO } else { $UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid) if (-not $CacheReturnedGPOs[$UniqueGuid]) { $CacheReturnedGPOs[$UniqueGuid] = $OutputGPO $OutputGPO } } } } } if ($Linked -contains 'Site') { # Sites are defined only in primary domain if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) { $SearchBase = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) # if ($SearchBase -notlike "*$DomainDistinguishedName") { # we check if SearchBase is part of domain distinugishname. If it isn't we skip #continue #} $Splat['Filter'] = "(objectClass -eq 'site')" $Splat['SearchBase'] = $SearchBase try { $ADObjectGPO = Get-ADObject @Splat } catch { Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)" } foreach ($_ in $ADObjectGPO) { Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache } } } if ($Linked -contains 'Other') { $SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'] #if ($SearchBase -notlike "*$DomainDistinguishedName") { # we check if SearchBase is part of domain distinugishname. If it isn't we skip # continue #} $Splat['Filter'] = "(objectClass -eq 'organizationalUnit')" $Splat['SearchBase'] = $SearchBase try { $ADObjectGPO = Get-ADObject @Splat } catch { Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)" } foreach ($_ in $ADObjectGPO) { if ($_.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) { # other skips Domain Root } elseif ($_.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) { # other skips Domain Controllers } else { $OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache foreach ($OutputGPO in $OutputGPOs) { if (-not $SkipDuplicates) { $OutputGPO } else { $UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid) if (-not $CacheReturnedGPOs[$UniqueGuid]) { $CacheReturnedGPOs[$UniqueGuid] = $OutputGPO $OutputGPO } } } } } } } } else { foreach ($Domain in $ForestInformation.Domains) { $Splat = @{ Filter = $Filter Properties = 'distinguishedName', 'gplink', 'CanonicalName' Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0] } if ($PSBoundParameters.ContainsKey('SearchBase')) { $DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'] $SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC if ($SearchBaseDC -ne $DomainDistinguishedName) { # we check if SearchBase is part of domain distinugishname. If it isn't we skip continue } $Splat['SearchBase'] = $SearchBase } if ($PSBoundParameters.ContainsKey('SearchScope')) { $Splat['SearchScope'] = $SearchScope } try { $ADObjectGPO = Get-ADObject @Splat } catch { Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)" } foreach ($_ in $ADObjectGPO) { $OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache foreach ($OutputGPO in $OutputGPOs) { if (-not $SkipDuplicates) { $OutputGPO } else { $UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid) if (-not $CacheReturnedGPOs[$UniqueGuid]) { $CacheReturnedGPOs[$UniqueGuid] = $OutputGPO $OutputGPO } } } } } } } else { foreach ($Object in $ADObject) { Get-PrivGPOZaurrLink -Object $Object -Limited:$Limited.IsPresent -GPOCache $GPOCache } } } End { } } function Get-GPOZaurrLinkSummary { [cmdletBinding()] param( [ValidateSet('All', 'MultipleLinks', 'OneLink', 'LinksSummary')][string[]] $Report = 'All', [switch] $UnlimitedProperties, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) $HighestCount = 0 # to keep number of depth $CacheSummaryLinks = [ordered] @{} # cache # Get all links $Links = Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Link in $Links) { if (-not $CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"]) { $CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"] = [System.Collections.Generic.List[System.Object]]::new() } $CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"].Add($Link) } $ReturnObject = [ordered] @{ MultipleLinks = [System.Collections.Generic.List[System.Object]]::new() OneLink = [System.Collections.Generic.List[System.Object]]::new() LinksSummary = [System.Collections.Generic.List[System.Object]]::new() } foreach ($Key in $CacheSummaryLinks.Keys) { $GPOs = $CacheSummaryLinks[$Key] [Array] $LinkingSummary = foreach ($GPO in $GPOs) { $SplitttedOU = ($GPO.DistinguishedName -split ',') [Array] $Clean = foreach ($_ in $SplitttedOU) { if ($_ -notlike 'DC=*') { $_ -replace 'OU=' } } if ($Clean.Count -gt $HighestCount) { $HighestCount = $Clean.Count } if ($Clean) { $Test = [ordered] @{ DisplayName = $GPO.DisplayName Guid = $GPO.Guid DomainName = $GPO.DomainName Level0 = ConvertFrom-DistinguishedName -DistinguishedName $GPO.DistinguishedName -ToDomainCN } for ($i = 1; $i -le 10; $i++) { $Test["Level$i"] = $Clean[ - $i] } [PSCustomobject] $Test } else { $Test = [ordered] @{ DisplayName = $GPO.DisplayName Guid = $GPO.Guid DomainName = $GPO.DomainName Level0 = $GPO.CanonicalName } for ($i = 1; $i -le 10; $i++) { $Test["Level$i"] = $null } [PSCustomobject] $Test } } if ($Report -contains 'MultipleLinks' -or $Report -contains 'All') { foreach ($Link in $LinkingSummary) { $ReturnObject.MultipleLinks.Add($Link) } #continue } if ($Report -eq 'OneLink' -or $Report -contains 'All') { $List = [ordered] @{ DisplayName = $GPOs[0].DisplayName Guid = $GPOs[0].Guid DomainName = $GPOs[0].DomainName LinksCount = $GPOs.Count } for ($i = 0; $i -le 10; $i++) { $List["Level$i"] = ($LinkingSummary."Level$i" | Select-Object -Unique).Count $List["Level$($i)List"] = ($LinkingSummary."Level$i" | Select-Object -Unique) } $List.LinksDistinguishedName = $GPOs.DistinguishedName # = Computers, OU = ITR02, DC = ad, DC = evotec, DC = xyz $List.LinksCanonicalName = $GPOs.CanonicalName $List.Owner = $GPOs[0].Owner #: EVOTEC\Domain Admins $List.GpoStatus = $GPOs[0].GpoStatus #: AllSettingsEnabled $List.Description = $GPOs[0].Description #: $List.CreationTime = $GPOs[0].CreationTime #: 16.12.2019 21:25:32 $List.ModificationTime = $GPOs[0].ModificationTime #: 30.05.2020 19:12:58 $List.GPODomainDistinguishedName = $GPOs[0].GPODomainDistinguishedName #: DC = ad, DC = evotec, DC = xyz $List.GPODistinguishedName = $GPOs[0].GPODistinguishedName #: cn = { AA782787 - 002B-4B8C-886F-05873F2DC0CA }, cn = policies, cn = system, DC = ad, DC = evotec, DC = xy $ReturnObject.OneLink.Add( [PSCustomObject] $List) } if ($Report -eq 'LinksSummary' -or $Report -contains 'All') { $Output = [PSCustomObject] @{ DisplayName = $GPOs[0].DisplayName #: COMPUTERS | LAPS Guid = $GPOs[0].Guid #: AA782787 - 002B-4B8C-886F-05873F2DC0CA DomainName = $GPOs[0].DomainName #: ad.evotec.xyz LinksCount = $GPOs.Count LinksDistinguishedName = $GPOs.DistinguishedName # = Computers, OU = ITR02, DC = ad, DC = evotec, DC = xyz LinksCanonicalName = $GPOs.CanonicalName #: ad.evotec.xyz / ITR02 / Computers Owner = $GPOs[0].Owner #: EVOTEC\Domain Admins GpoStatus = $GPOs[0].GpoStatus #: AllSettingsEnabled Description = $GPOs[0].Description #: CreationTime = $GPOs[0].CreationTime #: 16.12.2019 21:25:32 ModificationTime = $GPOs[0].ModificationTime #: 30.05.2020 19:12:58 GPODomainDistinguishedName = $GPOs[0].GPODomainDistinguishedName #: DC = ad, DC = evotec, DC = xyz GPODistinguishedName = $GPOs[0].GPODistinguishedName #: cn = { AA782787 - 002B-4B8C-886F-05873F2DC0CA }, cn = policies, cn = system, DC = ad, DC = evotec, DC = xy } $ReturnObject.LinksSummary.Add($Output) } } # Processing output if (-not $UnlimitedProperties) { if ($Report -contains 'MultipleLinks' -or $Report -contains 'All') { $Properties = @( 'DisplayName' 'DomainName' 'GUID' for ($i = 0; $i -le $HighestCount; $i++) { "Level$i" } 'Owner' 'GpoStatus' 'Description' 'CreationTime' 'ModificationTime' 'GPODomainDistinguishedName' 'GPODistinguishedName' ) $ReturnObject.MultipleLinks = $ReturnObject.MultipleLinks | Select-Object -Property $Properties } if ($Report -contains 'OneLink' -or $Report -contains 'All') { $Properties = @( 'DisplayName' 'DomainName' 'GUID' for ($i = 0; $i -le $HighestCount; $i++) { "Level$i" "Level$($i)List" } 'LinksDistinguishedName' 'LinksCanonicalName' 'Owner' 'GpoStatus' 'Description' 'CreationTime' 'ModificationTime' 'GPODomainDistinguishedName' 'GPODistinguishedName' ) $ReturnObject.OneLink = $ReturnObject.OneLink | Select-Object -Property $Properties } #if ($Report -contains 'LinksSummary' -or $Report -contains 'All') { # Not needed because there's no dynamic properties, but if there would be we need to uncomment and fix it #} } if ($Report.Count -eq 1 -and $Report -notcontains 'All') { $ReturnObject["$Report"] } else { $ReturnObject } } function Get-GPOZaurrOwner { [cmdletbinding(DefaultParameterSetName = 'Default')] param( [Parameter(ParameterSetName = 'GPOName')][string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID')][alias('GUID', 'GPOID')][string] $GPOGuid, [switch] $IncludeSysvol, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [System.Collections.IDictionary] $ADAdministrativeGroups ) Begin { $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation if (-not $ADAdministrativeGroups) { $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } } Process { $getGPOZaurrADSplat = @{ Forest = $Forest IncludeDomains = $IncludeDomains ExcludeDomains = $ExcludeDomains ExtendedForestInformation = $ForestInformation } if ($GPOName) { $getGPOZaurrADSplat['GPOName'] = $GPOName } elseif ($GPOGuid) { $getGPOZaurrADSplat['GPOGUID'] = $GPOGuid } $Objects = Get-GPOZaurrAD @getGPOZaurrADSplat foreach ($_ in $Objects) { Write-Verbose "Get-GPOZaurrOwner - Processing GPO: $($_.DisplayName) from domain: $($_.DomainName)" $ACL = Get-ADACLOwner -ADObject $_.GPODistinguishedName -Resolve -ADAdministrativeGroups $ADAdministrativeGroups $Object = [ordered] @{ DisplayName = $_.DisplayName DomainName = $_.DomainName GUID = $_.GUID Owner = $ACL.OwnerName OwnerSid = $ACL.OwnerSid OwnerType = $ACL.OwnerType } if ($IncludeSysvol) { $FileOwner = Get-FileOwner -JustPath -Path $_.Path -Resolve $Object['SysvolOwner'] = $FileOwner.OwnerName $Object['SysvolSid'] = $FileOwner.OwnerSid $Object['SysvolType'] = $FileOwner.OwnerType $Object['SysvolPath'] = $_.Path $Object['IsOwnerConsistent'] = if ($ACL.OwnerName -eq $FileOwner.OwnerName) { $true } else { $false } } $Object['DistinguishedName'] = $_.GPODistinguishedName [PSCUstomObject] $Object } } End { } } function Get-GPOZaurrPassword { [cmdletBinding()] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [string[]] $GPOPath ) if (-not $GPOPath) { if (-not $ExtendedForestInformation) { $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains } else { $ForestInformation = $ExtendedForestInformation } [Array] $GPOPath = foreach ($Domain in $ForestInformation.Domains) { -join ('\\', $Domain, '\SYSVOL\', $Domain, '\Policies') } } if (-not $GPOPath) { return } foreach ($Path in $GPOPath) { #Extract the all XML files in the Folders $Items = Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml $Output = foreach ($XMLFileName in $Items) { #Convert XML in a String file [string]$XMLString = Get-Content ($XMLFileName.FullName) #Check if Cpassword Exist in the file if ($XMLString.Contains("cpassword")) { #Take the Cpassword Value from XML String file [string]$Cpassword = [regex]::matches($XMLString, '(cpassword=).+?(?=\")') $Cpassword = $Cpassword.split('(\")')[1] #Check if Cpassword has a value if ($Cpassword.Length -gt 20 -and $Cpassword -notlike '*cpassword*') { $Mod = ($Cpassword.length % 4) switch ($Mod) { '1' { $Cpassword = $Cpassword.Substring(0, $Cpassword.Length - 1) } '2' { $Cpassword += ('=' * (4 - $Mod)) } '3' { $Cpassword += ('=' * (4 - $Mod)) } } $Base64Decoded = [Convert]::FromBase64String($Cpassword) $AesObject = [System.Security.Cryptography.AesCryptoServiceProvider]::new() #Use th AES Key [Byte[]] $AesKey = @(0x4e, 0x99, 0x06, 0xe8, 0xfc, 0xb6, 0x6c, 0xc9, 0xfa, 0xf4, 0x93, 0x10, 0x62, 0x0f, 0xfe, 0xe8, 0xf4, 0x96, 0xe8, 0x06, 0xcc, 0x05, 0x79, 0x90, 0x20, 0x9b, 0x09, 0xa4, 0x33, 0xb6, 0x6c, 0x1b) $AesIV = New-Object Byte[]($AesObject.IV.Length) $AesObject.IV = $AesIV $AesObject.Key = $AesKey $DecryptorObject = $AesObject.CreateDecryptor() [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length) #Convert Hash variable in a String valute $Password = [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock) } else { $Password = '' } #[string]$GPOguid = [regex]::matches($XMLFileName.DirectoryName, '(?<=\{).+?(?=\})') #$GPODetail = Get-GPO -guid $GPOguid [xml] $XMLContent = $XMLString #if (-not $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups.User.Properties.cpassword -and -not $XMLContent.gpo.User.ExtensionData.Extension.DriveMapSettings.Drive.Properties.cpassword) { #Write-Host '' #} if ($Password) { $PasswordStatus = $true } else { $PasswordStatus = $false } [PsCustomObject] @{ 'Name' = $XMLContent.GPO.Name 'Links' = $XMLContent.GPO.LinksTo #| Select-Object -ExpandProperty SOMPath 'Enabled' = $XMLContent.GPO.GpoStatus 'PasswordStatus' = $PasswordStatus #'GPO' = $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups 'User' = $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups.User.name 'Cpassword' = $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups.User.Properties.cpassword 'CpasswordMap' = $XMLContent.gpo.User.ExtensionData.Extension.DriveMapSettings.Drive.Properties.cpassword 'Password' = $Password 'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText 'Domain' = $XMLContent.GPO.Identifier.Domain 'ComputerSettingsAvailable' = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true } 'ComputerSettingsStatus' = if ($XMLContent.GPO.Computer.VersionDirectory -eq 0 -and $XMLContent.GPO.Computer.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" } 'ComputerEnabled' = [bool] $XMLContent.GPO.Computer.Enabled 'ComputerSetttingsVersionIdentical' = if ($XMLContent.GPO.Computer.VersionDirectory -eq $XMLContent.GPO.Computer.VersionSysvol) { $true } else { $false } 'ComputerSettings' = $XMLContent.GPO.Computer.ExtensionData.Extension 'UserSettingsAvailable' = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true } 'UserEnabled' = [bool] $XMLContent.GPO.User.Enabled 'UserSettingsStatus' = if ($XMLContent.GPO.User.VersionDirectory -eq 0 -and $XMLContent.GPO.User.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" } 'UserSettingsVersionIdentical' = if ($XMLContent.GPO.User.VersionDirectory -eq $XMLContent.GPO.User.VersionSysvol) { $true } else { $false } 'UserSettings' = $XMLContent.GPO.User.ExtensionData.Extension 'CreationTime' = [DateTime] $XMLContent.GPO.CreatedTime 'ModificationTime' = [DateTime] $XMLContent.GPO.ModifiedTime 'ReadTime' = [DateTime] $XMLContent.GPO.ReadTime 'WMIFilter' = $GPO.WmiFilter.name 'WMIFilterDescription' = $GPO.WmiFilter.Description 'Path' = $GPO.Path #'SDDL' = if ($Splitter -ne '') { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' -join $Splitter } else { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' } 'ACL' = $XMLContent.GPO.SecurityDescriptor.Permissions.TrusteePermissions | ForEach-Object -Process { [PSCustomObject] @{ 'User' = $_.trustee.name.'#Text' 'Permission Type' = $_.type.PermissionType 'Inherited' = $_.Inherited 'Permissions' = $_.Standard.GPOGroupedAccessEnum } } } #Write-Host "I find a Password [ " $Password " ] The GPO named:" $GPODetail" and th file is:" $XMLFileName } #if($XMLContent.Contains("cpassword") } $Output } } function Get-GPOZaurrPermission { [cmdletBinding(DefaultParameterSetName = 'GPO' )] param( [Parameter(ParameterSetName = 'GPOName')] [string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID')] [alias('GUID', 'GPOID')][string] $GPOGuid, [string[]] $Principal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'Sid', [validateSet('AuthenticatedUsers', 'DomainComputers', 'Unknown', 'WellKnownAdministrative', 'NotWellKnown', 'NotWellKnownAdministrative', 'NotAdministrative', 'Administrative', 'All')][string[]] $Type = 'All', [switch] $SkipWellKnown, [switch] $SkipAdministrative, [switch] $ResolveAccounts, [switch] $IncludeOwner, [Microsoft.GroupPolicy.GPPermissionType[]] $IncludePermissionType, [Microsoft.GroupPolicy.GPPermissionType[]] $ExcludePermissionType, [validateSet('Allow', 'Deny', 'All')][string] $PermitType = 'All', [string[]] $ExcludePrincipal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $ExcludePrincipalType = 'Sid', [switch] $IncludeGPOObject, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [System.Collections.IDictionary] $ADAdministrativeGroups, [switch] $ReturnSecurityWhenNoData # if no data return all data ) Begin { $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Extended if (-not $ADAdministrativeGroups) { $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } if ($Type -eq 'Unknown') { if ($SkipAdministrative -or $SkipWellKnown) { Write-Warning "Get-GPOZaurrPermission - Using SkipAdministrative or SkipWellKnown while looking for Unknown doesn't make sense as only Unknown will be displayed." } } if ($ResolveAccounts) { $Accounts = @{ } foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer $Users = Get-ADUser -Filter * -Server $QueryServer -Properties PasswordLastSet, LastLogonDate, UserPrincipalName foreach ($User in $Users) { $U = -join ($DomainInformation.NetBIOSName, '\', $User.SamAccountName) $Accounts[$U] = $User } $Groups = Get-ADGroup -Filter * -Server $QueryServer foreach ($Group in $Groups) { $G = -join ($DomainInformation.NetBIOSName, '\', $Group.SamAccountName) $Accounts[$G] = $Group } } } } Process { foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] if ($GPOName) { $getGPOSplat = @{ Name = $GPOName Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } $TextForError = "Error running Get-GPO (QueryServer: $QueryServer / Domain: $Domain / Name: $GPOName) with:" } elseif ($GPOGuid) { $getGPOSplat = @{ Guid = $GPOGuid Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } $TextForError = "Error running Get-GPO (QueryServer: $QueryServer / Domain: $Domain / GUID: $GPOGuid) with:" } else { $getGPOSplat = @{ All = $true Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } $TextForError = "Error running Get-GPO (QueryServer: $QueryServer / Domain: $Domain / All: $True) with:" } Try { Get-GPO @getGPOSplat | ForEach-Object -Process { $GPOSecurity = $_.GetSecurityInfo() $getPrivPermissionSplat = @{ Principal = $Principal PrincipalType = $PrincipalType PermitType = $PermitType Accounts = $Accounts Type = $Type GPO = $_ SkipWellKnown = $SkipWellKnown.IsPresent SkipAdministrative = $SkipAdministrative.IsPresent IncludeOwner = $IncludeOwner.IsPresent IncludeGPOObject = $IncludeGPOObject.IsPresent IncludePermissionType = $IncludePermissionType ExcludePermissionType = $ExcludePermissionType ExcludePrincipal = $ExcludePrincipal ExcludePrincipalType = $ExcludePrincipalType ADAdministrativeGroups = $ADAdministrativeGroups ExtendedForestInformation = $ForestInformation SecurityRights = $GPOSecurity } try { $Output = Get-PrivPermission @getPrivPermissionSplat } catch { $Output = $null Write-Warning "Get-GPOZaurrPermission - Error running Get-PrivPermission: $($_.Exception.Message)" } if (-not $Output) { if ($ReturnSecurityWhenNoData) { # there is no data to return, but we need to have GPO information to process ADD permissions. $ReturnObject = [PSCustomObject] @{ DisplayName = $_.DisplayName # : ALL | Enable RDP GUID = $_.ID DomainName = $_.DomainName # : ad.evotec.xyz Enabled = $_.GpoStatus Description = $_.Description CreationDate = $_.CreationTime ModificationTime = $_.ModificationTime GPOObject = $_ GPOSecurity = $GPOSecurity } $ReturnObject } } else { $Output } } } catch { Write-Warning "Get-GPOZaurrPermission - $TextForError $($_.Exception.Message)" } } } End { } } function Get-GPOZaurrPermissionConsistency { [cmdletBinding(DefaultParameterSetName = 'Type')] param( [Parameter(ParameterSetName = 'GPOName')][string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID')][alias('GUID', 'GPOID')][string] $GPOGuid, [Parameter(ParameterSetName = 'Type')][validateSet('Consistent', 'Inconsistent', 'All')][string[]] $Type = 'All', [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [switch] $IncludeGPOObject, [switch] $VerifyInheritance ) Begin { $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } Process { foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] if ($GPOName) { $getGPOSplat = @{ Name = $GPOName Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } } elseif ($GPOGuid) { $getGPOSplat = @{ Guid = $GPOGuid Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } } else { $getGPOSplat = @{ All = $true Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } } Get-GPO @getGPOSplat | ForEach-Object -Process { try { $IsConsistent = $_.IsAclConsistent() $ErrorMessage = '' } catch { $ErrorMessage = $_.Exception.Message Write-Warning "Get-GPOZaurrPermissionConsistency - Failed to get consistency: $($_.Exception.Message)." $IsConsistent = 'Not available.' } $SysVolpath = -join ('\\', $Domain, '\sysvol\', $Domain, '\Policies\{', $_.ID.GUID, '}') if ($VerifyInheritance) { $FolderPermissions = Get-WinADSharePermission -Path $SysVolpath [Array] $NotInheritedPermissions = foreach ($File in $FolderPermissions) { if ($File.Path -ne $SysVolpath -and $File.IsInherited -eq $false) { $File } } if ($NotInheritedPermissions.Count -eq 0) { $ACLConsistentInside = $true } else { $ACLConsistentInside = $false } } else { $ACLConsistentInside = $null } $Object = [ordered] @{ DisplayName = $_.DisplayName # : New Group Policy Object DomainName = $_.DomainName # : ad.evotec.xyz ACLConsistent = $IsConsistent } if ($VerifyInheritance) { $Object['ACLConsistentInside'] = $ACLConsistentInside } $Object['Owner'] = $_.Owner # : EVOTEC\Enterprise Admins $Object['Path'] = $_.Path $Object['SysVolPath '] = $SysvolPath $Object['Id '] = $_.Id # : 8a7bc515-d7fd-4d1f-90b8-e47c15f89295 $Object['GpoStatus'] = $_.GpoStatus # : AllSettingsEnabled $Object['Description'] = $_.Description # : $Object['CreationTime'] = $_.CreationTime # : 04.03.2020 17:19:42 $Object['ModificationTime'] = $_.ModificationTime# : 06.05.2020 10:30:36 $Object['UserVersion'] = $_.UserVersion # : AD Version: 0, SysVol Version: 0 $Object['ComputerVersion'] = $_.ComputerVersion # : AD Version: 1, SysVol Version: 1 $Object['WmiFilter'] = $_.WmiFilter # : $Object['Error'] = $ErrorMessage if ($IncludeGPOObject) { $Object['IncludeGPOObject'] = $_ } if ($VerifyInheritance) { $Object['ACLConsistentInsideDetails'] = $NotInheritedPermissions } if ($Type -eq 'All') { [PSCustomObject] $Object } elseif ($Type -eq 'Inconsistent') { if ($VerifyInheritance) { if (-not $IsConsistent -or -not $ACLConsistentInside) { [PSCustomObject] $Object } } else { if (-not $IsConsistent) { [PSCustomObject] $Object } } } elseif ($Type -eq 'Consistent') { if ($VerifyInheritance) { if ($IsConsistent -and $ACLConsistentInside) { [PSCustomObject] $Object } } else { if ($IsConsistent) { [PSCustomObject] $Object } } } } } } End { } } function Get-GPOZaurrSysvol { [cmdletBinding()] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [string[]] $ExcludeDomainControllers, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [alias('DomainControllers')][string[]] $IncludeDomainControllers, [switch] $SkipRODC, [Array] $GPOs, [System.Collections.IDictionary] $ExtendedForestInformation, [switch] $VerifyDomainControllers ) $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { Write-Verbose "Get-WinADGPOSysvolFolders - Processing $Domain" $QueryServer = $ForestInformation['QueryServers']["$Domain"].HostName[0] Try { [Array]$GPOs = Get-GPO -All -Domain $Domain -Server $QueryServer } catch { Write-Warning "Get-GPOZaurrSysvol - Couldn't get GPOs from $Domain. Error: $($_.Exception.Message)" continue } if ($GPOs.Count -ge 2) { if (-not $VerifyDomainControllers) { Test-SysVolFolders -GPOs $GPOs -Server $Domain -Domain $Domain } else { foreach ($Server in $ForestInformation['DomainDomainControllers']["$Domain"]) { Write-Verbose "Get-GPOZaurrSysvol - Processing $Domain \ $($Server.HostName.Trim())" Test-SysVolFolders -GPOs $GPOs -Server $Server.Hostname -Domain $Domain } } } else { Write-Warning "Get-GPOZaurrSysvol - GPO count for $Domain is less then 2. This is not expected for fully functioning domain. Skipping processing SYSVOL folder." } } } function Get-WMIFilter { param( ) } function Get-GPOZaurrWMI { [cmdletBinding()] Param( [Guid[]] $Guid, [string[]] $Name, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) $wmiFilterAttr = "msWMI-Name", "msWMI-Parm1", "msWMI-Parm2", "msWMI-Author", "msWMI-ID", 'CanonicalName', 'Created', 'Modified' $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $Objects = @( if ($Name) { foreach ($N in $Name) { try { $ldapFilter = "(&(objectClass=msWMI-Som)(msWMI-Name=$N))" Get-ADObject -LDAPFilter $ldapFilter -Properties $wmiFilterAttr -Server $QueryServer } catch { Write-Warning "Get-GPOZaurrWMI - Error processing WMI for $Domain`: $($_.Error.Exception)" } } } elseif ($GUID) { foreach ($G in $GUID) { try { $ldapFilter = "(&(objectClass=msWMI-Som)(Name={$G}))" Get-ADObject -LDAPFilter $ldapFilter -Properties $wmiFilterAttr -Server $QueryServer } catch { Write-Warning "Get-GPOZaurrWMI - Error processing WMI for $Domain`: $($_.Error.Exception)" } } } else { try { $ldapFilter = "(objectClass=msWMI-Som)" Get-ADObject -LDAPFilter $ldapFilter -Properties $wmiFilterAttr -Server $QueryServer } catch { Write-Warning "Get-GPOZaurrWMI - Error processing WMI for $Domain`: $($_.Error.Exception)" } } ) foreach ($_ in $Objects) { $WMI = $_.'msWMI-Parm2' -split ';' #$WMI = $_.'msWMI-Parm2'.Split(';',8) [Array] $Data = for ($i = 0; $i -lt $WMI.length; $i += 6) { if ($WMI[$i + 5]) { #[PSCustomObject] @{ # NameSpace = $WMI[$i + 5] # Query = $WMI[$i + 6] #} -join ($WMI[$i + 5], ';' , $WMI[$i + 6]) } } [PSCustomObject] @{ DisplayName = $_.'msWMI-Name' Description = $_.'msWMI-Parm1' DomainName = $Domain #NameSpace = $WMI[$i + 5] #Query = $WMI[$i + 6] QueryCount = $Data.Count Query = $Data -join "," Author = $_.'msWMI-Author' ID = $_.'msWMI-ID' Created = $_.Created Modified = $_.Modified ObjectGUID = $_.'ObjectGUID' CanonicalName = $_.CanonicalName DistinguishedName = $_.'DistinguishedName' } } } } <# CanonicalName : ad.evotec.xyz/System/WMIPolicy/SOM/{E988C890-BDBC-4946-87B5-BF70F39F4686} CN : {E988C890-BDBC-4946-87B5-BF70F39F4686} Created : 08.04.2020 19:04:06 createTimeStamp : 08.04.2020 19:04:06 Deleted : Description : DisplayName : DistinguishedName : CN={E988C890-BDBC-4946-87B5-BF70F39F4686},CN=SOM,CN=WMIPolicy,CN=System,DC=ad,DC=evotec,DC=xyz dSCorePropagationData : {01.01.1601 01:00:00} instanceType : 4 isDeleted : LastKnownParent : Modified : 08.04.2020 19:04:06 modifyTimeStamp : 08.04.2020 19:04:06 msWMI-Author : przemyslaw.klys@evotec.pl msWMI-ChangeDate : 20200408170406.280000-000 msWMI-CreationDate : 20200408170406.280000-000 msWMI-ID : {E988C890-BDBC-4946-87B5-BF70F39F4686} msWMI-Name : Virtual Machines msWMI-Parm1 : Oh my description msWMI-Parm2 : 1;3;10;66;WQL;root\CIMv2;SELECT * FROM Win32_ComputerSystem WHERE Model = "Virtual Machine"; Name : {E988C890-BDBC-4946-87B5-BF70F39F4686} nTSecurityDescriptor : System.DirectoryServices.ActiveDirectorySecurity ObjectCategory : CN=ms-WMI-Som,CN=Schema,CN=Configuration,DC=ad,DC=evotec,DC=xyz ObjectClass : msWMI-Som ObjectGUID : c1ee708d-7a67-46e2-b13f-d11a573d2597 ProtectedFromAccidentalDeletion : False sDRightsEffective : 15 showInAdvancedViewOnly : True uSNChanged : 12785589 uSNCreated : 12785589 whenChanged : 08.04.2020 19:04:06 whenCreated : 08.04.2020 19:04:06 #> function Invoke-GPOZaurr { [alias('Find-GPO')] [cmdletBinding(DefaultParameterSetName = 'Default')] param( [Parameter(ParameterSetName = 'Default')][alias('ForestName')][string] $Forest, [Parameter(ParameterSetName = 'Default')][string[]] $ExcludeDomains, [Parameter(ParameterSetName = 'Default')][alias('Domain', 'Domains')][string[]] $IncludeDomains, [Parameter(ParameterSetName = 'Default')][System.Collections.IDictionary] $ExtendedForestInformation, [Parameter(ParameterSetName = 'Local')][string] $GPOPath, [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [string[]] $Type, [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [switch] $NoTranslation, [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [string] $Splitter = [System.Environment]::NewLine, [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [switch] $FullObjects, [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [ValidateSet('HTML', 'Object', 'Excel')][string[]] $OutputType = 'Object', [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [string] $OutputPath, [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] [switch] $Open ) if ($Type.Count -eq 0) { $Type = $Script:GPODitionary.Keys } if ($GPOPath) { if (Test-Path -LiteralPath $GPOPath) { <# $GPOListPath = [io.path]::Combine($GPOPath, "GPOList.xml") if ($GPOListPath) { $GPOs = Import-Clixml -Path $GPOListPath } else { } #> $GPOFiles = Get-ChildItem -LiteralPath $GPOPath -Recurse -File [Array] $GPOs = foreach ($File in $GPOFiles) { if ($File.Name -ne 'GPOList.xml') { [xml] $GPORead = Get-Content -LiteralPath $File.FullName [PSCustomObject] @{ DisplayName = $GPORead.GPO.Name DomainName = $GPORead.GPO.Identifier.Domain.'#text' GUID = $GPORead.GPO.Identifier.Identifier.'#text' -replace '{' -replace '}' GPOOutput = $GPORead } } } } else { Write-Warning "Find-GPO - $GPOPath doesn't exists." return } } else { [Array] $GPOs = Get-GPOZaurrAD -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } $Output = [ordered] @{} $OutputByGPO = [ordered] @{} foreach ($GPO in $GPOs) { if ($GPOPath) { $GPOOutput = $GPO.GPOOutput } else { [xml] $GPOOutput = Get-GPOReport -Guid $GPO.GUID -Domain $GPO.DomainName -ReportType Xml } [Array] $Data = Get-XMLStandard -GPO $GPO -GPOOutput $GPOOutput.GPO -Splitter $Splitter -FullObjects:$FullObjects foreach ($D in $Data) { if (-not $Output["$($D.GpoCategory)"]) { $Output["$($D.GpoCategory)"] = [ordered] @{} } if (-not $Output["$($D.GpoCategory)"]["$($D.GpoSettings)"]) { $Output["$($D.GpoCategory)"]["$($D.GpoSettings)"] = [System.Collections.Generic.List[PSCustomObject]]::new() } $Output["$($D.GpoCategory)"]["$($D.GpoSettings)"].Add($D) if (-not $OutputByGPO["$($D.DomainName)"]) { $OutputByGPO["$($D.DomainName)"] = [ordered] @{} } if (-not $OutputByGPO[$D.DomainName][$D.DisplayName]) { $OutputByGPO[$D.DomainName][$D.DisplayName] = [System.Collections.Generic.List[PSCustomObject]]::new() } $OutputByGPO[$D.DomainName][$D.DisplayName].Add($D) } } if ($NoTranslation) { if ($OutputType -contains 'Object') { $OutputByGPO } } else { $TranslatedOutput = [ordered] @{} foreach ($Report in $Type) { $Category = $Script:GPODitionary[$Report]['Category'] $Settings = $Script:GPODitionary[$Report]['Settings'] #if (-not $TranslatedOutput[$Report]) { # $TranslatedOutput[$Report] = [ordered] @{} #} #foreach ($Setting in $Settings) { # if (-not $TranslatedOutput[$Category][$Settings]) { # $TranslatedOutput[$Category][$Settings] = [ordered] @{} # } $TranslatedOutput[$Report] = Invoke-GPOTranslation -InputData $Output -Category $Category -Settings $Settings -Report $Report #} } if ($OutputType -contains 'Object') { $TranslatedOutput } } if ($NoTranslation) { $SingleSource = $OutputType } else { $SingleSource = $TranslatedOutput } if ($OutputPath) { $FolderPath = $OutputPath } else { $FolderPath = [io.path]::GetTempPath() } if ($OutputType -contains 'HTML') { $FilePathHTML = [io.path]::Combine($FolderPath, "GPOZaurr-Summary-$((Get-Date).ToString('yyyy-MM-dd_HH_mm_ss')).html") Write-Warning "Invoke-GPOZaurr - $FilePathHTML" New-HTML { foreach ($GPOCategory in $SingleSource.Keys) { New-HTMLTab -Name $GPOCategory { if ($SingleSource["$GPOCategory"] -is [System.Collections.IDictionary]) { foreach ($GpoSettings in $SingleSource["$GPOCategory"].Keys) { New-HTMLTab -Name $GpoSettings { if ($SingleSource[$GPOCategory][$GpoSettings].Count -gt 0) { New-HTMLTable -DataTable $SingleSource[$GPOCategory][$GpoSettings] -ScrollX -DisablePaging -AllProperties -Title $GpoSettings } } } } else { if ($SingleSource[$GPOCategory].Count -gt 0) { New-HTMLTable -DataTable $SingleSource[$GPOCategory] -ScrollX -DisablePaging -AllProperties -Title $GpoSettings } } } } } -Online -ShowHTML:$Open.IsPresent -FilePath $FilePathHTML } if ($OutputType -contains 'Excel') { $FilePathExcel = [io.path]::Combine($FolderPath, "GPOZaurr-Summary-$((Get-Date).ToString('yyyy-MM-dd_HH_mm_ss')).xlsx") Write-Warning "Invoke-GPOZaurr - $FilePathExcel" foreach ($GPOCategory in $SingleSource.Keys) { if ($SingleSource["$GPOCategory"] -is [System.Collections.IDictionary]) { foreach ($GpoSettings in $SingleSource["$GPOCategory"].Keys) { if ($SingleSource[$GPOCategory][$GpoSettings].Count -gt 0) { ConvertTo-Excel -DataTable $SingleSource[$GPOCategory][$GpoSettings] -AllProperties -ExcelWorkSheetName $GpoSettings -FilePath $FilePathExcel -AutoFilter -AutoFit -Option Rename } } } else { if ($SingleSource[$GPOCategory].Count -gt 0) { ConvertTo-Excel -DataTable $SingleSource[$GPOCategory] -AllProperties -ExcelWorkSheetName $GPOCategory -FilePath $FilePathExcel -AutoFilter -AutoFit -Option Rename } } } if ($Open) { Invoke-Item -Path $FilePathExcel } } } [scriptblock] $SourcesAutoCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $Script:GPODitionary.Keys | Sort-Object | Where-Object { $_ -like "*$wordToComplete*" } } Register-ArgumentCompleter -CommandName Find-GPO -ParameterName Type -ScriptBlock $SourcesAutoCompleter function Invoke-GPOZaurrPermission { [cmdletBinding(SupportsShouldProcess)] param( [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [parameter(Position = 0)] [scriptblock] $PermissionRules, # ParameterSet1 [Parameter(ParameterSetName = 'GPOName')][string] $GPOName, # ParameterSet2 [Parameter(ParameterSetName = 'GPOGUID')][alias('GUID', 'GPOID')][string] $GPOGuid, # ParameterSet3 [parameter(ParameterSetName = 'Level', Mandatory)][int] $Level, [parameter(ParameterSetName = 'Level', Mandatory)][int] $Limit, # ParameterSet4 [parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'Site', 'Other')][string] $Linked, # ParameterSet5 [parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject, # ParameterSet6 [parameter(ParameterSetName = 'Filter')][string] $Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')", [parameter(ParameterSetName = 'Filter')][string] $SearchBase, [parameter(ParameterSetName = 'Filter')][Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope, # All other paramerrs are for for all parametersets [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [validateSet('Unknown', 'NotWellKnown', 'NotWellKnownAdministrative', 'NotAdministrative', 'All')][string[]] $Type, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [Array] $ApprovedGroups, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [alias('Principal')][Array] $Trustee, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [Microsoft.GroupPolicy.GPPermissionType] $TrusteePermissionType, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [alias('PrincipalType')][validateset('DistinguishedName', 'Name', 'Sid')][string] $TrusteeType = 'DistinguishedName', [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [System.Collections.IDictionary] $GPOCache, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [alias('ForestName')][string] $Forest, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [string[]] $ExcludeDomains, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [alias('Domain', 'Domains')][string[]] $IncludeDomains, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [System.Collections.IDictionary] $ExtendedForestInformation, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [parameter(ParameterSetName = 'Level')] [switch] $LimitAdministrativeGroupsToDomain, [Parameter(ParameterSetName = 'GPOGUID')] [Parameter(ParameterSetName = 'GPOName')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'ADObject')] [parameter(ParameterSetName = 'Linked')] [switch] $SkipDuplicates ) if ($PermissionRules) { $Rules = & $PermissionRules } else { Write-Warning "Invoke-GPOZaurrPermission - No rules defined. Stopping processing." return } $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation if ($LimitAdministrativeGroupsToDomain) { # This will get administrative based on IncludeDomains if given. It means that if GPO has Domain admins added from multiple domains it will only find one, and remove all other Domain Admins (if working with Domain Admins that is) $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ForestInformation } else { $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest #-IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ForestInformation } if ($PSCmdlet.ParameterSetName -ne 'Level') { $Splat = @{ Forest = $Forest IncludeDomains = $IncludeDomains ExcludeDomains = $ExcludeDomains ExtendedForestInformation = $ForestInformation SkipDuplicates = $SkipDuplicates.IsPresent } if ($ADObject) { $Splat['ADObject'] = $ADObject } elseif ($Linked) { $Splat['Linked'] = $Linked } elseif ($GPOName) { } elseif ($GPOGuid) { } else { if ($Filter) { $Splat['Filter'] = $Filter } if ($SearchBase) { $Splat['SearchBase'] = $SearchBase } if ($SearchScope) { $Splat['SearchScope'] = $SearchScope } } Get-GPOZaurrLink @Splat | ForEach-Object -Process { $GPO = $_ foreach ($Rule in $Rules) { if ($Rule.Action -eq 'Owner') { if ($Rule.Type -eq 'Administrative') { # We check for Owner (sometimes it can be empty) if ($GPO.Owner) { $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($GPO.Owner)"] } else { $AdministrativeGroup = $null } if (-not $AdministrativeGroup) { $DefaultPrincipal = $ADAdministrativeGroups["$($GPO.DomainName)"]['DomainAdmins'] Write-Verbose "Invoke-GPOZaurrPermission - Changing GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.Owner) to $DefaultPrincipal" #Set-ADACLOwner -ADObject $GPO.GPODistinguishedName -Principal $DefaultPrincipal -Verbose:$false -WhatIf:$WhatIfPreference Set-GPOZaurrOwner -GPOGuid $GPO.Guid -IncludeDomains $GPO.Domain -Principal $DefaultPrincipal -WhatIf:$WhatIfPreference } } elseif ($Rule.Type -eq 'Default') { Write-Verbose "Invoke-GPOZaurrPermission - Changing GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.Owner) to $($Rule.Principal)" #Set-ADACLOwner -ADObject $GPO.GPODistinguishedName -Principal $Rule.Principal -Verbose:$false -WhatIf:$WhatIfPreference Set-GPOZaurrOwner -GPOGuid $GPO.Guid -IncludeDomains $GPO.Domain -Principal $Rule.Principal -WhatIf:$WhatIfPreference } } elseif ($Rule.Action -eq 'Remove') { $GPOPermissions = Get-GPOZaurrPermission -GPOGuid $GPO.GUID -IncludeDomains $GPO.DomainName -IncludePermissionType $Rule.IncludePermissionType -ExcludePermissionType $Rule.ExcludePermissionType -Type $Rule.Type -IncludeGPOObject -PermitType $Rule.PermitType -Principal $Rule.Principal -PrincipalType $Rule.PrincipalType -ExcludePrincipal $Rule.ExcludePrincipal -ExcludePrincipalType $Rule.ExcludePrincipalType -ADAdministrativeGroups $ADAdministrativeGroups foreach ($Permission in $GPOPermissions) { Remove-PrivPermission -Principal $Permission.Sid -PrincipalType Sid -GPOPermission $Permission -IncludePermissionType $Permission.Permission } } elseif ($Rule.Action -eq 'Add') { # Initially we were askng for same domain as user requested, but in fact we need to apply GPODomain as it can be linked to different domain $SplatPermissions = @{ #Forest = $Forest IncludeDomains = $GPO.DomainName #ExcludeDomains = $ExcludeDomains #ExtendedForestInformation = $ForestInformation GPOGuid = $GPO.GUID IncludePermissionType = $Rule.IncludePermissionType Type = $Rule.Type PermitType = $Rule.PermitType Principal = $Rule.Principal ADAdministrativeGroups = $ADAdministrativeGroups } if ($Rule.PrincipalType) { $SplatPermissions.PrincipalType = $Rule.PrincipalType } Add-GPOZaurrPermission @SplatPermissions } } } } else { # This is special case based on different command $Report = Get-GPOZaurrLinkSummary -Report OneLink $AffectedGPOs = foreach ($GPO in $Report) { $Property = "Level$($Level)" if ($GPO."$Property" -gt $Limit) { foreach ($Rule in $Rules) { if ($Rule.Action -eq 'Owner') { if ($Rule.Type -eq 'Administrative') { # We check for Owner (sometimes it can be empty) if ($GPO.Owner) { $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($GPO.Owner)"] } else { $AdministrativeGroup = $null } if (-not $AdministrativeGroup) { $DefaultPrincipal = $ADAdministrativeGroups["$($GPO.DomainName)"]['DomainAdmins'] Write-Verbose "Invoke-GPOZaurrPermission - Changing GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.Owner) to $DefaultPrincipal" #Set-ADACLOwner -ADObject $GPO.GPODistinguishedName -Principal $DefaultPrincipal -Verbose:$false -WhatIf:$WhatIfPreference Set-GPOZaurrOwner -GPOGuid $GPO.Guid -IncludeDomains $GPO.Domain -Principal $DefaultPrincipal -WhatIf:$WhatIfPreference } } elseif ($Rule.Type -eq 'Default') { Write-Verbose "Invoke-GPOZaurrPermission - Changing GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.Owner) to $($Rule.Principal)" #Set-ADACLOwner -ADObject $GPO.GPODistinguishedName -Principal $Rule.Principal -Verbose:$false -WhatIf:$WhatIfPreference Set-GPOZaurrOwner -GPOGuid $GPO.Guid -IncludeDomains $GPO.Domain -Principal $Rule.Principal -WhatIf:$WhatIfPreference } } elseif ($Rule.Action -eq 'Remove') { $GPOPermissions = Get-GPOZaurrPermission -GPOGuid $GPO.GUID -IncludeDomains $GPO.DomainName -IncludePermissionType $Rule.IncludePermissionType -ExcludePermissionType $Rule.ExcludePermissionType -Type $Rule.Type -IncludeGPOObject -PermitType $Rule.PermitType -Principal $Rule.Principal -PrincipalType $Rule.PrincipalType -ExcludePrincipal $Rule.ExcludePrincipal -ExcludePrincipalType $Rule.ExcludePrincipalType -ADAdministrativeGroups $ADAdministrativeGroups foreach ($Permission in $GPOPermissions) { Remove-PrivPermission -Principal $Permission.Sid -PrincipalType Sid -GPOPermission $Permission -IncludePermissionType $Permission.Permission } } elseif ($Rule.Action -eq 'Add') { # Initially we were askng for same domain as user requested, but in fact we need to apply GPODomain as it can be linked to different domain $SplatPermissions = @{ #Forest = $Forest IncludeDomains = $GPO.DomainName #ExcludeDomains = $ExcludeDomains #ExtendedForestInformation = $ForestInformation GPOGuid = $GPO.GUID IncludePermissionType = $Rule.IncludePermissionType Type = $Rule.Type PermitType = $Rule.PermitType Principal = $Rule.Principal ADAdministrativeGroups = $ADAdministrativeGroups } if ($Rule.PrincipalType) { $SplatPermissions.PrincipalType = $Rule.PrincipalType } Add-GPOZaurrPermission @SplatPermissions } } } } $AffectedGPOs } } function New-GPOZaurrWMI { [cmdletBinding(SupportsShouldProcess)] param( [parameter(Mandatory)][string] $Name, [string] $Description = ' ', [string] $Namespace = 'root\CIMv2', [parameter(Mandatory)][string] $Query, [switch] $SkipQueryCheck, [switch] $Force, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) if (-not $Forest -and -not $ExcludeDomains -and -not $IncludeDomains -and -not $ExtendedForestInformation) { $IncludeDomains = $Env:USERDNSDOMAIN } if (-not $SkipQueryCheck) { try { $null = Get-CimInstance -Query $Query -ErrorAction Stop -Verbose:$false } catch { Write-Warning "New-GPOZaurrWMI - Query error $($_.Exception.Message). Terminating." return } } $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer $defaultNamingContext = $DomainInformation.DistinguishedName #$defaultNamingContext = (Get-ADRootDSE).defaultnamingcontext [string] $Author = (([ADSI]"LDAP://<SID=$([System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value)>").UserPrincipalName).ToString() [string] $GUID = "{" + ([System.Guid]::NewGuid()) + "}" [string] $DistinguishedName = -join ("CN=", $GUID, ",CN=SOM,CN=WMIPolicy,CN=System,", $defaultNamingContext) $CurrentTime = (Get-Date).ToUniversalTime() [string] $CurrentDate = -join ( ($CurrentTime.Year).ToString("0000"), ($CurrentTime.Month).ToString("00"), ($CurrentTime.Day).ToString("00"), ($CurrentTime.Hour).ToString("00"), ($CurrentTime.Minute).ToString("00"), ($CurrentTime.Second).ToString("00"), ".", ($CurrentTime.Millisecond * 1000).ToString("000000"), "-000" ) [Array] $ExistingWmiFilter = Get-GPOZaurrWMI -ExtendedForestInformation $ForestInformation -IncludeDomains $Domain -Name $Name if ($ExistingWmiFilter.Count -eq 0) { [string] $WMIParm2 = -join ("1;3;10;", $Query.Length.ToString(), ";WQL;$Namespace;", $Query , ";") $OtherAttributes = @{ "msWMI-Name" = $Name "msWMI-Parm1" = $Description "msWMI-Parm2" = $WMIParm2 "msWMI-Author" = $Author "msWMI-ID" = $GUID "instanceType" = 4 "showInAdvancedViewOnly" = "TRUE" "distinguishedname" = $DistinguishedName "msWMI-ChangeDate" = $CurrentDate "msWMI-CreationDate" = $CurrentDate } $WMIPath = -join ("CN=SOM,CN=WMIPolicy,CN=System,", $defaultNamingContext) try { Write-Verbose "New-GPOZaurrWMI - Creating WMI filter $Name in $Domain" New-ADObject -Name $GUID -Type "msWMI-Som" -Path $WMIPath -OtherAttributes $OtherAttributes -Server $QueryServer } catch { Write-Warning "New-GPOZaurrWMI - Creating GPO filter error $($_.Exception.Message). Terminating." return } } else { foreach ($_ in $ExistingWmiFilter) { Write-Warning "New-GPOZaurrWMI - Skipping creation of GPO because name: $($_.DisplayName) guid: $($_.ID) for $($_.DomainName) already exists." } } } } function Remove-GPOPermission { [cmdletBinding()] param( [validateSet('Unknown', 'NotWellKnown', 'NotWellKnownAdministrative', 'Administrative', 'NotAdministrative', 'All')][string[]] $Type, [Microsoft.GroupPolicy.GPPermissionType[]] $IncludePermissionType, [Microsoft.GroupPolicy.GPPermissionType[]] $ExcludePermissionType, [validateSet('Allow', 'Deny', 'All')][string] $PermitType = 'Allow', [string[]] $Principal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'Sid', [string[]] $ExcludePrincipal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $ExcludePrincipalType = 'Sid' ) if ($Type) { @{ Action = 'Remove' Type = $Type IncludePermissionType = $IncludePermissionType ExcludePermissionType = $ExcludePermissionType PermitType = $PermitType Principal = $Principal PrincipalType = $PrincipalType ExcludePrincipal = $ExcludePrincipal ExcludePrincipalType = $ExcludePrincipalType } } } function Remove-GPOZaurr { [cmdletBinding(SupportsShouldProcess)] param( [parameter(Mandatory)][validateset('Empty', 'Unlinked')][string[]] $Type, [int] $LimitProcessing, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [string[]] $GPOPath, [string] $BackupPath, [switch] $BackupDated ) Begin { if ($BackupPath) { $BackupRequired = $true if ($BackupDated) { $BackupFinalPath = "$BackupPath\$((Get-Date).ToString('yyyy-MM-dd_HH_mm_ss'))" } else { $BackupFinalPath = $BackupPath } Write-Verbose "Remove-GPOZaurr - Backing up to $BackupFinalPath" $null = New-Item -ItemType Directory -Path $BackupFinalPath -Force } else { $BackupRequired = $false } $Count = 0 } Process { Get-GPOZaurr -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -GPOPath $GPOPath | ForEach-Object { if ($Type -contains 'Empty') { if ($_.ComputerSettingsAvailable -eq $false -and $_.UserSettingsAvailable -eq $false) { if ($BackupRequired) { try { Write-Verbose "Remove-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName)" $BackupInfo = Backup-GPO -Guid $_.Guid -Domain $_.DomainName -Path $BackupFinalPath -ErrorAction Stop #-Server $QueryServer $BackupInfo $BackupOK = $true } catch { Write-Warning "Remove-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" $BackupOK = $false } } if (($BackupRequired -and $BackupOK) -or (-not $BackupRequired)) { try { Write-Verbose "Remove-GPOZaurr - Removing GPO $($_.DisplayName) from $($_.DomainName)" Remove-GPO -Domain $_.DomainName -Guid $_.Guid -ErrorAction Stop #-Server $QueryServer } catch { Write-Warning "Remove-GPOZaurr - Removing GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" } } $Count++ if ($LimitProcessing -eq $Count) { break } } } if ($Type -contains 'Unlinked') { if ($_.Linked -eq $false) { if ($BackupRequired) { try { Write-Verbose "Remove-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName)" $BackupInfo = Backup-GPO -Guid $_.Guid -Domain $_.DomainName -Path $BackupFinalPath -ErrorAction Stop #-Server $QueryServer $BackupInfo $BackupOK = $true } catch { Write-Warning "Remove-GPOZaurr - Backing up GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" $BackupOK = $false } } if (($BackupRequired -and $BackupOK) -or (-not $BackupRequired)) { try { Write-Verbose "Remove-GPOZaurr - Removing GPO $($_.DisplayName) from $($_.DomainName)" Remove-GPO -Domain $_.DomainName -Guid $_.Guid -ErrorAction Stop #-Server $QueryServer } catch { Write-Warning "Remove-GPOZaurr - Removing GPO $($_.DisplayName) from $($_.DomainName) failed: $($_.Exception.Message)" } } $Count++ if ($LimitProcessing -eq $Count) { break } } } } } End { } } function Remove-GPOZaurrLegacyFiles { [cmdletBinding(SupportsShouldProcess)] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [int] $LimitProcessing = [int32]::MaxValue ) $Splat = @{ Forest = $Forest IncludeDomains = $IncludeDomains ExcludeDomains = $ExcludeDomains ExtendedForestInformation = $ExtendedForestInformation Verbose = $VerbosePreference } Get-GPOZaurrLegacyFiles @Splat | Select-Object -First $LimitProcessing | ForEach-Object { try { Remove-Item -Path $_.FullName -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message Write-Warning "Remove-GPOZaurrLegacyFiles - Failed to remove file $($_.FullName): $($ErrorMessage)." } } } function Remove-GPOZaurrOrphanedSysvolFolders { [cmdletBinding(SupportsShouldProcess)] param( [int] $LimitProcessing = [int32]::MaxValue ) Get-GPOZaurrSysvol | Where-Object { if ($_.Status -eq 'Orphaned GPO') { $_ } } | Select-Object | Select-Object -First $LimitProcessing | ForEach-Object { Remove-Item -Recurse -Force -LiteralPath $_.Path } } function Remove-GPOZaurrPermission { [cmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Global')] param( [Parameter(ParameterSetName = 'GPOName', Mandatory)] [string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID', Mandatory)] [alias('GUID', 'GPOID')][string] $GPOGuid, [string[]] $Principal, [validateset('DistinguishedName', 'Name', 'Sid')][string] $PrincipalType = 'Sid', [validateset('Unknown', 'NotAdministrative', 'Default')][string[]] $Type = 'Default', [alias('PermissionType')][Microsoft.GroupPolicy.GPPermissionType[]] $IncludePermissionType, [Microsoft.GroupPolicy.GPPermissionType[]] $ExcludePermissionType, [switch] $SkipWellKnown, [switch] $SkipAdministrative, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [int] $LimitProcessing ) Begin { $Count = 0 $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ForestInformation if ($Type -eq 'Unknown') { if ($SkipAdministrative -or $SkipWellKnown) { Write-Warning "Remove-GPOZaurrPermission - Using SkipAdministrative or SkipWellKnown while looking for Unknown doesn't make sense as only Unknown will be displayed." } } } Process { if ($Type -contains 'Named' -and $Principal.Count -eq 0) { Write-Warning "Remove-GPOZaurrPermission - When using type Named you need to provide names to remove. Terminating." return } # $GPOPermission.GPOSecurity.RemoveTrustee($GPOPermission.Sid) #void RemoveTrustee(string trustee) #void RemoveTrustee(System.Security.Principal.IdentityReference identity) #$GPOPermission.GPOSecurity.Remove #void RemoveAt(int index) #void IList[GPPermission].RemoveAt(int index) #void IList.RemoveAt(int index) foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] if ($GPOName) { $getGPOSplat = @{ Name = $GPOName Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } } elseif ($GPOGuid) { $getGPOSplat = @{ Guid = $GPOGuid Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } } else { $getGPOSplat = @{ All = $true Domain = $Domain Server = $QueryServer ErrorAction = 'SilentlyContinue' } } Get-GPO @getGPOSplat | ForEach-Object -Process { $getPrivPermissionSplat = @{ Principal = $Principal PrincipalType = $PrincipalType Accounts = $Accounts Type = $Type GPO = $_ SkipWellKnown = $SkipWellKnown.IsPresent SkipAdministrative = $SkipAdministrative.IsPresent IncludeOwner = $false IncludeGPOObject = $true IncludePermissionType = $IncludePermissionType ExcludePermissionType = $ExcludePermissionType ADAdministrativeGroups = $ADAdministrativeGroups } [Array] $GPOPermissions = Get-PrivPermission @getPrivPermissionSplat if ($GPOPermissions.Count -gt 0) { foreach ($Permission in $GPOPermissions) { Remove-PrivPermission -Principal $Permission.Sid -PrincipalType Sid -GPOPermission $Permission -IncludePermissionType $Permission.Permission #-IncludeDomains $GPO.DomainName } $Count++ if ($Count -eq $LimitProcessing) { # skipping skips per removed permission not per gpo. break } } } } <# Get-GPOZaurrPermission @Splat | ForEach-Object -Process { $GPOPermission = $_ if ($Type -contains 'Unknown') { if ($GPOPermission.SidType -eq 'Unknown') { #Write-Verbose "Remove-GPOZaurrPermission - Removing $($GPOPermission.Sid) from $($GPOPermission.DisplayName) at $($GPOPermission.DomainName)" if ($PSCmdlet.ShouldProcess($GPOPermission.DisplayName, "Removing $($GPOPermission.Sid) from $($GPOPermission.DisplayName) at $($GPOPermission.DomainName)")) { try { Write-Verbose "Remove-GPOZaurrPermission - Removing permission $($GPOPermission.Permission) for $($GPOPermission.Sid)" $GPOPermission.GPOSecurity.RemoveTrustee($GPOPermission.Sid) $GPOPermission.GPOObject.SetSecurityInfo($GPOPermission.GPOSecurity) #$GPOPermission.GPOSecurity.RemoveAt($GPOPermission.GPOSecurityPermissionItem) #$GPOPermission.GPOObject.SetSecurityInfo($GPOPermission.GPOSecurity) } catch { Write-Warning "Remove-GPOZaurrPermission - Removing permission $($GPOPermission.Permission) for $($GPOPermission.Sid) with error: $($_.Exception.Message)" } # Set-GPPPermission doesn't work on Unknown Accounts } $Count++ if ($Count -eq $LimitProcessing) { # skipping skips per removed permission not per gpo. break } } } if ($Type -contains 'Named') { } if ($Type -contains 'NotAdministrative') { } if ($Type -contains 'Default') { Remove-PrivPermission -Principal $Principal -PrincipalType $PrincipalType -GPOPermission $GPOPermission -IncludePermissionType $IncludePermissionType } #Set-GPPermission -PermissionLevel None -TargetName $GPOPermission.Sid -Verbose -DomainName $GPOPermission.DomainName -Guid $GPOPermission.GUID #-WhatIf #Set-GPPermission -PermissionLevel GpoRead -TargetName 'Authenticated Users' -TargetType Group -Verbose -DomainName $Domain -Guid $_.GUID -WhatIf } #> } End {} } function Remove-GPOZaurrWMI { [CmdletBinding(SupportsShouldProcess)] Param ( [Guid[]] $Guid, [string[]] $Name, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) if (-not $Forest -and -not $ExcludeDomains -and -not $IncludeDomains -and -not $ExtendedForestInformation) { $IncludeDomains = $Env:USERDNSDOMAIN } $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] [Array] $Objects = @( if ($Guid) { Get-GPOZaurrWMI -Guid $Guid -ExtendedForestInformation $ForestInformation -IncludeDomains $Domain } if ($Name) { Get-GPOZaurrWMI -Name $Name -ExtendedForestInformation $ForestInformation -IncludeDomains $Domain } ) $Objects | ForEach-Object -Process { if ($_.DistinguishedName) { Write-Verbose "Remove-GPOZaurrWMI - Removing WMI Filter $($_.DistinguishedName)" Remove-ADObject $_.DistinguishedName -Confirm:$false -Server $QueryServer } } } } function Repair-GPOZaurrPermissionConsistency { [cmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Default')] param( [Parameter(ParameterSetName = 'GPOName')][string] $GPOName, [Parameter(ParameterSetName = 'GPOGUID')][alias('GUID', 'GPOID')][string] $GPOGuid, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [int] $LimitProcessing = [int32]::MaxValue ) $ConsistencySplat = @{ Forest = $Forest IncludeDomains = $IncludeDomains ExcludeDomains = $ExcludeDomains ExtendedForestInformation = $ExtendedForestInformation Verbose = $VerbosePreference } if ($GPOName) { $ConsistencySplat['GPOName'] = $GPOName } elseif ($GPOGuid) { $ConsistencySplat['GPOGuid'] = $GPOGUiD } else { $ConsistencySplat['Type'] = 'Inconsistent' } Get-GPOZaurrPermissionConsistency @ConsistencySplat -IncludeGPOObject | Where-Object { if ($_.ACLConsistent -eq $false) { $_ } } | Select-Object -First $LimitProcessing | ForEach-Object { #Write-Verbose "Repair-GPOZaurrPermissionConsistency - Repairing GPO consistency $($_.DisplayName) from domain: $($_.DomainName)" if ($PSCmdlet.ShouldProcess($_.DisplayName, "Reparing GPO permissions consistency in domain $($_.DomainName)")) { try { $_.IncludeGPOObject.MakeAclConsistent() } catch { $ErrorMessage = $_.Exception.Message Write-Warning "Repair-GPOZaurrPermissionConsistency - Failed to set consistency: $($ErrorMessage)." } } } } function Restore-GPOZaurr { [cmdletBinding()] param( [parameter(Mandatory)][string] $BackupFolder, [alias('Name')][string] $DisplayName, [string] $NewDisplayName, [string] $Domain, [switch] $SkipBackupSummary ) if ($BackupFolder) { if (Test-Path -LiteralPath $BackupFolder) { if ($DisplayName) { if (-not $SkipBackupSummary) { $BackupSummary = Get-GPOZaurrBackupInformation -BackupFolder $BackupFolder if ($Domain) { [Array] $FoundGPO = $BackupSummary | Where-Object { $_.DisplayName -eq $DisplayName -and $_.DomainName -eq $Domain } } else { [Array] $FoundGPO = $BackupSummary | Where-Object { $_.DisplayName -eq $DisplayName } } foreach ($GPO in $FoundGPO) { if ($NewDisplayName) { Import-GPO -Path $BackupFolder -BackupId $GPO.ID -Domain $GPO.Domain -TargetName $NewDisplayName -CreateIfNeeded } else { Write-Verbose "Restore-GPOZaurr - Restoring GPO $($GPO.DisplayName) from $($GPO.DomainName) / BackupId: $($GPO.ID)" try { Restore-GPO -Path $BackupFolder -BackupId $GPO.ID -Domain $GPO.DomainName } catch { Write-Warning "Restore-GPOZaurr - Restoring GPO $($GPO.DisplayName) from $($GPO.DomainName) failed: $($_.Exception.Message)" } } } } else { if ($Domain) { Write-Verbose "Restore-GPOZaurr - Restoring GPO $($Name) from $($Domain)" try { Restore-GPO -Path $BackupFolder -Name $Name -Domain $Domain } catch { Write-Warning "Restore-GPOZaurr - Restoring GPO $($Name) from $($Domain) failed: $($_.Exception.Message)" } } else { Write-Verbose "Restore-GPOZaurr - Restoring GPO $($Name)" try { Restore-GPO -Path $BackupFolder -Name $Name } catch { Write-Warning "Restore-GPOZaurr - Restoring GPO $($Name) failed: $($_.Exception.Message)" } } } } else { $BackupSummary = Get-GPOZaurrBackupInformation -BackupFolder $BackupFolder foreach ($GPO in $BackupSummary) { Write-Verbose "Restore-GPOZaurr - Restoring GPO $($GPO.DisplayName) from $($GPO.DomainName) / BackupId: $($GPO.ID)" try { Restore-GPO -Path $BackupFolder -Domain $GPO.DomainName -BackupId $GPO.ID } catch { Write-Warning "Restore-GPOZaurr - Restoring GPO $($GPO.DisplayName) from $($GPO.DomainName) failed: $($_.Exception.Message)" } } } } else { Write-Warning "Restore-GPOZaurr - BackupFolder incorrect ($BackupFolder)" } } } function Save-GPOZaurrFiles { [cmdletBinding()] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation, [string[]] $GPOPath, [switch] $DeleteExisting ) if ($GPOPath) { if ($DeleteExisting) { $Test = Test-Path -LiteralPath $GPOPath if ($Test) { Write-Verbose "Save-GPOZaurrFiles - Removing existing content in $GPOPath" Remove-Item -LiteralPath $GPOPath -Recurse } } $null = New-Item -ItemType Directory -Path $GPOPath -Force $GPOs = Get-GPOZaurrAD -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($GPO in $GPOS) { $XMLContent = Get-GPOReport -ID $GPO.Guid -ReportType XML -Domain $GPO.DomainName $GPODOmainFolder = [io.path]::Combine($GPOPath, $GPO.DomainName) if (-not (Test-Path -Path $GPODOmainFolder)) { $null = New-Item -ItemType Directory -Path $GPODOmainFolder -Force } $Path = [io.path]::Combine($GPODOmainFolder, "$($GPO.Guid).xml") $XMLContent | Set-Content -LiteralPath $Path -Force -Encoding Unicode } $GPOListPath = [io.path]::Combine($GPOPath, "GPOList.xml") $GPOs | Export-Clixml -Depth 5 -Path $GPOListPath } } function Select-GPOTranslation { [cmdletbInding()] param( [Parameter(ValueFromPipeline)][System.Collections.IDictionary] $InputObject, [string] $Category, [string] $Settings ) $Important = [ordered] @{} $AllProperties = Select-Properties -AllProperties -Objects $InputObject.$Category.$Settings $MissingProperties = $AllProperties | Where-Object { $_ -notin 'DisplayName', 'DomainName', 'GUID', 'Linked', 'LinksCount', 'Links', 'GPOType', 'GPOCategory', 'GPOSettings' } $Types = foreach ($Property in $MissingProperties) { ($InputObject.$Category.$Settings | Where-Object { $null -ne $_.$Property }).$Property | ForEach-Object { ($_ | Get-Member -MemberType Properties) | Where-Object { $_.Name -notin 'Length' } } } $Important['AllProperties'] = $AllProperties $Important['MissingProperties'] = $MissingProperties $Important['Types'] = $Types | Select-Object -Unique $Important['Data'] = $InputObject.$Category.$Settings $Important } function Set-GPOOwner { [cmdletBinding()] param( [validateset('Administrative', 'Default')][string] $Type = 'Default', [string] $Principal ) if ($Type -eq 'Default') { if ($Principal) { @{ Action = 'Owner' Type = 'Default' Principal = $Principal } } } elseif ($Type -eq 'Administrative') { @{ Action = 'Owner' Type = 'Administrative' Principal = '' } } } function Set-GPOZaurrOwner { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Type Unknown - finds unknown Owners and sets them to Administrative (Domain Admins) or chosen principal NotMatching - find administrative groups only and if sysvol and gpo doesn't match - replace with chosen principal or Domain Admins if not specified NotAdministrative - combination of Unknown/NotMatching and NotAdministrative - replace with chosen principal or Domain Admins if not specified All - if Owner is known it checks if it's Administrative, if it sn't it fixes that. If owner is unknown it fixes it .PARAMETER GPOName Parameter description .PARAMETER GPOGuid Parameter description .PARAMETER Forest Parameter description .PARAMETER ExcludeDomains Parameter description .PARAMETER IncludeDomains Parameter description .PARAMETER ExtendedForestInformation Parameter description .PARAMETER Principal Parameter description .PARAMETER SkipSysvol Parameter description .PARAMETER LimitProcessing Parameter description .EXAMPLE An example .NOTES General notes #> [cmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Type')] param( [Parameter(ParameterSetName = 'Type', Mandatory)] [validateset('Unknown', 'NotAdministrative', 'NotMatching', 'All')][string] $Type, [Parameter(ParameterSetName = 'Named')][string] $GPOName, [Parameter(ParameterSetName = 'Named')][alias('GUID', 'GPOID')][string] $GPOGuid, [Parameter(ParameterSetName = 'Type')] [Parameter(ParameterSetName = 'Named')] [alias('ForestName')][string] $Forest, [Parameter(ParameterSetName = 'Type')] [Parameter(ParameterSetName = 'Named')] [string[]] $ExcludeDomains, [Parameter(ParameterSetName = 'Type')] [Parameter(ParameterSetName = 'Named')] [alias('Domain', 'Domains')][string[]] $IncludeDomains, [Parameter(ParameterSetName = 'Type')] [Parameter(ParameterSetName = 'Named')] [System.Collections.IDictionary] $ExtendedForestInformation, [Parameter(ParameterSetName = 'Type')] [Parameter(ParameterSetName = 'Named')] [string] $Principal, [switch] $SkipSysvol, [Parameter(ParameterSetName = 'Type')] [Parameter(ParameterSetName = 'Named')] [int] $LimitProcessing = [int32]::MaxValue ) Begin { #Write-Verbose "Set-GPOZaurrOwner - Getting ADAdministrativeGroups" $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation #Write-Verbose "Set-GPOZaurrOwner - Processing GPO for Type $Type" } Process { $getGPOZaurrOwnerSplat = @{ IncludeSysvol = -not $SkipSysvol.IsPresent Forest = $Forest IncludeDomains = $IncludeDomains ExcludeDomains = $ExcludeDomains ExtendedForestInformation = $ExtendedForestInformation ADAdministrativeGroups = $ADAdministrativeGroups Verbose = $VerbosePreference } if ($GPOName) { $getGPOZaurrOwnerSplat['GPOName'] = $GPOName } elseif ($GPOGuid) { $getGPOZaurrOwnerSplat['GPOGuid'] = $GPOGUiD } Get-GPOZaurrOwner @getGPOZaurrOwnerSplat | Where-Object { if ($_.Owner) { $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($_.Owner)"] } else { $AdministrativeGroup = $null } if (-not $SkipSysvol) { if ($_.SysvolOwner) { $AdministrativeGroupSysvol = $ADAdministrativeGroups['ByNetBIOS']["$($_.SysvolOwner)"] } else { $AdministrativeGroupSysvol = $null } } if ($Type -eq 'NotAdministrative') { if (-not $AdministrativeGroup -or (-not $AdministrativeGroupSysvol -and -not $SkipSysvol)) { $_ } else { if ($AdministrativeGroup -ne $AdministrativeGroupSysvol) { Write-Verbose "Set-GPOZaurrOwner - Detected mismatch GPO: $($_.DisplayName) from domain: $($_.DomainName) - owner $($_.Owner) / sysvol owner $($_.SysvolOwner). Fixing required." $_ } } } elseif ($Type -eq 'Unknown') { if (-not $_.Owner -or (-not $_.SysvolOwner -and -not $SkipSysvol)) { $_ } } elseif ($Type -eq 'NotMatching') { if ($SkipSysvol) { Write-Verbose "Set-GPOZaurrOwner - Detected mismatch GPO: $($_.DisplayName) from domain: $($_.DomainName) - owner $($_.Owner) / sysvol owner $($_.SysvolOwner). SysVol scanning is disabled. Skipping." } else { if ($AdministrativeGroup -ne $AdministrativeGroupSysvol) { #Write-Verbose "Set-GPOZaurrOwner - Detected mismatch GPO: $($_.DisplayName) from domain: $($_.DomainName) - owner $($_.Owner) / sysvol owner $($_.SysvolOwner). Fixing required." $_ } } } else { # we run with no type, that means we need to either set it to principal or to Administrative if ($_.Owner) { # we check if Principal is not set $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($_.Owner)"] if (-not $SkipSysvol -and $_.SysvolOwner) { $AdministrativeGroupSysvol = $ADAdministrativeGroups['ByNetBIOS']["$($_.SysvolOwner)"] if (-not $AdministrativeGroup -or -not $AdministrativeGroupSysvol) { $_ } } else { if (-not $AdministrativeGroup) { $_ } } } else { $_ } } } | Select-Object -First $LimitProcessing | ForEach-Object -Process { $GPO = $_ if (-not $Principal) { $DefaultPrincipal = $ADAdministrativeGroups["$($_.DomainName)"]['DomainAdmins'] } else { $DefaultPrincipal = $Principal } if ($Action -eq 'OnlyGPO') { Write-Verbose "Set-GPOZaurrOwner - Changing GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.Owner) (SID: $($GPO.OwnerSID)) to $DefaultPrincipal" Set-ADACLOwner -ADObject $GPO.DistinguishedName -Principal $DefaultPrincipal -Verbose:$false -WhatIf:$WhatIfPreference } elseif ($Action -eq 'OnlyFileSystem') { if (-not $SkipSysvol) { Write-Verbose "Set-GPOZaurrOwner - Changing Sysvol Owner GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.SysvolOwner) (SID: $($GPO.SysvolSid)) to $DefaultPrincipal" Set-FileOwner -JustPath -Path $GPO.SysvolPath -Owner $DefaultPrincipal -Verbose:$true -WhatIf:$WhatIfPreference } } else { Write-Verbose "Set-GPOZaurrOwner - Changing GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.Owner) (SID: $($GPO.OwnerSID)) to $DefaultPrincipal" Set-ADACLOwner -ADObject $GPO.DistinguishedName -Principal $DefaultPrincipal -Verbose:$false -WhatIf:$WhatIfPreference if (-not $SkipSysvol) { Write-Verbose "Set-GPOZaurrOwner - Changing Sysvol Owner GPO: $($GPO.DisplayName) from domain: $($GPO.DomainName) from owner $($GPO.SysvolOwner) (SID: $($GPO.SysvolSid)) to $DefaultPrincipal" Set-FileOwner -JustPath -Path $GPO.SysvolPath -Owner $DefaultPrincipal -Verbose:$true -WhatIf:$WhatIfPreference } } } } End { } } Export-ModuleMember -Function @('Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrFiles', 'Get-GPOZaurrLegacyFiles', 'Get-GPOZaurrLink', 'Get-GPOZaurrLinkSummary', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrSysvol', 'Get-GPOZaurrWMI', 'Get-WMIFilter', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrPermission', 'New-GPOZaurrWMI', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrOrphanedSysvolFolders', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Select-GPOTranslation', 'Set-GPOOwner', 'Set-GPOZaurrOwner') -Alias @('Find-GPO') |