DSInternals icon indicating copy to clipboard operation
DSInternals copied to clipboard

Test-PasswordQuality - Groups are not returned as object

Open PrzemyslawKlys opened this issue 7 years ago • 2 comments

I'm trying to use Test-PasswordQuality but it seems while output is something like this:

These groups of accounts have the same passwords:
  Group 1:
    adm.pklys
    przemyslaw.klys
  Group 2:
    expiration
    new

When you try to access it like this

$Results = Get-ADReplAccount -All -Server $Server -NamingContext $DomainDN | Test-PasswordQuality -WeakPasswordsFile $DictionaryDatabase1 -IncludeDisabledAccounts
$Results.DuplicatePasswordGroups 

You only get strings of names. I would expect to access groups by using

$Results.DuplicatePasswordGroups.'Group 1' 

or similar. Is there a way to achieve this?

PrzemyslawKlys avatar Oct 01 '18 11:10 PrzemyslawKlys

Good point! I will probably change it to IList. For now, you can either use foreach or $Results.DuplicatePasswordGroups.ToArray()[0].

MichaelGrafnetter avatar Oct 01 '18 12:10 MichaelGrafnetter

Thanks. That works!

PrzemyslawKlys avatar Oct 01 '18 12:10 PrzemyslawKlys

Forgive me here for being a noob. Would I be able to produce information about the users in these groups? For example samaccountname, lastlogondate, etc? For all the other password objects, I've done it like this:

$riskyAccounts = $accounts | Where-Object LogonName -in $results.EmptyPassword $riskyAccounts | Select-Object -Property SamAccountName,DistinguishedName,userPrincipalName,LastLogonTimeStamp,createTimeStamp |Export-Csv "G:\dits\output\Empty-pwd-$name-output.csv" -NoTypeInformation

Thanks, Joe

joejsullivan avatar Apr 03 '23 18:04 joejsullivan

Hi,

@joejsullivan - if you want I wrote it already.

I've created PowerShell module called PasswordSolution (https://github.com/EvotecIT/PasswordSolution). While main part controls the password expiration I also added "reporting" on top of what Test-PasswordQuality offers using DSInternals if you have them installed

As an object:

$Users = Find-PasswordQuality
$Users | Format-Table

As html report:

Show-PasswordQuality -FilePath $PSScriptRoot\Reporting\PasswordQuality.html -Online -WeakPasswords "Test1", "Test2", "Test3" -Verbose

image image image

I actually forgot last logon date, but it should be trivial to add.

I missed this functionality in Michael's module, so I made it all pretty.

Hope it helps.

Przemek

PrzemyslawKlys avatar Apr 03 '23 18:04 PrzemyslawKlys

Thanks, @PrzemyslawKlys . Unfortunately, all of my work must remain offline. I've been given separate hardware to perform. From what it looks like, all the discovery is done online.

But wow.... the output and reporting are phenomenal.

Thanks again, Joe

joejsullivan avatar Apr 03 '23 18:04 joejsullivan

Depends on your definition of offline. It works "online" as in requires Domain Controller that is up and running and then it uses:

 Get-ADReplAccount -All -Server $Server

and then Test-PasswordQuality against that.

If by Online you mean switch you saw in the command is for "HTML" - it's for using CDN JS and CSS which means lower size of generated HTML. But if you skip the Online switch it embedded all required CSS and JS and works well offline. So it can be run on machine without internet that just have DC visibility. It just makes it 3mb more in the final HTML output.

PrzemyslawKlys avatar Apr 03 '23 19:04 PrzemyslawKlys

@PrzemyslawKlys , closer. I don't even have DC visibility. The DIT's have all been dumped and placed on separate, isolated hardware. I'm executing these as:

$accounts = Get-ADDBAccount -DatabasePath $path -BootKey $key -All | Where-Object samaccounttype -like User $results = $accounts |Test-PasswordQuality

joejsullivan avatar Apr 03 '23 20:04 joejsullivan

I see. Adding "offline" mode would be possible, since it's just additional if/else logic. A bit harder would be to get users from AD first, so one would have to allow something like:

  • Get ADForest, Get-ADUser, Save them to XML with the required data, and pass them all to a single command that merges that data. Not really big deal, and that could be used in "offline" mode after that.

