{"id":54163,"date":"2009-03-18T21:24:00","date_gmt":"2009-03-18T21:24:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/03\/18\/hey-scripting-guy-how-can-i-search-active-directory-with-windows-powershell-to-return-a-list-of-missing-groups\/"},"modified":"2009-03-18T21:24:00","modified_gmt":"2009-03-18T21:24:00","slug":"hey-scripting-guy-how-can-i-search-active-directory-with-windows-powershell-to-return-a-list-of-missing-groups","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-search-active-directory-with-windows-powershell-to-return-a-list-of-missing-groups\/","title":{"rendered":"Hey, Scripting Guy! How Can I Search Active Directory with Windows PowerShell to Return a List of Missing Groups?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/H2>\n<P>Hey, Scripting Guy! We created some groups that were used by our student interns. The student interns have now returned to college (yeah, it was a while ago). To be honest, I had actually forgotten about these groups, but the other day I was doing some work in Active Directory Users and Computers and I happened across one of these student intern groups. That reminded me that I had actually created several different groups for the students. Luckily, I had placed the word intern in the groups&#8217; description property. Is there a way I can easily find all of the intern groups, so I can look at them and make a decision as to their final disposition?<BR><BR>&#8211; RH<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"> \n<P>Hi RH,<\/P>\n<P>I am listening to &#8220;Lost Someone&#8221; by <A href=\"http:\/\/en.wikipedia.org\/wiki\/James_Brown\" target=\"_blank\">James Brown<\/A> on my Zune. It\u2019s the recording that was made live from the <A href=\"http:\/\/en.wikipedia.org\/wiki\/Apollo_Theater\" target=\"_blank\">Apollo Theatre<\/A> back in 1963. Man, what a voice. It is easy to see why he was called the hardest working man in show business. Anyway, it seems that the song is apropos because it seems you have lost several groups. Luckily, we can use Windows PowerShell to search Active Directory and return a listing of the missing groups. <\/P>\n<TABLE id=\"EAD\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">This week we are talking about searching Active Directory. The <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/hubs\/ad.mspx\" target=\"_blank\">Active Directory Script Center Hub<\/A> has links to a number of resources related to working with Active Directory. You will also find in <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/scripts\/ad\/search\/default.mspx\" target=\"_blank\">this section<\/A> of the Script Center Script Repository a good collection of scripts that illustrate searching Active Directory. There are several scripts in the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/csc\/scripts\/ad\/general\/index.mspx\" target=\"_blank\">Community-Submitted Scripts Center<\/A> that also illustrate searching Active Directory. The <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/ad.mspx\" target=\"_blank\">\u201cHey, Scripting Guy!\u201d Active Directory Archive<\/A> is also an excellent source of information for searching Active Directory. Not to be outdone, the Scripting Guide has an <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/guide\/sas_ads_overview.mspx\" target=\"_blank\">ADSI Scripting Primer<\/A>.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>We decided to write a script named <B>SearchGroupDescriptions.ps1<\/B>. This script connects to the default domain and finds all the groups that have a description that contains the word \u201cintern\u201d in it. A similar script written in VBScript is available in the <A href=\"http:\/\/en.wikipedia.org\/wiki\/Apollo_Theater\" target=\"_blank\">Script Center Script Repository<\/A>. The <B>SearchGroupDescriptions.ps1<\/B> script is seen here:<\/P><PRE class=\"codeSample\">$Filter = &#8220;(&amp;(ObjectCategory=group)(Description=*intern *))&#8221;\n$Searcher = New-Object System.DirectoryServices.DirectorySearcher($Filter)\n$Searcher.Findall() | \nForEach-Object `\n  -Begin { &#8220;Results of $Filter query: &#8221; } `\n  -Process { \n                    $_.properties.item(&#8220;DistinguishedName&#8221;)\n                    $_.properties.item(&#8220;Description&#8221;)\n                    &#8220;`r&#8221;\n                   } `\n  -End { [string]$Searcher.FindAll().Count + &#8221; $Filter results were found&#8221; }\n<\/PRE>\n<P>If&nbsp;we look in Active Directory Users and Computers, we find we have an organizational unit named <B>Students<\/B>. In there, we find a group that has a description that contains the word \u201cintern\u201d in it. This is seen here:<\/P><IMG border=\"0\" alt=\"Image of the Students organizational unit\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0317\/hsg-3-17-9-1.jpg\" width=\"500\" height=\"221\"> \n<P>&nbsp;<\/P>\n<P>Perhaps the hardest thing about searching Active Directory is configuring the appropriate search filter. If you would like some refresher information about the LDAP dialect search filter syntax, refer to <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/mar09\/hey0317.mspx\">yesterday\u2019s \u201cHey, Scripting Guy!\u201d article<\/A>.<\/P>\n<P>In our search filter, we are using two Active Directory attributes: the <B>ObjectCategory<\/B> and the <B>Description<\/B>. If we were to use a search filter that returned all groups, it would look like the following:<\/P><PRE class=\"codeSample\">&#8220;ObjectCategory=group&#8221;<\/PRE>\n<P>Of course there are lots of groups in Active Directory\u2014both those we created and those created by the system. On the other hand, if we were to look for objects that had a description that contained the word \u201cintern\u201d in them, the query would look like this one:<\/P><PRE class=\"codeSample\">&#8220;Description=*intern*&#8221;<\/PRE>\n<P>When we put the two together, we need to add some parentheses and an ampersand. The query now looks like the one seen here:<\/P><PRE class=\"codeSample\">&#8220;(&amp;(ObjectCategory=group)(Description=*intern*))&#8221;<\/PRE>\n<P>On our computer, when we run the script with the above query, our results are not exactly what we were expecting. This is because an additional group is returned. This is one that we do not use, but it was created by the system for use by the Internet Information Services. D&#8217;oh! This is seen here:<\/P><IMG border=\"0\" alt=\"Image of the query results with one additional group\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0318\/hsg-3-18-9-2.jpg\" width=\"500\" height=\"248\"> \n<P>&nbsp;<\/P>\n<P>No problem. From looking at the results seen in that image, it seems the match was the word \u201cInternet\u201d; all we need to do is to include a space after the letter &#8220;n&#8221; in the word \u201cintern\u201d. The quickly revised query is seen here:<\/P><PRE class=\"codeSample\">$Filter = &#8220;(&amp;(ObjectCategory=group)(Description=*intern *))&#8221;<\/PRE>\n<P>The easiest way to search Active Directory when using Windows PowerShell 1.0 is to create an instance of the <B>System.DirectoryServices.DirectorySearcher<\/B>. To do this we use the <B>New-Object<\/B> cmdlet and tell it we want to create the <B>System.DirectoryServices.DirectorySearcher<\/B> class, and we feed it the filter we arrived at from our earlier experimentation. We store the returned <B>DirectorySearcher<\/B> object in the <B>$Searcher<\/B> variable as seen here:<\/P><PRE class=\"codeSample\">$Searcher = New-Object System.DirectoryServices.DirectorySearcher($Filter)<\/PRE>\n<P>We use the <B>FindAll<\/B> method from the <B>DirectorySearcher<\/B> object to find everything that matches our query. We pipeline the resulting object as seen here:<\/P><PRE class=\"codeSample\">$Searcher.Findall() |<\/PRE>\n<P>Next we use the <B>ForEach-Object<\/B> cmdlet to allow us to work our way through objects as they come across the pipeline. The <B>ForEach-Object<\/B> cmdlet is documented on the Script Center. We use the back-tick line continuation character (`) because we want to line up the <B>-Begin<\/B>, <B>-Process<\/B>, and <B>-End<\/B> parameters. This is seen here:<\/P><PRE class=\"codeSample\">ForEach-Object `<\/PRE>\n<P>The <B>-Begin<\/B> parameter contains information that will run once for all the stuff that comes across the pipeline. We use it here to provide a bit of feedback to the user running the script. Because we display the query that is contained in the <B>$Filter<\/B> variable, this can actually provide a bit of troubleshooting information in the case that the script returns unexpected results. This is shown here: <\/P><PRE class=\"codeSample\">-Begin { &#8220;Results of $Filter query: &#8221; } `<\/PRE>\n<P>The <B>-Process<\/B> block is executed once for each object that comes across the pipeline. In this script, it is executed once for each group that was identified as a match for our query. The <B>-Process<\/B> block opens a set of curly brackets as seen here:<\/P><PRE class=\"codeSample\">-Process {<\/PRE>\n<P>Now we decide which information we want our script to return. In this script, we are interested in the <B>DistinguishedName<\/B> attribute because it will tell us exactly where the group was found. We also want the group description so that we can ensure the match was legitimate. We also decide it would be nice to include a carriage return to separate the groups from each other. The code that prints out the two attributes is seen here:<\/P><PRE class=\"codeSample\">$_.properties.item(&#8220;DistinguishedName&#8221;)\n                    $_.properties.item(&#8220;Description&#8221;)\n                    &#8220;`r&#8221;\n                   } `\n<\/PRE>\n<P>Now&nbsp;we need to print out confirmation that the script has completed running. To do this, we use the <B>-End<\/B> parameter of the <B>ForEach-Object<\/B> cmdlet. We convert the number that represents the count of the items returned by the query into a string so that we can concatenate it with another string that tells us how the results were found. This is seen here:<\/P><PRE class=\"codeSample\">-End { [string]$Searcher.FindAll().Count + &#8221; $Filter results were found&#8221; }<\/PRE>\n<P>The display of the matching groups is seen here:<\/P><IMG border=\"0\" alt=\"Image of the display of the matching groups\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0318\/hsg-3-18-9-3.jpg\" width=\"500\" height=\"248\"> \n<P>&nbsp;<\/P>\n<P>Well, SL, this concludes our discussion about searching Active Directory for a listing of all computers in the domain. Join us tomorrow as Searching Active Directory Week continues. Until then, peace.<\/P>\n<P>&nbsp;<\/P>\n<P><B>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/B><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! We created some groups that were used by our student interns. The student interns have now returned to college (yeah, it was a while ago). To be honest, I had actually forgotten about these groups, but the other day I was doing some work in Active Directory Users and Computers and I [&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,8,45],"class_list":["post-54163","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-scripting-guy","tag-searching-active-directory","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! We created some groups that were used by our student interns. The student interns have now returned to college (yeah, it was a while ago). To be honest, I had actually forgotten about these groups, but the other day I was doing some work in Active Directory Users and Computers and I [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54163","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=54163"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54163\/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=54163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=54163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=54163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}