Converting LastLogon to DateTime format - powershell

My objective is to get a list of users from my domain with the following info:
-Display name
-Country
-Manager Name
-Last login date
I am running the following script, and everything looks good except for the LastLogon. It outputs the time into a bunch of random numbers like "129948127853609000". How can I convert this to DateTime format?
Search-ADAccount -UsersOnly -SearchBase "OU=International,DC=mycompany,DC=com" -AccountDisabled:$false | Get-ADUser -Properties Name, manager, LastLogon | Select Name, manager, LastLogon | export-csv C:\Australia.csv -NoTypeInformation

DateTime.FromFileTime should do the trick:
PS C:\> [datetime]::FromFileTime(129948127853609000)
Monday, October 15, 2012 3:13:05 PM
Then depending on how you want to format it, check out standard and custom datetime format strings.
PS C:\> [datetime]::FromFileTime(129948127853609000).ToString('d MMMM')
15 October
PS C:\> [datetime]::FromFileTime(129948127853609000).ToString('g')
10/15/2012 3:13 PM
If you want to integrate this into your one-liner, change your select statement to this:
... | Select Name, manager, #{N='LastLogon'; E={[DateTime]::FromFileTime($_.LastLogon)}} | ...

Get-ADUser -Filter {Enabled -eq $true} -Properties Name,Manager,LastLogon |
Select-Object Name,Manager,#{n='LastLogon';e={[DateTime]::FromFileTime($_.LastLogon)}}

LastLogon is the last time that the user logged into whichever domain controller you happen to have been load balanced to at the moment that you ran the GET-ADUser cmdlet, and is not replicated across the domain. You really should use LastLogonTimestamp if you want the time the last user logged in to any domain controller in your domain.

Use the LastLogonDate property and you won't have to convert the date/time.
lastLogonTimestamp should equal to LastLogonDate when converted.
This way, you will get the last logon date and time across the domain without needing to convert the result.

It is important to know that LastLogonDate is not replicated. LastLogonTimestamp is so it is important that you use timestamp on large domains

While lastlogon is not replicated, lastlogontimestamp is. lastlogontimstamp is not human readable (milliseconds since windows epoch)
Here is a one liner that ACTUALLY solves it without querying every server.
get-adcomputer -filter 'operatingsystem -like "server" -and enabled -eq "true"' -prop lastlogontimestamp|select name, lastlogontimestamp, #{N='LastLogon'; E={[DateTime]::FromFileTime($_.LastLogontimestamp)}}

Related

Unable to get AD users/mailboxes created within a certain number of days using Powershell

Good morning. As the title states, the company I work for has a requirement to get a list of user accounts and mailboxes that were created over the last 30 days.
I am using the following Powershell script to achieve this, but I am NOT getting any results returned.
$lastday = ((Get-Date).AddDays(-30))
Get-ADUser -filter {(whencreated -ge $lastday)}
Any help in this regard would be appreciated.
That code should work just fine, but for the sake of readability i would remove the extra () in both lines.
You'll also want to add -properties whencreated so you can actually see the date of creation.
$lastday = (Get-Date).AddDays(-30)
Get-ADUser -filter {whencreated -ge $lastday} -properties whencreated
If you're not getting results that's because there's no users created in the past 30 days.
This is what you want:
$lastday = ((Get-Date).AddDays(-30))
Get-ADUser -Filter * -Properties whencreated | Where-Object {$_.whencreated -ge $lastday}
If you don't get any results it means no AD user where crated in that period, or someone has deleted them.

AD GUI shows properties that PowerShell returns empty