PrzemyslawKlys avatar Apr 03 '23 20:04 PrzemyslawKlys

Thanks. I think getting the users as a Get-ADDBAccount should get all the details necessary? No?

Joe

joejsullivan avatar Apr 03 '23 20:04 joejsullivan

I've never used it, so dunno what sort of data it shows up. For me it's easier to get them with Get-ADUser, and merge with Test-PasswordQuality. Maybe if I will have some free time I will play with it and improve my module to work offline like this. But so far haven't had a need.

PrzemyslawKlys avatar Apr 03 '23 20:04 PrzemyslawKlys

Thanks @PrzemyslawKlys. I just took a look at the output of $results.DuplicatePasswordGroups and the output is totally different than any other result. It's been a vey long day for me, I'm somewhat tired.

Thanks for the input today. The first suggestion I had made to complete this was doing it on a new VM that had network access. Was given all the dit's on a laptop instead.

Joe

joejsullivan avatar Apr 03 '23 21:04 joejsullivan

This gets me through it.

I really appreciate you putting up with me today while I worked through it.

 $results.DuplicatePasswordGroups | ForEach-Object { $_.Replace("Remove_the_leading_domain_name\", "") } | ForEach-Object { 
            $newJunk = $_
            $accounts | Where-Object { $_.samaccountname -eq $newJunk } | Select-Object -Property SamAccountName,DistinguishedName,LastLogonTimeStamp | Export-Csv "G:\dits\output\dupe-pwdgrps-$name-output.csv" -NoTypeInformation -Append
               }

joejsullivan avatar Apr 03 '23 21:04 joejsullivan

Btw. don't use where-object. Switch to standard foreach. It will be 10x faster. Maybe if you have small domain it doesn't matter, but for large ones you will get heavy penalty.

PrzemyslawKlys avatar Apr 03 '23 21:04 PrzemyslawKlys

Ha. Thanks for the heads up. Yes - I may take quite a penalty for some of the domains. Some of the good part is, I can let it run overnight. The bad part, I have to let it run overnight and somewhat "monitor" the progress.

Perhaps something like this:

# Get the domain name from the first line of $results.DuplicatePasswordGroups
$domain = ($results.DuplicatePasswordGroups[0] -split '\\')[0]

# Loop through each username in $results.DuplicatePasswordGroups
foreach ($username in $results.DuplicatePasswordGroups) {
    # Remove the domain name from the username
    $newJunk = $username.Replace("$domain\", "")
    
    # Loop through each account in $accounts and find the matching object
    foreach ($account in $accounts) {
        if ($account.samaccountname -eq $newJunk) {
            # Select the desired properties and export to CSV
            Select-Object -InputObject $account -Property SamAccountName,DistinguishedName,LastLogonTimeStamp |
            Export-Csv "G:\dits\output\dupe-pwds-$name-output.csv" -NoTypeInformation -Append
            break # exit the inner foreach loop once a match is found
        }
    }
}

joejsullivan avatar Apr 03 '23 21:04 joejsullivan

If you want it to be really fast you should cache it using hashtable. The inner loop will hit you hard, as for every user you would possible have to go thru a full number of users. WIth hashtable that's just super fast

$domain = ($results.DuplicatePasswordGroups[0] -split '\\')[0]
$CacheAccounts = [ordered] @{}
foreach ($account in $accounts) {
    $CacheAccounts[$account.samaccountname] = $account
}

# Loop through each username in $results.DuplicatePasswordGroups
foreach ($username in $results.DuplicatePasswordGroups) {
    # Remove the domain name from the username
    $newJunk = $username.Replace("$domain\", "")

    # Loop through each account in $accounts and find the matching object
    if ($CacheAccounts[$newJunk]) {
        # Select the desired properties and export to CSV
        Select-Object -InputObject $CacheAccounts[$newJunk] -Property SamAccountName, DistinguishedName, LastLogonTimeStamp |
        Export-Csv "G:\dits\output\dupe-pwds-$name-output.csv" -NoTypeInformation -Append
    }
}

PrzemyslawKlys avatar Apr 04 '23 05:04 PrzemyslawKlys