SQL Server Converting AD TimeStamp with T-SQL

sz81bmfz  于 2023-10-15  发布在  其他
关注(0)|答案(3)|浏览(168)

How to convert Windows NT time from a SQL query pull to a readable format? I'm doing an AD pull of user accounts and I want to convert or CAST the windows AD timestamp to a better readable format. The issue is I am having problems doing that converting when doing the pull.

Query:

SELECT
  CASE
    WHEN CHARINDEX('@', userPrincipalName) > 7
      THEN SUBSTRING(userPrincipalName, 1, (CHARINDEX('@', userPrincipalName)) - 1)
    ELSE ''
  END AS edipi
 ,UPPER(samaccountname) AS samaccountname
 ,givenName AS firstName
 ,sn AS lastName
 ,initials
 ,UPPER(mail) AS email
 ,userAccountControl
 ,telephoneNumber
 ,title
 ,accountExpires
FROM
  OPENQUERY
    (ADSI
     ,'select 
          givenName, 
          samaccountName, 
          userPrincipalName, 
          sn, 
          initials, 
          mail, 
          userAccountControl, 
          telephoneNumber, 
          title, 
          accountExpires
        from ''LDAP PATH''
        where objectcategory=''person'' and objectclass = ''user'' and name=''*'' '
    );

My query returns the accountExpires Field in windows NT time but, I want it to be something like this:

2020-02-09 15:23:36.367

instead of this:

132257354163700000

I have come up with a simple solution doing the converting one by one, but I want it to do the CAST on the pull instead of having to do this for every users

DECLARE @accountExpired BIGINT
SET @accountExpired = 132257354163700000; --This is a random time pulled from a user from the above select statement.

SELECT CAST((@accountExpired / 864000000000.0 - 109207) AS DATETIME);
4szc88ey

4szc88ey1#

When SQL Server does an implicit conversion from nvarchar to numeric (or anything to numeric , actually), it sets the default precision and scale to numeric(18,0) . That's good enough for the sample data in your question, but the error message indicates that there's a value somewhere in your data set that exceeds the capacity of the defaulted data type.

To get past that, try an explicit cast to a larger capacity numeric . Maybe:

SELECT
  ...
 ,CAST((CAST(accountExpires AS numeric(28,0)) / 864000000000.0 - 109207) AS DATETIME)
 ...

Probably, numeric(19,0) would be sufficient, but if you go over 19, you might as well go to 28 since 20-28 all have the same storage size.

o7jaxewo

o7jaxewo2#

This worked for me for every user in AD.

CAST((convert(bigint, lastlogontimestamp) / 864000000000.0 - 109207) AS DATETIME) as lastLogonTimestamp,

-- To overcome the limit of datetime convert to big or to small to null case when convert(bigint, accountexpires) = 0 then null when convert(bigint, accountexpires) > 2650467743999999716 then null else CAST((convert(bigint, accountexpires) / 864000000000.0 - 109207) AS DATETIME) end as accountexpires

jmo0nnb3

jmo0nnb33#

Several years late to the party, but hopefully this helps others trying to query LDAP.

Erics' answer is great! However, I ran into the overflow error and had to increase the NUMERIC(28,0) to NUMERIC(38,0) to account for very large numbers/dates from AD. The Select statement example below will output "2023-07-15 00:00:00.000"

select CAST((CAST(133338528000000000 AS numeric(38,0)) / 864000000000.0 - 109207) AS DATETIME) as accountExpires

Below is a working example, on my domain of course, that pulls 500 records from LDAP and converts the accountExpires to a readable date. The userAccountControl statements are for pulling Active and Disabled employees only and excluding accounts without a password.

SELECT TOP 500 [name], adsPath, streetaddress, pager, company, title, displayName, telephoneNumber, sAMAccountName, mail, mobile,facsimileTelephoneNumber, department, physicalDeliveryOfficeName, givenName, cn, initials, mailnickname, othertelephone,ou, postaladdress, l, postalcode, st, C, sn, Manager, userPrincipalName,distinguishedName, userAccountControl,employeeID
,CAST((CAST(accountExpires AS numeric(38,0)) / 864000000000.0 - 109207) AS DATETIME) as accountExpires
FROM OPENQUERY(ADSI,
'<LDAP://MyDomain.com/DC=MyDomain,DC=com>;
(&(employeeNumber=*)(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=512)(!userAccountControl:1.2.840.113556.1.4.803:=32)(userAccountControl:1.2.840.113556.1.4.803:=2)(samAccountType=805306368)(mail=*)(uSNChanged=*));
name,adsPath,streetaddress,pager,company,title,displayName,telephoneNumber,sAMAccountName,mail,mobile
,facsimileTelephoneNumber,department,physicalDeliveryOfficeName,givenName,cn,initials,mailnickname, othertelephone
,ou,postaladdress,l,postalcode,st,C,sn,Manager,userPrincipalName, distinguishedName, userAccountControl,employeeID,accountExpires;subtree')

I hope this helps

相关问题