I want to get a list of all AD Users and their creation time and last logon time. First I used the Active Diretory Users and Computers app and activated the Advanced Features. In the Attribute Editor I can see the properties are called LastLogon and WhenCreated.
So I did this:
$allUsers = Get-ADUser -Filter * -Properties SamAccountName,LastLogon,WhenCreated
$allUsers | select SamAccountName,LastLogon,WhenCreated
However LastLogonand WhenCreated are only filled for 13 of 500 Users. In the Attribute Editor these values are filled for a lot more...
When I query one user only that has these values in the Attribute Editor with Get-ADUser -Identity $User -Properties * I see that the attributes are called LastLogonDateand Created (values are shown empty).
So I searched for those attributes:
$allUsers2= Get-ADUser -Filter * -Properties SamAccountName,LastLogonDate,Created
$allUsers2 | select SamAccountName,LastLogonDate,Created
Then again those 13 have the info the rest doesn't.
Has anyone an idea how I get those values? (I am going to export them with Export-CSV so another way to get those in Excel is ok, too )
As requested my comments as answer.
First attempt:
Add the -Server switch on Get-ADUser and have it query the same Domain Controller you are currently connected to with Active Directory Users and Computers. It may be that you are asking for properties that have not yet been synchronized (especially the lastLogon time stamp which I believe is synced only once every 14 days unless you have specified a different value for the ms-DS-Logon-Time-Sync-Interval attribute on the domain default naming context.)
--> didn't apply because you're running this on the DC itself
Second attempt:
Try ADSI as in $searcher = [adsisearcher]'(&(objectCategory=person)(objectClass=user))'; $searcher.FindAll()
--> same results as with Get-ADUser; still empty values
Third attempt:
Check PowerShell version(s)
--> apparently the DC had PS version 4. With version 5.1 it works
First, look at what properties your cmdlet has:
$a = Get-ADUser -server 'DomenNameTest.en' -Identity 'makarovayu' -Properties *
$a | Get-Member
I recommend copying the received data into a notepad in order to copy the available field names later.
2-Let's declare an array and use the cmdlet to try to collect information on the required fields
$userList = Get-ADUser -server 'DomenNameTest.en' -Properties SamAccountName,Name -Filter * |
#Do not forget that the comanlet has a limitation and can fall off on timeout.See how I work with each property in [select]
Select #{Name = "SamAccountName"; Expression={$_.SamAccountName}},#{Name = "Name"; Expression={$_.Name}} |
#Uploading data to [csv]
Export-Csv -Path "D:\Users\userTest\Desktop\userList.csv" -Append -NoTypeInformation -Encoding Default -Delimiter ';'
Remove-Variable a,userList #Clear the variables

Subtraction between two dates in Powershell is evaluating to null

I am using the following code to display some values , the subtraction between two dates as in the expression
[datetime]::Now.AddDays(-365) - $_.PasswordLastSet).Days
is evaluating to null in my data, what could be the reason, how to fix this code ?
Get-ADUser -Filter * -Properties PasswordLastSet, Mail -SearchBase $searchBase |
Where-Object{
([datetime]::Now.AddDays(-365) - $_.PasswordLastSet).Days -in #(" ",364, 350, 354, 340, 335,' ','',"")
}|
Select-Object name, PasswordLastSet,#{n='DaysUntilExpired';e={(([datetime]::Now.AddDays(365) - [datetime]::$_.PasswordLastSet).Day).days}} |
Add-Content -Path C:\Temp\PasswordExpList.txt
There are two obvious bugs in your code, both here:
#{n='DaysUntilExpired';e={(([datetime]::Now.AddDays(365) - [datetime]::$_.PasswordLastSet).Day).days}}
However, I can't tell if you should specify this:
#{n='DaysUntilExpired';e={([datetime]::Now.AddDays(365) - $_.PasswordLastSet).Days}}
Or, if you're looking for the last day of the month prior to the expiration date, then this:
#{n='DaysUntilExpired';e={(([datetime]::Now.AddDays(365) - $_.PasswordLastSet.Day).Days}}
As the comments mention, [datetime]::$_.PasswordLastSet is nonsense. That's the first bug. The second one is that the property of a timespan is Days, not Day. Day is a property of a datetime.
However, assuming you're trying to calculate the password expiration date defined by AD password policy, you should look at the msDS-UserPasswordExpiryTimeComputed property in AD because that's what that property contains. You have to convert it from a large integer date, but that's what [datetime]::fromfiletime() does.
Get-ADUser -Filter * -Properties PasswordLastSet, Mail, 'msDS-UserPasswordExpiryTimeComputed' -SearchBase $searchBase |
Select-Object -Properties Name, PasswordLastSet, #{n='PasswordExpirationDate';e={[DateTime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}}
This doesn't do everything your script does, but then I don't understand why you're looking for accounts whose password was set an exact number of days in the past. That doesn't seem useful.

AD inactive user with OU

