What is this?

This knowledgebase contains questions and answers about PRTG Network Monitor and network monitoring in general.

Learn more

PRTG Network Monitor

Intuitive to Use. Easy to manage.
More than 500,000 users rely on Paessler PRTG every day. Find out how you can reduce cost, increase QoS and ease planning, as well.

Free Download

Top Tags


View all Tags

Powershell Custom Sensor for monitoring AD User lockouts

Votes:

1

There is a desire to monitor user lockouts in my organization. This thread offers a script that comes close, but isn't quite what we needed, as it monitors all disabled users.

I've taken that script and adjusted it to only look at non-disabled, non-expired, locked out users. I've decided to post it here in its own thread, because the use case is sufficiently different from the original script. The script is generic and should work in any AD environment. Do keep in mind, though, that the server running the sensor needs to have the Active Directory Powershell module installed.

Import-Module ActiveDirectory

$server=Get-ADUser -Filter * -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {$_.lockedout -eq "True" -and $_.enabled -eq "True" -and (($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -eq $null)))}

if ($server.count -eq $null -and $server -eq $null){
    $a=0
}
Elseif ($server.count -eq $null -and $server -ne $null){
    $a=1
}
Else
{
    $a=@($server.count)
}
Write-Host "<prtg>"
Write-Host "<result>" 
"<channel>Locked Out Users</channel>" 
"<value>"+ $a +"</value>" 
"</result>"
"<text>" + (($server | select SamAccountName,DisplayName,@{n='LockoutTime';e={[DateTime]::FromFileTime($_.lockouttime)}} | sort LockoutTime -descending | ConvertTo-Csv -NoTypeInformation | select -skip 1 ) -join ", ").replace("""","") + "</text>"
Write-Host "</prtg>"

If anyone spots any issues with the script, or has suggestions for optimization, I'm happy to hear them.

active-directory powershell user-accounts

Created on Sep 20, 2017 10:50:02 AM



Best Answer

Accepted Answer

Votes:

4

Tested this - and yes you are right.. the correct line would be:

-LT (less than) and a -AND instead of -OR

resulting in this command:

Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {(($_.AccountExpirationDate -lt (Get-Date) -and ($_.AccountExpirationDate -ne $null)))} 

and here the corrected full script:

Import-Module ActiveDirectory

#you could add - filters, a OU limitation or a server against whom this would be executed.. see Get-ADUser options for more details

#all locked users that aren't disabled or expired
$LockedOutUsers=Get-ADUser -Filter {Enabled -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {$_.lockedout -eq $True -and (($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -eq $null)))} 

#all users that are disabled - this is a manual action in Active Directory
$DisabledUsers=Get-ADUser -Filter {Enabled -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate

#all users that are not disabled but expired already
$ExpiredUsers=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {(($_.AccountExpirationDate -lt (Get-Date) -and ($_.AccountExpirationDate -ne $null)))} 

#users with not expiring passwords and are enabled and not expired
$NotExpiringPWD=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate 

If ($LockedOutUsers.count -eq $null -and $LockedOutUsers -eq $null){
    $cntLockedOutUsers=0
}Elseif ($LockedOutUsers.count -eq $null -and $LockedOutUsers -ne $null){
    $cntLockedOutUsers=1
}Else{
    $cntLockedOutUsers=@($LockedOutUsers.count)
}

If ($DisabledUsers.count -eq $null -and $DisabledUsers -eq $null){
    $cntDisabledUsers=0
}Elseif ($DisabledUsers.count -eq $null -and $DisabledUsers -ne $null){
    $cntDisabledUsers=1
}Else{
    $cntDisabledUsers=@($DisabledUsers.count)
}

If ($ExpiredUsers.count -eq $null -and $ExpiredUsers -eq $null){
    $cntExpiredUsers=0
}Elseif ($ExpiredUsers.count -eq $null -and $ExpiredUsers -ne $null){
    $cntExpiredUsers=1
}Else{
    $cntExpiredUsers=@($ExpiredUsers.count)
}

If ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -eq $null){
    $cntNotExpiringPWD=0
}Elseif ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -ne $null){
    $cntNotExpiringPWD=1
}Else{
    $cntNotExpiringPWD=@($NotExpiringPWD.count)
}

$XML += "<prtg>"
$XML += "<result>" 
$XML += "<channel>Locked Out Users</channel>" 
$XML += "<value>$cntLockedOutUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Disabled Users</channel>" 
$XML += "<value>$cntDisabledUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Expired Users - not disabled</channel>" 
$XML += "<value>$cntExpiredUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Users with password never expires</channel>" 
$XML += "<value>$cntNotExpiringPWD</value>" 
$XML += "</result>"
$XML += "</prtg>"

Function WriteXmlToScreen ([xml]$xml)
{
    $StringWriter = New-Object System.IO.StringWriter;
    $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter;
    $XmlWriter.Formatting = "indented";
    $xml.WriteTo($XmlWriter);
    $XmlWriter.Flush();
    $StringWriter.Flush();
    Write-Output $StringWriter.ToString();
}

WriteXmlToScreen $XML

Thanks for pointing this out - did not realize this mistake...

Regards

Florian Rossmark

www.it-admins.com

Created on Nov 2, 2018 1:48:47 PM



26 Replies

Votes:

0

Hello Bdmm,

Thank you very much for your valuable input, I'm pretty sure that there are users out there who will benefit from your script.

Best regards and thanks again.
Sebastian

Created on Sep 21, 2017 10:33:09 AM by  Sebastian Kniege [Paessler Support]



Votes:

0

Is it possible to monitor user account lockout status where the sensor is running on a different domain ?

Created on Mar 12, 2018 9:06:12 PM



Votes:

0

Tested, works smooth as I have one user locked out and I can see the details in de settings. The counters says 0, so it needs a minor tweak to show 1 ? If users locked out >1, does this sensor show the number of locks, but without the details ??

Created on Mar 16, 2018 4:13:46 PM



Votes:

0

Is it possible to monitor user account lockout status where the sensor is running on a different domain ?

possible yes, but does anybody have a solution to get the Data without the use of a Domain Admin ? Wen don't wan't to use any Domain Admins - instead we use local admins (when necessary and possible)

Created on Apr 17, 2018 2:37:19 PM



Votes:

0

This should actually work with a regular user account - any domain user can gather information like this.

What you might need is the RSAT tools installed on the probe-device, besides that I do not see a reason why you shouldn't be able to execute this as a regular user.

Actually, you would be quite surprised seeing what a regular user account can read from your Active Directory. Please have a look at my free IT-Admins Tool at https://www.it-admins.com - you might be quite astonished.

Having this said - I would re-write the script and do it differently and a bit more extended.

The following script will read through your current Active Directory and filter for user accounts with the following specific conditions:

  • Lockedout users - please read below
    • all users that are lockedout
    • must be an enabled user
    • that is not expired
  • disabled users
    • all users that have been disabled
  • expired users
    • must be an enabled user
    • the expiration date is set and past the current date
  • users with password never expires set
    • must be an enabled user

This will give you a pure counter output per channel in an for PRTG Extended script sensor XML result.

But there is a theoretical flaw in one of the methods - the locked out users. Now, user accounts get locked out in Active Directory due to too many logon attempts with an invalid password. This causes Active Directory to set the lockedout bit in the object properties. The issue here is that this bit will not be set back to 0 after the defined lockout duration (GPO) is past, the property will only be set back to 0 once the lockout duration is passed and he successfully logged on.

This means, the counter might give you more results then currently true, it might count users that have been locked out but the lockout-duration passed - but they did not yet logon successfully. This is somehow a false positive, while not totally false. In any case, you need to be aware of this.

The script could be more efficient as well in the way it filters a few things, so far I optimized it as far as I could - the LockedOut value can not be set as a -Filter, in theory it might be possible to speed it up with a -Filter to the UserAccountControl - but I am not certain this would work. If you really want to speed it up you would need to work with -LDAPFilter - but this actually needs to completely replace the internal filter capabilities of Get-ADUser - you can't use both - it is one or the other.

Import-Module ActiveDirectory

#you could add - filters, a OU limitation or a server against whom this would be executed.. see Get-ADUser options for more details

#all locked users that aren't disabled or expired
$LockedOutUsers=Get-ADUser -Filter {Enabled -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {$_.lockedout -eq $True -and (($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -eq $null)))} 

#all users that are disabled - this is a manual action in Active Directory
$DisabledUsers=Get-ADUser -Filter {Enabled -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate

#all users that are not disabled but expired already
$ExpiredUsers=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {(($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -ne $null)))} 

#users with not expiring passwords and are enabled and not expired
$NotExpiringPWD=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate 

If ($LockedOutUsers.count -eq $null -and $LockedOutUsers -eq $null){
    $cntLockedOutUsers=0
}Elseif ($LockedOutUsers.count -eq $null -and $LockedOutUsers -ne $null){
    $cntLockedOutUsers=1
}Else{
    $cntLockedOutUsers=@($LockedOutUsers.count)
}

If ($DisabledUsers.count -eq $null -and $DisabledUsers -eq $null){
    $cntDisabledUsers=0
}Elseif ($DisabledUsers.count -eq $null -and $DisabledUsers -ne $null){
    $cntDisabledUsers=1
}Else{
    $cntDisabledUsers=@($DisabledUsers.count)
}

If ($ExpiredUsers.count -eq $null -and $ExpiredUsers -eq $null){
    $cntExpiredUsers=0
}Elseif ($ExpiredUsers.count -eq $null -and $ExpiredUsers -ne $null){
    $cntExpiredUsers=1
}Else{
    $cntExpiredUsers=@($ExpiredUsers.count)
}

If ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -eq $null){
    $cntNotExpiringPWD=0
}Elseif ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -ne $null){
    $cntNotExpiringPWD=1
}Else{
    $cntNotExpiringPWD=@($NotExpiringPWD.count)
}

$XML += "<prtg>"
$XML += "<result>" 
$XML += "<channel>Locked Out Users</channel>" 
$XML += "<value>$cntLockedOutUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Disabled Users</channel>" 
$XML += "<value>$cntDisabledUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Expired Users - not disabled</channel>" 
$XML += "<value>$cntExpiredUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Users with password never expires</channel>" 
$XML += "<value>$cntNotExpiringPWD</value>" 
$XML += "</result>"
$XML += "</prtg>"

Function WriteXmlToScreen ([xml]$xml)
{
    $StringWriter = New-Object System.IO.StringWriter;
    $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter;
    $XmlWriter.Formatting = "indented";
    $xml.WriteTo($XmlWriter);
    $XmlWriter.Flush();
    $StringWriter.Flush();
    Write-Output $StringWriter.ToString();
}

WriteXmlToScreen $XML

The above script was as well posted on my blog here.

Regards

Florian Rossmark

www.it-admins.com

Created on Jul 19, 2018 3:36:16 PM



Votes:

1

For correct value display when only 1 account is locked you can replace this :

if ($server.count -eq $null -and $server -eq $null){
    $a=0
}
Elseif ($server.count -eq $null -and $server -ne $null){
    $a=1
}
Else
{
    $a=@($server.count)
}

by this :

$server | ForEach-Object {$a++}

Created on Aug 31, 2018 12:02:12 PM

Last change on Aug 31, 2018 12:53:08 PM by  Sebastian Kniege [Paessler Support]



Votes:

0

Thanks for that script, looking good so far. However, I fear there's an issue with "Expired Users - not disabled". I can imagine this is down to "Get-Date". It also matches users with an expiry date in the future which obviously is wrong. Adding a "-Format "dd.MM.yyyy HH:mm"" also returns the list containing too many users. Any idea?

Created on Nov 2, 2018 9:27:59 AM



Accepted Answer

Votes:

4

Tested this - and yes you are right.. the correct line would be:

-LT (less than) and a -AND instead of -OR

resulting in this command:

Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {(($_.AccountExpirationDate -lt (Get-Date) -and ($_.AccountExpirationDate -ne $null)))} 

and here the corrected full script:

Import-Module ActiveDirectory

#you could add - filters, a OU limitation or a server against whom this would be executed.. see Get-ADUser options for more details

#all locked users that aren't disabled or expired
$LockedOutUsers=Get-ADUser -Filter {Enabled -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {$_.lockedout -eq $True -and (($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -eq $null)))} 

#all users that are disabled - this is a manual action in Active Directory
$DisabledUsers=Get-ADUser -Filter {Enabled -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate

#all users that are not disabled but expired already
$ExpiredUsers=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {(($_.AccountExpirationDate -lt (Get-Date) -and ($_.AccountExpirationDate -ne $null)))} 

#users with not expiring passwords and are enabled and not expired
$NotExpiringPWD=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate 

If ($LockedOutUsers.count -eq $null -and $LockedOutUsers -eq $null){
    $cntLockedOutUsers=0
}Elseif ($LockedOutUsers.count -eq $null -and $LockedOutUsers -ne $null){
    $cntLockedOutUsers=1
}Else{
    $cntLockedOutUsers=@($LockedOutUsers.count)
}

If ($DisabledUsers.count -eq $null -and $DisabledUsers -eq $null){
    $cntDisabledUsers=0
}Elseif ($DisabledUsers.count -eq $null -and $DisabledUsers -ne $null){
    $cntDisabledUsers=1
}Else{
    $cntDisabledUsers=@($DisabledUsers.count)
}

If ($ExpiredUsers.count -eq $null -and $ExpiredUsers -eq $null){
    $cntExpiredUsers=0
}Elseif ($ExpiredUsers.count -eq $null -and $ExpiredUsers -ne $null){
    $cntExpiredUsers=1
}Else{
    $cntExpiredUsers=@($ExpiredUsers.count)
}

If ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -eq $null){
    $cntNotExpiringPWD=0
}Elseif ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -ne $null){
    $cntNotExpiringPWD=1
}Else{
    $cntNotExpiringPWD=@($NotExpiringPWD.count)
}

$XML += "<prtg>"
$XML += "<result>" 
$XML += "<channel>Locked Out Users</channel>" 
$XML += "<value>$cntLockedOutUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Disabled Users</channel>" 
$XML += "<value>$cntDisabledUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Expired Users - not disabled</channel>" 
$XML += "<value>$cntExpiredUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Users with password never expires</channel>" 
$XML += "<value>$cntNotExpiringPWD</value>" 
$XML += "</result>"
$XML += "</prtg>"

Function WriteXmlToScreen ([xml]$xml)
{
    $StringWriter = New-Object System.IO.StringWriter;
    $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter;
    $XmlWriter.Formatting = "indented";
    $xml.WriteTo($XmlWriter);
    $XmlWriter.Flush();
    $StringWriter.Flush();
    Write-Output $StringWriter.ToString();
}

WriteXmlToScreen $XML

Thanks for pointing this out - did not realize this mistake...

Regards

Florian Rossmark

www.it-admins.com

Created on Nov 2, 2018 1:48:47 PM



Votes:

0

You're welcome :)

Always happy to give back. Thanks a bunch to you for coming up with that. Saved time to self-develop.

Created on Nov 2, 2018 1:57:52 PM



Votes:

0

Hi, where and how can I set a specific OU? I locked out one user for a test but the script shows 0 locked out users. I think the script is looking in the wrong OU.

Created on Nov 12, 2018 10:08:37 AM



Votes:

0

Script doesn't cehck for a specific OU.

Bear in mind that lock out status needs to be synced between DCs so at the point of time you ran the script, it might either be not synced yet or account may have already unlock again, depending on your domain settings.

Created on Nov 12, 2018 10:15:26 AM



Votes:

0

Hi,

the output of this script showed many (really many) users for the channel "Users with password never expires". I thought that this could not be true. Having a closer look at the script I saw this:

#users with not expiring passwords and are enabled and not expired
$NotExpiringPWD=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate

Shouldn't it be PasswordNeverExpires -eq $True ?

Created on Feb 7, 2019 12:58:26 PM



Votes:

2

Good catch... it is a while that I played around with that script.. interestingly no one ever complained, lol...

You can easily run those commands manually and compare the output to Active Directory manually..

In theory there is more that should be adjusted here... cause the $ExpiredUsers filters for Password never expires $false as well.. so this would be a more updated version of the script

Additionally I added a few notes about how to filter OUs and execute it on a specific server.. in theory the whole script could be changed so it accepts parameter and does everything more variable.. but that's for another day..

Import-Module ActiveDirectory

#you could add - filters, a OU limitation or a server against whom this would be executed.. see Get-ADUser options for more details
#$Server = ""
#$OU = ""
#Get-ADUser -Server $Server -Filter
#Get-ADUser -SearchBase $OU -Filter

#all locked users that aren't disabled or expired
$LockedOutUsers=Get-ADUser -Filter {Enabled -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {$_.lockedout -eq $True -and (($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -eq $null)))} 

#all users that are disabled - this is a manual action in Active Directory
$DisabledUsers=Get-ADUser -Filter {Enabled -eq $False -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate

#all users that are not disabled but expired already
$ExpiredUsers=Get-ADUser -Filter {Enabled -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {(($_.AccountExpirationDate -lt (Get-Date) -and ($_.AccountExpirationDate -ne $null)))} 

#users with not expiring passwords and are enabled and not expired
$NotExpiringPWD=Get-ADUser -Filter {Enabled -eq $True -and PasswordNeverExpires -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate 


If ($LockedOutUsers.count -eq $null -and $LockedOutUsers -eq $null){
    $cntLockedOutUsers=0
}Elseif ($LockedOutUsers.count -eq $null -and $LockedOutUsers -ne $null){
    $cntLockedOutUsers=1
}Else{
    $cntLockedOutUsers=@($LockedOutUsers.count)
}

If ($DisabledUsers.count -eq $null -and $DisabledUsers -eq $null){
    $cntDisabledUsers=0
}Elseif ($DisabledUsers.count -eq $null -and $DisabledUsers -ne $null){
    $cntDisabledUsers=1
}Else{
    $cntDisabledUsers=@($DisabledUsers.count)
}

If ($ExpiredUsers.count -eq $null -and $ExpiredUsers -eq $null){
    $cntExpiredUsers=0
}Elseif ($ExpiredUsers.count -eq $null -and $ExpiredUsers -ne $null){
    $cntExpiredUsers=1
}Else{
    $cntExpiredUsers=@($ExpiredUsers.count)
}

If ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -eq $null){
    $cntNotExpiringPWD=0
}Elseif ($NotExpiringPWD.count -eq $null -and $NotExpiringPWD -ne $null){
    $cntNotExpiringPWD=1
}Else{
    $cntNotExpiringPWD=@($NotExpiringPWD.count)
}

$XML += "<prtg>"
$XML += "<result>" 
$XML += "<channel>Locked Out Users</channel>" 
$XML += "<value>$cntLockedOutUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Disabled Users</channel>" 
$XML += "<value>$cntDisabledUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Expired Users - not disabled</channel>" 
$XML += "<value>$cntExpiredUsers</value>" 
$XML += "</result>"
$XML += "<result>" 
$XML += "<channel>Users with password never expires</channel>" 
$XML += "<value>$cntNotExpiringPWD</value>" 
$XML += "</result>"
$XML += "</prtg>"

Function WriteXmlToScreen ([xml]$xml)
{
    $StringWriter = New-Object System.IO.StringWriter;
    $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter;
    $XmlWriter.Formatting = "indented";
    $xml.WriteTo($XmlWriter);
    $XmlWriter.Flush();
    $StringWriter.Flush();
    Write-Output $StringWriter.ToString();
}

WriteXmlToScreen $XML

Created on Feb 7, 2019 2:49:06 PM



Votes:

0

Hi,

I am trying to use the above script (PRTG v.18.4.46.1754) but i'm getting the below error:

XML: The returned XML does not match the expected schema. (code: PE233) -- JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231)

Any ideas?

Created on Feb 12, 2019 9:38:34 PM



Votes:

0

Dear lzsembera,

in order to debug this, please open the Settings tab of the sensor and enable "Write Exe result to disk".

After the next scans, the logs appear in "C:\ProgramData\Paessler\PRTG Network Monitor\Logs (Sensors)".

If you look at the Powershell output included in the log, do you see the cause of the script execution error?

Created on Feb 12, 2019 10:58:16 PM by  Arne Seifert [Paessler Support]



Votes:

0

Hi I have implemented this script, but even in a Powershell ISE session it errors when it comes to writing out the results:-

WriteXmlToScreen : Cannot process argument transformation on parameter 'xml'. Cannot convert value "<prtg><result><channel>Locked Out Users</channel><value>0</value></result><result><channel>Disabled Users</channel><value>0</value></result><result><channel>Expired Users - not disabled</channel><value>0</value></result><result><channel>Users with password never expires</channel><value>0</value></result></prtg><prtg><result><channel>Locked Out Users</channel><value>0</value></result><result><channel>Disabled Users</channel><value>558</value></result><result><channel>Expired Users - not disabled</channel><value>3</value></result><result><channel>Users with password never expires</channel><value>408</value></result></prtg><prtg><result><channel>Locked Out Users</channel><value>0</value></result><result><channel>Disabled Users</channel><value>558</value></result><result><channel>Expired Users - not disabled</channel><value>3</value></result><result><channel>Users with password never expires</channel><value>408</value></result></prtg><prtg><result><channel>Locked Out Users</channel><value>0</value></result><result><channel>Disabled Users</channel><value>558</value></result><result><channel>Expired Users - not disabled</channel><value>3</value></result><result><channel>Users with password never expires</channel><value>408</value></result></prtg>" to type "System.Xml.XmlDocument". Error: "This document already has a 'DocumentElement' node." At line:84 char:18 + WriteXmlToScreen $XML + ~~~~ + CategoryInfo : InvalidData: (:) [WriteXmlToScreen], ParameterBindingArgumentTransformationException + FullyQualifiedErrorId : ParameterArgumentTransformationError,WriteXmlToScreen

Any guidance?

Created on Feb 19, 2019 4:07:42 PM

Last change on Feb 20, 2019 5:19:22 AM by  Sven Roggenhofer [Paessler Technical Support]



Votes:

0

Hi Ian,

The XML data posted from you looks like this:

<prtg>
<result><channel>Locked Out Users</channel><value>0</value></result>
<result><channel>Disabled Users</channel><value>0</value></result>
<result><channel>Expired Users - not disabled</channel><value>0</value></result>
<result><channel>Users with password never expires</channel><value>0</value></result>
</prtg>

<prtg>
<result><channel>Locked Out Users</channel><value>0</value></result>
<result><channel>Disabled Users</channel><value>558</value></result>
<result><channel>Expired Users - not disabled</channel><value>3</value></result>
<result><channel>Users with password never expires</channel><value>408</value></result>
</prtg>

<prtg>
<result><channel>Locked Out Users</channel><value>0</value></result>
<result><channel>Disabled Users</channel><value>558</value></result>
<result><channel>Expired Users - not disabled</channel><value>3</value></result>
<result><channel>Users with password never expires</channel><value>408</value></result>
</prtg>

<prtg>
<result><channel>Locked Out Users</channel><value>0</value></result>
<result><channel>Disabled Users</channel><value>558</value></result>
<result><channel>Expired Users - not disabled</channel><value>3</value></result>
<result><channel>Users with password never expires</channel><value>408</value></result>
</prtg>

Did you modify the script? I don't see any reason that the output would a) put in to the $XML value 4x times nor that you would have all 0s in the first XML Element group...

Florian

Created on Feb 20, 2019 2:53:46 PM



Votes:

0

Forgive my ignorance, how do i install this?

Created on Apr 9, 2019 10:46:54 AM



Votes:

0

Copy the script to EXEXML folder, restart Probe/Core then you can select it for custom script monitoring

Created on Apr 9, 2019 10:51:37 AM



Votes:

0

Correct count of locked users is:

#If ($LockedOutUsers.count -eq $null -and $LockedOutUsers -eq $null){
#    $cntLockedOutUsers=0
#}Elseif ($LockedOutUsers.count -eq $null -and $LockedOutUsers -ne $null){
#       $cntLockedOutUsers=1
#}Else{
#    $cntLockedOutUsers=@($LockedOutUsers.count)
#}
$cntLockedOutUsers=@(Get-ADUser -Filter {Enabled -eq $True -and objectCategory -eq "person" -and objectClass -eq "user"} -Properties sAMAccountName,DisplayName,LockedOut,LockoutTime,Enabled,AccountExpirationDate | where {$_.lockedout -eq $True -and (($_.AccountExpirationDate -gt (Get-Date) -or ($_.AccountExpirationDate -eq $null)))}).count

Add before line:

$XML += "</prtg>"

this line:

$XML += "<text>$LockedOutUsers</text>"

to display locked users name in "Last Message"

Created on Apr 30, 2019 12:56:33 PM

Last change on Apr 30, 2019 3:38:50 PM by  Arne Seifert [Paessler Support]



Votes:

0

Is there a way to set alerts based on the status? For instance, if the sensor reports a locked out user - it will send an alert or notification? If so, how do I do that?

Thanks!

Created on Sep 3, 2020 6:24:44 PM



Votes:

1

Hello,

indeed, you can use PRTG's alerting to perform actions on specific statuses.

Created on Sep 4, 2020 11:42:35 AM by  Arne Seifert [Paessler Support]



Votes:

0

Hi, guys! Is it possible to set alert sent out every time when someone is locked? I play with Notification Triggers settings and no luck so far. I am new to PRTG and just hoping to get some guidance. Thank you!

Created on Oct 5, 2020 12:04:17 PM



Votes:

0

Hello,

the closest thing would be the Change Trigger.

However that one registers changes of the sensor value which in this case could stay the same even if a new user is logged out (since another user could be no longer locked out then).

Created on Oct 5, 2020 4:47:25 PM by  Arne Seifert [Paessler Support]



Votes:

0

Hi,

I'm new to PRTG and have imported the script, which does alert when accounts are locked, which is great. However I also get the following message:

Response not well-formed: "(<prtg> <result> <channel>Locked Out Users</channel> <value>0</value> </result> <text></text> </prtg> )" (code: PE132)

This is either wrapped around the locked users or when no accounts are locked it just looks like above. Is there any way to get rid of this message?

Created on Jul 28, 2021 8:56:30 AM

Last change on Jul 28, 2021 12:30:05 PM by  Felix Wiesneth [Paessler Support]



Votes:

0

Hello,

in this case, please check if you use the Exe/Script Advanced sensor (not the non-advanced version).

Created on Aug 3, 2021 12:24:07 PM by  Arne Seifert [Paessler Support]




Disclaimer: The information in the Paessler Knowledge Base comes without warranty of any kind. Use at your own risk. Before applying any instructions please exercise proper system administrator housekeeping. You must make sure that a proper backup of all your data is available.