FN-GM Posted January 29, 2012 Posted January 29, 2012 Hi, I have found a very handy powershell script to disable inactive user accounts. It works just how i want it apart from one thing. When an account is disabled its supposed to put in the description "Account Disabled on for Inactivity". But there its supposed to put the date its failing and just leaving a white space. Can anyone help please? Thanks ### User Variables ### # Query Options # $searchRoot = "domain.local/" # Where to begin your recursive search - If you use top-level (e.g. "domain.local/") make sure to have a trailing slash, otherwise do not use a slash (e.g. "domain.local/Users") $inactiveDays = 90 # Integer for number of days of inactivity (e.q. 90) $timeSinceCreation = 30 # Integer for number of "grace" days since the account was created (to prevent disabling of brand new accounts) $sizeLimit = 0 # How many users do you want returned. 0 = unlimited. Without setting this the default is 1000 # Email Settings # $emailAlerts = 1 # Turn e-mail alerts on or off. 0 = off $fromAddr = "[email protected]" # Enter the FROM address for the e-mail alert $toAddr = "[email protected]" # Enter the TO address for the e-mail alert $smtpsrv = "192.168.1.1" # Enter the FQDN or IP of a SMTP relay # Enable Script # $enableAction = 1 # Change to 0 if you want to "whatif" this script - It will bypass the actual account disabling (turn e-mail alerts on!) ###################### Add-PSSnapin "Quest.ActiveRoles.ADManagement" $creationCutoff = (Get-Date).AddDays(-$timeSinceCreation) $inactiveUsers = @(Get-QADUser -SearchRoot $searchRoot -Enabled -NotLoggedOnFor $inactiveDays -CreatedBefore $creationCutoff -SizeLimit $sizeLimit | Select-Object Name,SamAccountName,LastLogonTimeStamp,Description | Sort-Object Name) ### Disable Accounts ### if ($enableAction -eq 1 -and $inactiveUsers -ne $null){ foreach($user in $inactiveUsers){ Set-QADUser $user.SamAccountName -Description "Account Disabled on $date for Inactivity - $($user.Description)" | Disable-QADUser } } ###### ### Email Alerts ### if ($emailAlerts -eq 1 -and $inactiveUsers -ne $null){ $date = Get-Date -DisplayHint Date $body = @(" NameAccountLast Login") $i = 0 do { if($i % 2){$body += "$($inactiveUsers[$i].Name)$($inactiveUsers[$i].SamAccountName)$($inactiveUsers[$i].LastLogonTimestamp)";$i++} else {$body += "$($inactiveUsers[$i].Name)$($inactiveUsers[$i].SamAccountName)$($inactiveUsers[$i].LastLogonTimestamp)";$i++} } while ($inactiveUsers[$i] -ne $null) $body += "" Send-MailMessage -To $toAddr -From $fromAddr -Subject "Info: $($inactiveUsers.Count) User Accounts Disabled on $date" -Body "$body" -SmtpServer $smtpsrv -BodyAsHtml } ###### exit
vikpaw Posted January 29, 2012 Posted January 29, 2012 I'm no powershell expert, so don't know exactly how it all works but try moving the "$date = ..." line higher up, preferably above the active code, so you could put it at the bottom of all the user variables. That way it will be populated before it's used. 1
FN-GM Posted January 29, 2012 Author Posted January 29, 2012 (edited) your are correct thats fixed it. One thing is that is shows the exact time as well. It really inst needed do you happen to know how to get it to display only the date? Also It show the date in American format, do you know how to switch it to the British way please? Thanks Edited January 29, 2012 by FN-GM
Iain Posted January 29, 2012 Posted January 29, 2012 your are correct thats fixed it. One thing is that is shows the exact time as well. It really inst needed do you happen to know how to get it to display only the date? Also It show the date in American format, do you know how to switch it to the British way please? Thanks You can use the -format switch on the Get-Date cmdlet to format the output. e.g. Get-Date -format "d/M/yyyy" For details of the format specifiers for Get-Date, take a look here: Windows PowerShell Tip: Formatting Dates and Times Iain. 1
FN-GM Posted January 29, 2012 Author Posted January 29, 2012 Thanks perfect. I ageing to post the finished code on the blogs. Thanks guys
Arthur Posted January 29, 2012 Posted January 29, 2012 how to switch it to the British way please? A bit late, but here are a few more examples... 29-01-2012 [DateTime]::Now.ToString("dd-MM-yyyy") 29/01/2012 [DateTime]::Now.ToShortDateString() For details of the format specifiers for Get-Date, take a look here: Windows PowerShell Tip: Formatting Dates and Times To quickly see what all of the date/time letters from that link do, try running this... ForEach ($format in "d","D","f","F","g","G","m","r","s","t","T", "u","U","y","dddd, MMMM dd yyyy","M/yy","dd-MM-yy") { "$format`: {0}" -f (Get-Date).ToString($format) } This is what you should get... d: 29/01/2012 D: 29 January 2012 f: 29 January 2012 09:15 F: 29 January 2012 09:15:56 g: 29/01/2012 09:15 G: 29/01/2012 09:15:56 m: 29 January r: Sun, 29 Jan 2012 09:15:56 GMT s: 2012-01-29T09:15:56 t: 09:15 T: 09:15:56 u: 2012-01-29 09:15:56Z U: 29 January 2012 09:15:56 y: January 2012 dddd, MMMM dd yyyy: Sunday, January 29 2012 M/yy: 1/12 dd-MM-yy: 29-01-12 Then simply replace the letter after the colon with whichever one you want from the list above... "{0:[color="#FF0000"]g[/color]}" -f (Get-Date)
Arthur Posted January 29, 2012 Posted January 29, 2012 (edited) I forgot to mention one of the best tips I have found so far regarding the date. As you may know, once a variable has been calculated, it doesn't change from that point on. Therefore, if you get the current date and time at the beginning of your script, it will have changed by the time you actually go to use it in another cmdlet further on. If you would like to re-calculate the $date variable every single time it is used, try this instead... $global:date = Set-PSBreakpoint -Variable date -Mode Read -Action { $global:date = "{0:F}" -f (Get-Date) } http://i.imgur.com/8tHsz.png Edited January 29, 2012 by Arthur 2
FN-GM Posted January 29, 2012 Author Posted January 29, 2012 Thanks for the input. What would i need to do with the script I posted to make this now do the same for computer accounts please? Thanks
Arthur Posted January 29, 2012 Posted January 29, 2012 This ought to do it... Get-QADComputer -IncludeAllProperties | Where-Object { $_.lastlogon -lt (Get-Date).AddDays(-90) } | Disable-QADComputer
FN-GM Posted January 29, 2012 Author Posted January 29, 2012 Thanks. I had seen that, but the one here does exactly what I want. It will add a note on the account, I can drill down to a particular ou and get it to email me a report. That's why I want to try and convert this one :-) Thanks
PiqueABoo Posted January 29, 2012 Posted January 29, 2012 I take it you read my pedantic comments in your related thread?? Not a huge deal but nevertheless something you should be aware of when doing anything based on when a user/computer last logged on, especially if it's a scheduled task that makes changes based on the result. -- More broadly: Perhaps it's just what turns up at the top of Google searches but I don't get why QAD keeps getting used for things like this rather than the out-of-box MS ActiveDirectory module on 2008 R2. Then again I get around a bit, so regardless of which might be easiest I will always pick tech that will be there are opposed to tech that might need installing. It's just as easy with MS in this case with their Get-ADUser or alternatively there is Search-ADAccount that can pull out inactive computer/user accounts based on a fixed date or timespan e.g. 90 days, that could then be thrown at Disable- or (don't do it!) Remove- cmdlets.
FN-GM Posted January 29, 2012 Author Posted January 29, 2012 I take it you read my pedantic comments in your related thread?? Not a huge deal but nevertheless something you should be aware of when doing anything based on when a user/computer last logged on, especially if it's a scheduled task that makes changes based on the result. I have got this in my mind. I have read a few posts on the net that say you can increase the replication rate of this. Unless i can adapt the script to look at all DC's? More broadly: Perhaps it's just what turns up at the top of Google searches but I don't get why QAD keeps getting used for things like this rather than the out-of-box MS ActiveDirectory module on 2008 R2. Then again I get around a bit, so regardless of which might be easiest I will always pick tech that will be there are opposed to tech that might need installing. It's just as easy with MS in this case with their Get-ADUser or alternatively there is Search-ADAccount that can pull out inactive computer/user accounts based on a fixed date or timespan e.g. 90 days, that could then be thrown at Disable- or (don't do it!) Remove- cmdlets. Sorry i dont understand you, please can you elaborate? Thanks
FN-GM Posted January 29, 2012 Author Posted January 29, 2012 I take it you read my pedantic comments in your related thread?? Not a huge deal but nevertheless something you should be aware of when doing anything based on when a user/computer last logged on, especially if it's a scheduled task that makes changes based on the result. Looking at this page the lastLogontimeStamp attribute is replicated to all DC's in real time. My script uses this time stamp (i think). The lastLogon attribute that i think your talking about replicates every 9 - 14 days. So i should be safe. Do you agree? Thanks
PiqueABoo Posted January 30, 2012 Posted January 30, 2012 Look again... - lastLogon gets updated every time on the DC where the logon happens but that doesn't replicate. - lastLogonTimestamp only gets updated when the a logon happens if the current value is more than 9-14 days old. If it is changed that new value does replicate. Your script uses lastLogonTimestamp and a 90 day timespan thus risks picking up some users who in the worst case, last logged on 76 days ago. They're still old and for this kind of thing it's not often an issue.. if you want to guarantee "at least 90 days old" then just use a 104 day timespan instead of 90. OTOH if you're running this daily and must get accounts as soon as they hit 90 days old you will need to look at lastLogon on all the DCs and check the age of the freshest one.
FN-GM Posted January 30, 2012 Author Posted January 30, 2012 (edited) I think I get you, so what would you suggest please? Thanks Edited January 30, 2012 by FN-GM
PiqueABoo Posted January 30, 2012 Posted January 30, 2012 Depends on what you want to do. Whenever I've set about finding old users or computers I haven't cared about precision, so I'd be happy to use LastLogonTimestamps more than say 100 days old and not worry if that sometimes gets a few accounts that actually last logged on 84-100 days ago coz they're old too. Chasing round for the freshest LastLogon is the kind of thing I'd do if I wanted to know if someone (or a computer) logged on recently e.g. this morning, yesterday etc., 1
FN-GM Posted January 30, 2012 Author Posted January 30, 2012 Would you know how to make the script chase around please? I assume it would be allot of work? I may Google to see if there is a way to increase the replication period or if there is a way to force the attribute to replicate then run the script. What are your thoughts please? Thanks for your help.
FN-GM Posted January 31, 2012 Author Posted January 31, 2012 Can you just confirm i have got something correct. When the users logs on, it will check the DC to see if the timestamp is older than 14 days. If it is older than 14 days it updates it with a new one. If it is under 14 it ignores it. Because of this you wont end up with this scenario: On July 2, the script disables account_A. On July 4, the admin enables the account so that account_A can log in. On July 9, the script runs again and the account is disabled again. Thanks
Arthur Posted January 31, 2012 Posted January 31, 2012 I may Google to see if there is a way to increase the replication period or if there is a way to force the attribute to replicate then run the script. Have you seen this? “The LastLogonTimeStamp Attribute” – “What it was designed for and how it works” « Ask the Directory Services Team If you need more accuracy, you could query the event logs... It is important to note that the intended purpose of the lastLogontimeStamp attribute to help identify inactive computer and user accounts. The lastLogon attribute is not designed to provide real time logon information. With default settings in place the lastLogontimeStamp will be 9-14 days behind the current date. If you are looking for more “real-time” logon tracking you will need to query the Security Event log on your DC’s for the desired logon events i.e. 528 –Windows XP/2003 and earlier or 4624 Windows Vista/2008. See this blog post by Eric Fitzgerald for more info. (I think he knows something about auditing) IMO your best bet for near real-time data is to use an event log collection service to gather all domain controller security event logs to a centralized database. You can then query a single database for the desired logon events. Microsoft’s solution for security event log collection is Audit Collection Services. There are many 3rd party solutions as well.
FN-GM Posted January 31, 2012 Author Posted January 31, 2012 I have read it thanks. I think i am going to reduce the time on the attribute to 7 days. Thanks
FN-GM Posted February 5, 2012 Author Posted February 5, 2012 Thanks for the input. What would i need to do with the script I posted to make this now do the same for computer accounts please? Thanks Does anyone have any suggestions regarding this please? Thanks
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now