I'd like to get a list of users that haven't used their account in the past 90 days. And I'd like to see in which OU/DC they are without getting the CN. is this possible? I'm using PowerShell ISE for this
I currently have
Search-ADAccount -UsersOnly –AccountInActive –TimeSpan 90:00:00:00
–ResultPageSize 2000 –ResultSetSize $null
| ?{$_.Enabled –eq $True}
| Select-Object Name, SamAccountName, DistinguishedName, LastLogonDate
| Export-CSV “C:\Temp\InActiveUsers.CSV” –NoTypeInformation
This returns the full distinguished name and I have to remove the CN in Excel afterwards, which is an annoying mess - I'd rather not deal with that repeatedly.
The solution doesn't have to be based on search-adaccount, but I do want it to be in a single code, so I don't have to get a list of users and then use that list with another bit of code to get their OU/DC.
You can grab the superior DN by splitting the string on the first non-escaped comma and discard the CN part:
# ...
| Select-Object Name,SamAccountName,#{Name='OU';Expression={($_.DistinguishedName -split '(?<!\\),',2)[1]}}, LastLogonDate
If your domain is running at least Windows 2012, you can ask for the msDS-parentdistname attribute, which will give you the DN of the parent object. It's a constructed attribute, which means it's calculated at the time you ask for it. You have to specifically ask for it, which means in this case I think you'll have to pipe the result into Get-ADUser to do so. That might slow things down quite a bit (there are faster ways to do this) but it should work.
Search-ADAccount -UsersOnly –AccountInActive –TimeSpan 90:00:00:00
–ResultPageSize 2000 –ResultSetSize $null
| ?{$_.Enabled –eq $True}
| Get-AdUser -Properties Name, SamAccountName, "msDS-parentdistname", LastLogonDate
| Select-Object Name, SamAccountName, "msDS-parentdistname", LastLogonDate
| Export-CSV "C:\Temp\InActiveUsers.CSV" –NoTypeInformation

Use Search-ADAccount to find all accounts with Account Expiration Date Not Set

Is there a way in Powershell to list all AD Accounts in the domain which don't have an account expiration date set? ie the accounts expiration date is set to 'Never'.
I can utilise Get-ADuser to get the expiry of a single account.
get-aduser username | Select-Object -Property name,Enabled,AccountExpirationDate,DistinguishedName | Where-Object {$_.AccountExpirationDate -eq '`n'}
However is there a way to use "Search-ADAccount -AccountExpiring....." to get a list of all accounts in the domain which don't have an account expiration date set or a better way to do this?
When I use the below command I don't get any return information however I setup a test account with no Expiration Date (ie Never) set to test the command however the account is not displayed in the results.
Search-ADAccount -AccountExpiring | Select-Object -Property name,AccountExpirationDate | Where-Object {$_.AccountExpirationDate -eq '`n'}
Solution with Get-ADUser
You can still use Get-ADUser to find the accounts, if you use the correct Filter:
Get-ADUser -Filter {-not(AccountExpirationDate -like "*") } -Properties AccountExpirationDate | Select-Object -Property name,Enabled,AccountExpirationDate,DistinguishedName
This will give you every Account where no value is set for the Attribute AccountExpirationDate.
Solution with Search-ADAccount
If you still want to use Search-ADAccount you have to offer a timestamp until the Accounts should expire (take a look at the ref). There is no option to search for accounts that doesn't have any value set. You allways have to offer some kind of DateTime.
For example, if you want to find all Accounts that expire in 2 Weeks you have to options:
First:
A solution with a date on which the account expires:
Search-ADAccount -AccountExpiring -DateTime ((Get-Date).AddDays(14))
Second:
A solution on the remaining days until the account expires:
Search-ADAccount -AccountExpiring -Timespan "14"
I found a solution combining Paxz reply above and this Technet thread. The 'AccountExpirationDate' is too hard to filter out of AD effectively without exporting every users Account Expiration Date and formatting it to readable date-time string.
The Technet article linked above explains that "accountExpires AD attribute is a large integer (64-bit) representing dates (in UTC) as the number of 100-nanosecond intervals since 12:00 am January 1, 1601. The AccountExpirationDate parameter is a property method that converts the value of accountExpires into the corresponding date in the local time zone". From additional research when an account is set to Never expire it will have an 'accountexpires' integer of 9223372036854775807.
'Get-ADUser' can be used to filter for all accounts where the 'accountexpires' integer equals '9223372036854775807'. This avoids the need to convert the date for every account in the Domain.
Get-ADUser -filter {Enabled -eq 'True' -and accountexpires -eq '9223372036854775807'} | Select-Object name,enabled,accountexpires,distinguishedName