{"id":69033,"date":"2005-09-02T19:08:00","date_gmt":"2005-09-02T19:08:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2005\/09\/02\/how-can-i-return-a-list-of-all-the-users-whose-user-account-never-expires\/"},"modified":"2005-09-02T19:08:00","modified_gmt":"2005-09-02T19:08:00","slug":"how-can-i-return-a-list-of-all-the-users-whose-user-account-never-expires","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-return-a-list-of-all-the-users-whose-user-account-never-expires\/","title":{"rendered":"How Can I Return a List of All the Users Whose User Account Never Expires?"},"content":{"rendered":"<p><P>&nbsp;<\/P><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hey, Scripting Guy! How can I return a list of all the users whose user account never expires?<BR><BR>&#8212; PG<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, PG. You know, no one &#8211; not even his own mother! &#8211; has ever claimed that the Scripting Guy who writes this column is a genius. Needless to say, then, the first time he read this question he thought it said, \u201cHow can I return a list of all the <I>users<\/I> who never expire?\u201d Having once served as a system administrator, the idea of having users who never expired, users who would continue to live &#8211; and to torment &#8211; their system administrators forever and ever was truly frightening. Fortunately, though, you were just talking about user <I>accounts<\/I> and not the users themselves.<\/P>\n<TABLE class=\"dataTable\" id=\"E6C\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. We should clarify that this Scripting Guy never wanted any of his users to die, not even the one who reformatted her hard drive because she read somewhere that doing so would remove all the old files that she didn\u2019t use anymore. Well, it did.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>For some reason, this calls to mind an episode of <I>The Simpsons<\/I> where Bart &#8211; saying his evening prayers &#8211; asks God to kill Sideshow Bob. \u201cBart!\u201d said his mother. \u201cYou don\u2019t ask God to kill people!\u201d \u201cThat\u2019s right,\u201d added Homer, \u201cyou do your own killing.\u201d<\/P>\n<P>Fortunately, no one has to be harmed in any way in order for us to get back a list of all the user accounts that never expire. In fact, all you have to do is run a script similar to this:<\/P><PRE class=\"codeSample\">On Error Resume Next<\/p>\n<p>Const ADS_SCOPE_SUBTREE = 2<\/p>\n<p>Set objConnection = CreateObject(&#8220;ADODB.Connection&#8221;)\nSet objCommand =   CreateObject(&#8220;ADODB.Command&#8221;)\nobjConnection.Provider = &#8220;ADsDSOObject&#8221;\nobjConnection.Open &#8220;Active Directory Provider&#8221;\nSet objCommand.ActiveConnection = objConnection<\/p>\n<p>objCommand.Properties(&#8220;Page Size&#8221;) = 1000\nobjCommand.Properties(&#8220;Searchscope&#8221;) = ADS_SCOPE_SUBTREE <\/p>\n<p>objCommand.CommandText = _\n    &#8220;SELECT AdsPath FROM &#8216;LDAP:\/\/dc=fabrikam,dc=com&#8217; WHERE objectCategory=&#8217;user'&#8221;\nSet objRecordSet = objCommand.Execute<\/p>\n<p>objRecordSet.MoveFirst\nDo Until objRecordSet.EOF\n    Set objUser = GetObject(objRecordSet.Fields(&#8220;AdsPath&#8221;).Value)<\/p>\n<p>    If objUser.AccountExpirationDate = &#8220;1\/1\/1970&#8221; Or Err.Number = -2147467259 Then\n        Wscript.Echo objUser.Name\n    End If<\/p>\n<p>    objRecordSet.MoveNext\nLoop\n<\/PRE>\n<P>We should point out that we took a bit of a shortcut here, a shortcut that makes the script easier to write and easier to understand, but one that <I>does<\/I> make the script a tad bit slower and a little less efficient. Although there are two different properties that can be used to determine whether a user account expires or not &#8211; <B>accountExpires<\/B> and <B>accountExpirationDate<\/B> &#8211; neither one is a simple yes\/no kind of value: yes the user account will expire someday, no the user account will never expire. Instead, each property contains a value that either indicates the date that the account expires or the fact that the account will not expire. Because accountExpires is a large integer value that tracks time via the number of nanoseconds that have expired since January 1, 1601, we decided to skip that whole mess and use accountExpirationDate instead.<\/P>\n<P>Not that this totally solves all our problems, mind you. Technically, accountExpirationDate is not even an attribute of a user account; instead, it\u2019s an Active Directory property method. When you ask for the accountExpirationDate, ADSI will actually grab the value of the accountExpires attribute and convert it to a real date. That\u2019s the good news: when you ask for accountExpirationDate you\u2019ll get back a <I>real<\/I> date-time value, not the number of nanoseconds that have expired since January 1, 1601. The bad news? Because accountExpirationDate isn\u2019t a hard-coded user account attribute you can\u2019t use ADO to search for accounts based on that attribute.<\/P>\n<P>Having fun yet? Now, we <I>could<\/I> create a somewhat complicated script and do a search using the accountExpires attribute. Being the Scripting Guys, however, we opted to take the easy way out. Instead of retrieving only those user accounts where accountExpires is equal to a certain value, we decided to retrieve <I>all<\/I> the user accounts, then bind to each individual account and use accountExpirationDate to determine whether the account expires. Like we said, this is not the optimal way to do things; your script <I>will<\/I> take a bit longer to run. (Although, depending on the number of users you have, \u201ca bit longer\u201d might only be a few seconds.) However, this script is much easier to write, and thus much easier for you to use and modify.<\/P>\n<P>Wait a second: we aren\u2019t done just yet. There\u2019s one more issue we have to deal with. How do we know whether or not a user account will expire? Well, if accountExpirationDate is set to January 1, 1970 then the account will never expire. (Weird, but true.) Unfortunately, though, that\u2019s not the only way to determine whether or not a user account is configured to never expire. An account also doesn\u2019t expire if no accountExpirationDate has been set. You find out accountExpirationDate has no value when you try to access this attribute and get back error number -2147467259 (the much-beloved \u201cUnspecified error\u201d error). That means for each account we need to determine whether accountExpirationDate is set to January 1, 1970 <I>or<\/I> whether we get back error number -2147467259 when trying to get the value of accountExpirationDate. That\u2019s what this block of code is for:<\/P><PRE class=\"codeSample\">If objUser.AccountExpirationDate = &#8220;1\/1\/1970&#8221; Or Err.Number = -2147467259 Then\n    Wscript.Echo objUser.Name\nEnd If\n<\/PRE>\n<P>If either of our criteria is true, we echo back the user name; we do that because this is an account that does not expire. If neither criteria is true then we do nothing at all; that\u2019s because this account <I>does<\/I> expire, and all we care about here are those accounts that never expire.<\/P>\n<P>Well, at least <I>that<\/I> part is simple.<\/P>\n<P>There\u2019s obviously more to the script than just this simple block of code, but the remainder is pretty much a run-of-the-mill Active Directory search script. If you need more information about searching Active Directory, take a look at our two-part <I>Tales from the Script<\/I> series <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/tales\/sg0405.mspx\"><B>Dude, Where\u2019s My Printer?<\/B><\/A> That should give you a good explanation of what the rest of the script does.<\/P>\n<TABLE class=\"dataTable\" id=\"EHF\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Disclaimer<\/B>. No users were harmed during the making of today\u2019s column. We aren\u2019t saying we weren\u2019t tempted (like, say, the user who uninstalled Microsoft Word because he was finished using it for the day) but \u2026.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV><BR>\n<DIV>\n<TABLE class=\"\" cellSpacing=\"0\" cellPadding=\"0\" width=\"100%\" border=\"0\">\n<TBODY>\n<TR>\n<TD class=\"\"><A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/sept05\/hey0902.mspx#top\"><IMG height=\"9\" alt=\"Top of page\" src=\"http:\/\/www.microsoft.com\/technet\/mnplibrary\/templates\/MNP2.Common\/images\/arrow_px_up.gif\" width=\"7\" border=\"0\"><\/A><A class=\"topOfPage\" href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/sept05\/hey0902.mspx#top\">Top of page<\/A><\/TD><\/TR><\/TBODY><\/TABLE><\/DIV><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! How can I return a list of all the users whose user account never expires?&#8212; PG Hey, PG. You know, no one &#8211; not even his own mother! &#8211; has ever claimed that the Scripting Guy who writes this column is a genius. Needless to say, then, the first time he [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[7,3,63,20,5],"class_list":["post-69033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-scripting-guy","tag-security","tag-user-accounts","tag-vbscript"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! How can I return a list of all the users whose user account never expires?&#8212; PG Hey, PG. You know, no one &#8211; not even his own mother! &#8211; has ever claimed that the Scripting Guy who writes this column is a genius. Needless to say, then, the first time he [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/69033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=69033"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/69033\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=69033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=69033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=69033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}