GPOZaurr.psm1

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)
    if ($Global:ProgressPreference -ne 'SilentlyContinue') {
        $TemporaryProgress = $Global:ProgressPreference
        $Global:ProgressPreference = 'SilentlyContinue'
    }
    $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['QueryServers']['Forest'] = $DC
    $Findings.Domains = foreach ($_ in $ForestInformation.Domains) {
        if ($IncludeDomains) {
            if ($_ -in $IncludeDomains) { $_.ToLower() }
            continue
        }
        if ($_ -notin $ExcludeDomains) { $_.ToLower() }
    }
    $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) {
        try { $DC = Get-ADDomainController -DomainName $Domain -Discover -ErrorAction Stop } catch {
            Write-Warning "Get-WinADForestDetails - Error discovering DC for domain $Domain - $($_.Exception.Message)"
            continue
        }
        $Findings['QueryServers']["$Domain"] = $DC
        [Array] $AllDC = try {
            try { $DomainControllers = Get-ADDomainController -Filter $Filter -Server $DC.HostName[0] -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 -notin $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) { $Findings[$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { $Findings[$Domain] = $AllDC }
        $Findings[$Domain]
    }
    if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress }
    $Findings
}
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 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 Get-XMLGPO {
    [cmdletBinding()]
    param(
        [XML] $XMLContent
    )
    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'
    }

    [PsCustomObject] @{
        'Name'                              = $XMLContent.GPO.Name
        'Domain'                            = $XMLContent.GPO.Identifier.Domain.'#text'
        'GUID'                              = $XMLContent.GPO.Identifier.Identifier.InnerText
        '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

        '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
            }
        }
        'Links'                             = $XMLContent.GPO.LinksTo #| Select-Object -ExpandProperty SOMPath

    }
    #break
}
function Invoke-GPOZaurr {
    [cmdletBinding()]
    param(

    )
}
$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 Get-GPOZaurr {
    [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
        }

        foreach ($Domain in $ForestInformation.Domains) {
            Get-GPO -All -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain | ForEach-Object {
                $XMLContent = Get-GPOReport -ID $_.ID -ReportType XML -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain
                Get-XMLGPO -XMLContent $XMLContent
            }
        }
    } else {
        foreach ($Path in $GPOPath) {
            Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml | ForEach-Object {
                $XMLContent = [XML]::new()
                $XMLContent.Load($_.FullName)
                Get-XMLGPO -XMLContent $XMLContent
            }
        }
    }
}

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
        }

        $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 Save-GPOZaurrFiles {
    [cmdletBinding()]
    param(
        [alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [System.Collections.IDictionary] $ExtendedForestInformation,
        [string[]] $GPOPath
    )
    if ($GPOPath) {
        if (-not $ExtendedForestInformation) {
            $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
        } else {
            $ForestInformation = $ExtendedForestInformation
        }
        $null = New-Item -ItemType Directory -Path $GPOPath -Force
        foreach ($Domain in $ForestInformation.Domains) {
            Get-GPO -All -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain | ForEach-Object {
                $XMLContent = Get-GPOReport -ID $_.ID.Guid -ReportType XML -Server $ForestInformation.QueryServers[$Domain].HostName[0] -Domain $Domain
                $Path = [io.path]::Combine($GPOPath, "$($_.ID.Guid).xml")

                $XMLContent | Set-Content -LiteralPath $Path -Force -Encoding Unicode
            }
        }
    }
}



Export-ModuleMember -Function @('Get-GPOZaurr', 'Get-GPOZaurrPassword', 'Save-GPOZaurrFiles') -Alias @()