{"id":8097,"date":"2021-01-28T15:44:00","date_gmt":"2021-01-28T20:44:00","guid":{"rendered":"https:\/\/jdhitsolutions.com\/blog\/?p=8097"},"modified":"2021-01-28T15:44:07","modified_gmt":"2021-01-28T20:44:07","slug":"building-a-powershell-tool-for-active-directory-changes","status":"publish","type":"post","link":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/","title":{"rendered":"Building a PowerShell Tool for Active Directory Changes"},"content":{"rendered":"\n<div class=\"wp-block-image is-style-default\"><figure class=\"alignleft size-large\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png\"><img loading=\"lazy\" decoding=\"async\" width=\"171\" height=\"286\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png\" alt=\"\" class=\"wp-image-4019\"\/><\/a><\/figure><\/div>\n\n\n\n<p>A few days ago, <a href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8087\/an-active-directory-change-report-from-powershell\/\" target=\"_blank\" rel=\"noreferrer noopener\">I posted a PowerShell script<\/a> I wrote that creates a formatted HTML report, complete with collapsible regions, which shows recent changes to objects in your Active Directory domain.  Including objects that have been deleted, assuming you enabled the Active Directory RecycleBin feature. I am pleased with the result and many of you found it useful and at least worth looking at. However, I realize now that I went about the process backward. True, the HTML generating script is based on PowerShell code that I can run interactively to show Active Directory changes. But I should have gone further. I should have built a PowerShell tool that would show me the same changes, but from a PowerShell console prompt. I hinted at this in the original article. The script I wrote is useful, but it can only do what it is designed to do -- create an HTML report.  Here's how I fixed my oversight.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Start with a PowerShell Cmdlet<\/h2>\n\n\n\n<p>As with any PowerShell toolmaking project you want to start with a cmdlet and a PowerShell expression or set of expressions, that you can run interactively to achieve the desired result. Or at least enough of the result that you can embellish. I had that code using Get-ADObject from the previous script. But where the HTML report script could only do one thing, I wanted my command-line tool to be more flexible. <\/p>\n\n\n\n<p>In addition to supporting some of the Get-ADObject parameters such as Credential, Server and SearchBase, I also wanted the user to be able to specify the type of object. Maybe I only need to see Group objects now, but tomorrow I want to see users and computers. I will need a parameter like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">[Parameter(<em>HelpMessage<\/em>\u00a0=\u00a0\"Specify\u00a0the\u00a0types\u00a0of\u00a0objects\u00a0to\u00a0query.\")]\n[ValidateSet(\"User\",\"Group\",\"Computer\",\"OU\")]\n[ValidateNotNullOrEmpty()]\n[string[]]$Category\u00a0=\u00a0\"User\",<\/code><\/pre>\n\n\n\n<p>There are many types of Active Directory objects but these are the ones that I want to watch on a regular basis. Notice the use of [ValidateSet()]. These are the only possible values and PowerShell will tab-complete them. Remember that if you specify a default value that it is included in the validation set.<\/p>\n\n\n\n<p>I also thought about what properties I wanted to see.  You aren't limited to original object. I had a list of what I wanted from the Get-ADObject command. But I also wanted to include the name of the domain controller.  You might get different results depending on domain controller replication so I wanted to capture the domain controller. I couldn't find anywhere in the output that showed that to me, so I decided to set a default parameter value for the server so that I'd always have something to use.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">[Parameter(<em>HelpMessage<\/em>\u00a0=\u00a0\"Specifies\u00a0the\u00a0Active\u00a0Directory\u00a0Domain\u00a0Services\u00a0domain\u00a0controller\u00a0to\u00a0query.\u00a0The\u00a0default\u00a0is\u00a0your\u00a0Logon\u00a0server.\")]\n[alias(\"DC\")]\n[ValidateNotNullorEmpty()]\n[string]$Server\u00a0=\u00a0$env:LOGONSERVER.SubString(2)<\/code><\/pre>\n\n\n\n<p>The environment variable uses a format like \\\\DOM1 but Get-ADObject is expecting a server value of DOM1 so my default value parses the environment value. I could have made the parameter mandatory, but that felt like overkill. Although I could have added an ArgumentCompleter to the Server parameter.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\"><code>[ArgumentCompleter({(Get-ADDomain).ReplicaDirectoryServers})]<\/code><\/code><\/pre>\n\n\n\n<p>In a small domain, this might be a good choice.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">LDAP Queries<\/h2>\n\n\n\n<p>My HTML reporting script used a single filter to get all objects modified since a given datetime. But my new PowerShell tool was expecting to be a bit more granular. I started out trying to build a complex filtering expression for Get-ADObject on-the-fly, based on parameter values from my function. This soon got out of hand. In addition, there was a quirk in Active Directory that I had forgotten about. My early versions returned changed objects for users AND computers, even when I was only searching for users. This is because the computer object is derived from the user object and searching for the latter included the former.<\/p>\n\n\n\n<p>My solution was to fall back to LDAP filters which turned out to be a good thing. Now I could have a filter that returned exactly the object type I was looking for. However, including filtering on the datetime value added another wrinkle. I couldn't include something like \"WhenChanged >= '1\/28\/2021 2:00PM'\". I needed to convert the datetime value to a string formatted as yyyyMMddhhmmss.ff followed by a timezone offset like -0400. I wrote a private helper function to reformat the datetime value.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function\u00a0_ConvertToLDAPTime\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em>#a\u00a0private\u00a0helper\u00a0function\u00a0to\u00a0convert\u00a0a\u00a0date\u00a0time\u00a0object\u00a0into\u00a0a\u00a0LDAP\u00a0query-compatible\u00a0value<\/em>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Param([datetime]$Date)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$offset\u00a0=\u00a0(Get-TimeZone).baseUtcOffset\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em>#values\u00a0must\u00a0be\u00a0formatted\u00a0with\u00a0leading\u00a0zeros\u00a0to\u00a0the\u00a0specified\u00a0number\u00a0of\u00a0decimal\u00a0places<\/em>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$tz\u00a0=\u00a0\"{0:d2}{1:d2}\"\u00a0-f\u00a0$offset.hours,$offset.Minutes\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"{0:yyyyMMddhhmmss}.0{1}\"\u00a0-f\u00a0$date,$tz\n}<\/code><\/pre>\n\n\n\n<p>I'm using a non-standard name because this function is not exposed to the user and is only called within the parent function.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\"><em>$<\/em>dt\u00a0=\u00a0_ConvertToLDAPTime\u00a0-Date\u00a0$Since<\/code><\/pre>\n\n\n\n<p>In my function, I will loop through each object class using an LDAP filter.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">foreach\u00a0($objClass\u00a0in\u00a0$Category)\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Switch\u00a0($objclass)\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"User\"\u00a0\u00a0\u00a0\u00a0\u00a0{\u00a0$ldap\u00a0=\u00a0\"(&amp;(WhenChanged>=$dt)(objectclass=user)(!(objectclass=computer)))\"\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"Computer\"\u00a0{\u00a0$ldap\u00a0=\u00a0\"(&amp;(WhenChanged>=$dt)(objectclass=computer))\"}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"Group\"\u00a0\u00a0\u00a0\u00a0{\u00a0$ldap\u00a0=\u00a0\"(&amp;(WhenChanged>=$dt)(objectclass=group))\"}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"OU\"\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\u00a0$ldap\u00a0=\u00a0\"(&amp;(WhenChanged>=$dt)(objectclass=organizationalunit))\"}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Write-Verbose\u00a0\"[$(Get-Date)]\u00a0Using\u00a0LDAP\u00a0filter\u00a0$ldap\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$getparams[\"LDAPFilter\"]\u00a0=\u00a0$ldap\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Get-ADObject\u00a0@getParams\u00a0|\u00a0Foreach-Object\u00a0{\u00a0$items.Add($_)}\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Creating New Objects<\/h2>\n\n\n\n<p>The results are saved to a list object which is then processed and turned into a new custom object with a typename of ADChange.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">foreach\u00a0($item\u00a0in\u00a0$items)\u00a0{\n\u00a0\u00a0\u00a0\u00a0if\u00a0($item.WhenCreated\u00a0-ge\u00a0$since)\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$isNew\u00a0=\u00a0$True\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0else\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$isNew\u00a0=\u00a0$false\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0<em>#create\u00a0a\u00a0custom\u00a0object\u00a0based\u00a0on\u00a0each\u00a0search\u00a0result<\/em>\n\u00a0\u00a0\u00a0\u00a0[PSCustomObject]@{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0PSTypeName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0\"ADChange\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ObjectClass\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.ObjectClass\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ObjectGuid\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.ObjectGuid\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DistinguishedName\u00a0=\u00a0$item.DistinguishedName\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.Name\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DisplayName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.DisplayName\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Description\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.Description\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WhenCreated\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.WhenCreated\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WhenChanged\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.WhenChanged\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IsNew\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$IsNew\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IsDeleted\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.Deleted\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Container\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$item.distinguishedname.split(\",\",\u00a02)[1]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DomainController\u00a0\u00a0=\u00a0$Server.toUpper()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ReportDate\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0=\u00a0$ReportDate\n\u00a0\u00a0\u00a0\u00a0}\n}\u00a0<em>#foreach\u00a0item<\/em><\/code><\/pre>\n\n\n\n<p>Why go to this effort? So that I can customize the object to make it easy to use in the pipeline. For example, I can define a few alias properties as well as a set of default properties.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Update-TypeData\u00a0-TypeName\u00a0ADChange\u00a0-DefaultDisplayPropertySet\u00a0DistinguishedName,WhenCreated,WhenChanged,IsNew,IsDeleted,ObjectClass,ReportDate\u00a0-Force\n<em>#define\u00a0some\u00a0alias\u00a0properties\u00a0for\u00a0the\u00a0custom\u00a0object<\/em>\nUpdate-TypeData\u00a0-TypeName\u00a0ADChange\u00a0-MemberType\u00a0AliasProperty\u00a0-MemberName\u00a0class\u00a0-Value\u00a0ObjectClass\u00a0-Force\nUpdate-TypeData\u00a0-TypeName\u00a0ADChange\u00a0-MemberType\u00a0AliasProperty\u00a0-MemberName\u00a0DN\u00a0-Value\u00a0DistinguishedName\u00a0-Force<\/code><\/pre>\n\n\n\n<p>I can also create a custom format file so not only can I get the default formatted view that I want, but I can include other views as well.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Update-FormatData\u00a0$PSScriptRoot\\ADchange.format.ps1xml<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"347\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default-1024x347.png\" alt=\"\" class=\"wp-image-8099\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default-1024x347.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default-300x102.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default-768x260.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default-1536x520.png 1536w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default-850x288.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-default.png 1654w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"437\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class-1024x437.png\" alt=\"\" class=\"wp-image-8100\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class-1024x437.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class-300x128.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class-768x327.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class-1536x655.png 1536w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class-850x362.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-class.png 1724w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"427\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container-1024x427.png\" alt=\"\" class=\"wp-image-8101\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container-1024x427.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container-300x125.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container-768x321.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container-1536x641.png 1536w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container-850x355.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-container.png 1780w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>I use Verbose output all the time in my PowerShell work. In this function I'm including what I refer to as runtime metadata.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"309\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose-1024x309.png\" alt=\"\" class=\"wp-image-8102\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose-1024x309.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose-300x91.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose-768x232.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose-1536x464.png 1536w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose-850x257.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/01\/get-adchange-verbose.png 1902w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>The idea is that if someone has a problem running the command, I can have them start a transcript, run the command with -Verbose, stop the transcript and send it me. Hopefully the verbose output can help me isolate the problem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Get the Code<\/h2>\n\n\n\n<p>By now some of you are looking for the  rest of the code.  Because this is something I might keep tinkering with, I have posted the Get-ADChange function and the format file on Github.  Go to <a href=\"https:\/\/gist.github.com\/jdhitsolutions\/3bce157bd64717dd616b949f6e280433\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/gist.github.com\/jdhitsolutions\/3bce157bd64717dd616b949f6e280433 <\/a>and grab both files. The files should go in the same folder and make sure the format file is saved as adchange.format.ps1xml . You can then dot source the script file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">. c:\\scripts\\get-adchange.ps1<\/code><\/pre>\n\n\n\n<p>Obviously use the appropriate path. The script will also load the format file into your PowerShell session. You should be able to run the Get-ADChange command from a Windows 10 desktop that has the ActiveDirectory module installed.<\/p>\n\n\n\n<p>That said, this code is offered as-is with no guarantees or support. I <strong>strongly encourage <\/strong>you to test thoroughly in a non-production environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>I could go back to my HTML reporting script and modify it to use this new function. Or I might build other controller scripts around it. And let me re-iterate that if you a larger Active Directory infrastructure, you will be better served by investing in true management and reporting solutions.  A number of readers wanted to be able to discover who might have made a change. That information is not stored with the Active Directory object. That's where auditing and logging come into play and where a \"real\" management product is worth the investment.<\/p>\n\n\n\n<p>Still, I hope you learn something about the process of building a PowerShell tool from this. As always, questions and comments are welcome.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A few days ago, I posted a PowerShell script I wrote that creates a formatted HTML report, complete with collapsible regions, which shows recent changes to objects in your Active Directory domain. Including objects that have been deleted, assuming you enabled the Active Directory RecycleBin feature. I am pleased with the result and many of&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"New on the blog: Building a #PowerShell Tool for Active Directory Changes","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7,4,8],"tags":[539,224,534,540],"class_list":["post-8097","post","type-post","status-publish","format-standard","hentry","category-active-directory","category-powershell","category-scripting","tag-active-directory","tag-function","tag-powershell","tag-scripting"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building a PowerShell Tool for Active Directory Changes &#8226; The Lonely Administrator<\/title>\n<meta name=\"description\" content=\"How I built a PowerShell function to get changed objects in Active Directory using LDAP searches. Includes a custom format file with ANSI.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a PowerShell Tool for Active Directory Changes &#8226; The Lonely Administrator\" \/>\n<meta property=\"og:description\" content=\"How I built a PowerShell function to get changed objects in Active Directory using LDAP searches. Includes a custom format file with ANSI.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/\" \/>\n<meta property=\"og:site_name\" content=\"The Lonely Administrator\" \/>\n<meta property=\"article:published_time\" content=\"2021-01-28T20:44:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-01-28T20:44:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png\" \/>\n<meta name=\"author\" content=\"Jeffery Hicks\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:site\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeffery Hicks\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/\"},\"author\":{\"name\":\"Jeffery Hicks\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"headline\":\"Building a PowerShell Tool for Active Directory Changes\",\"datePublished\":\"2021-01-28T20:44:00+00:00\",\"dateModified\":\"2021-01-28T20:44:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/\"},\"wordCount\":1154,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2014\\\/09\\\/blacksmith.png\",\"keywords\":[\"Active Directory\",\"Function\",\"PowerShell\",\"Scripting\"],\"articleSection\":[\"Active Directory\",\"PowerShell\",\"Scripting\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/\",\"name\":\"Building a PowerShell Tool for Active Directory Changes &#8226; The Lonely Administrator\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2014\\\/09\\\/blacksmith.png\",\"datePublished\":\"2021-01-28T20:44:00+00:00\",\"dateModified\":\"2021-01-28T20:44:07+00:00\",\"description\":\"How I built a PowerShell function to get changed objects in Active Directory using LDAP searches. Includes a custom format file with ANSI.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#primaryimage\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2014\\\/09\\\/blacksmith.png\",\"contentUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2014\\\/09\\\/blacksmith.png\",\"width\":171,\"height\":286},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8097\\\/building-a-powershell-tool-for-active-directory-changes\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"PowerShell\",\"item\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/category\\\/powershell\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a PowerShell Tool for Active Directory Changes\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/\",\"name\":\"The Lonely Administrator\",\"description\":\"Practical Advice for the Automating IT Pro\",\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\",\"name\":\"Jeffery Hicks\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"caption\":\"Jeffery Hicks\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building a PowerShell Tool for Active Directory Changes &#8226; The Lonely Administrator","description":"How I built a PowerShell function to get changed objects in Active Directory using LDAP searches. Includes a custom format file with ANSI.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/","og_locale":"en_US","og_type":"article","og_title":"Building a PowerShell Tool for Active Directory Changes &#8226; The Lonely Administrator","og_description":"How I built a PowerShell function to get changed objects in Active Directory using LDAP searches. Includes a custom format file with ANSI.","og_url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/","og_site_name":"The Lonely Administrator","article_published_time":"2021-01-28T20:44:00+00:00","article_modified_time":"2021-01-28T20:44:07+00:00","og_image":[{"url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png","type":"","width":"","height":""}],"author":"Jeffery Hicks","twitter_card":"summary_large_image","twitter_creator":"@JeffHicks","twitter_site":"@JeffHicks","twitter_misc":{"Written by":"Jeffery Hicks","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#article","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/"},"author":{"name":"Jeffery Hicks","@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"headline":"Building a PowerShell Tool for Active Directory Changes","datePublished":"2021-01-28T20:44:00+00:00","dateModified":"2021-01-28T20:44:07+00:00","mainEntityOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/"},"wordCount":1154,"commentCount":1,"publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png","keywords":["Active Directory","Function","PowerShell","Scripting"],"articleSection":["Active Directory","PowerShell","Scripting"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/","url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/","name":"Building a PowerShell Tool for Active Directory Changes &#8226; The Lonely Administrator","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#primaryimage"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png","datePublished":"2021-01-28T20:44:00+00:00","dateModified":"2021-01-28T20:44:07+00:00","description":"How I built a PowerShell function to get changed objects in Active Directory using LDAP searches. Includes a custom format file with ANSI.","breadcrumb":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#primaryimage","url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png","contentUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2014\/09\/blacksmith.png","width":171,"height":286},{"@type":"BreadcrumbList","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8097\/building-a-powershell-tool-for-active-directory-changes\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"PowerShell","item":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},{"@type":"ListItem","position":2,"name":"Building a PowerShell Tool for Active Directory Changes"}]},{"@type":"WebSite","@id":"https:\/\/jdhitsolutions.com\/blog\/#website","url":"https:\/\/jdhitsolutions.com\/blog\/","name":"The Lonely Administrator","description":"Practical Advice for the Automating IT Pro","publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jdhitsolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9","name":"Jeffery Hicks","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","caption":"Jeffery Hicks"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":37,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/37\/get-active-directory-user-information-in-powershell\/","url_meta":{"origin":8097,"position":0},"title":"Get Active Directory User Information in PowerShell","author":"Jeffery Hicks","date":"July 5, 2006","format":false,"excerpt":"One feature that PowerShell will likely be missing when it first ships is solid support for ADSI and working with Active Directory. You can use .NET DirectoryEntry objects but it feels more like programming and less like scripting. Another option for working with Active Directory in PowerShell is to use\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1036,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/1036\/join-me-in-orlando\/","url_meta":{"origin":8097,"position":1},"title":"Join Me in Orlando","author":"Jeffery Hicks","date":"December 30, 2010","format":false,"excerpt":"I will be presenting 3 sessions at Techmentor Orlando 2011. The conference runs March 14-18, 2011 at the Disney Yacht Club. My sessions are all on Wednesday March 16. In addition to all the other fabulous material at the conference I will be presenting the following: PowerShell Scripting Best Practices\u2026","rel":"","context":"In &quot;Active Directory&quot;","block_context":{"text":"Active Directory","link":"https:\/\/jdhitsolutions.com\/blog\/category\/active-directory\/"},"img":{"alt_text":"Disney Yacht Club","src":"https:\/\/i0.wp.com\/techmentorevents.com\/design\/ecg\/techmentorevents\/home\/img\/portal_2011spring.gif?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":148,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/148\/order-managing-active-directory-with-windows-powershell-tfm-finally\/","url_meta":{"origin":8097,"position":2},"title":"Order Managing Active Directory with Windows PowerShell: TFM &#8211; Finally!","author":"Jeffery Hicks","date":"September 22, 2008","format":false,"excerpt":"Yes, its finally true. You can finally get your hands on Managing Active Directory with Windows PowerShell: TFM. The book is being printed so you can get your copy today. You can order it today at ScriptingOutpost.com in both print and ebook format. Or if you prefer the best of\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":130,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/130\/techmentor-san-francisco-2008\/","url_meta":{"origin":8097,"position":3},"title":"Techmentor San Francisco 2008","author":"Jeffery Hicks","date":"February 22, 2008","format":false,"excerpt":"I finished up my slide decks last week for the first Techmentor conference of the year in San Francisco (March 30 -April 3). If you've never been to a Techmentor conference you're missing a great opportunity to hear and see your favorite IT speakers. Plus it's a lot of fun\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":8400,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8400\/friday-fun-custom-grouping-with-powershell\/","url_meta":{"origin":8097,"position":4},"title":"Friday Fun &#8211; Custom Grouping with PowerShell","author":"Jeffery Hicks","date":"May 14, 2021","format":false,"excerpt":"The other day I was answering a question in the PowerShell Facebook group. This person was getting data from Active Directory and trying to organize the results in a way that met his business requirements. My suggestion was to use Group-Object and a custom grouping property. I am assuming you\u2026","rel":"","context":"In &quot;Active Directory&quot;","block_context":{"text":"Active Directory","link":"https:\/\/jdhitsolutions.com\/blog\/category\/active-directory\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/05\/custom-grouping.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/05\/custom-grouping.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/05\/custom-grouping.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/05\/custom-grouping.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":7700,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/7700\/active-directory-objects-and-the-powershell-pipeline\/","url_meta":{"origin":8097,"position":5},"title":"Active Directory Objects and the PowerShell Pipeline","author":"Jeffery Hicks","date":"September 28, 2020","format":false,"excerpt":"This article is something I've been meaning to write for sometime. As often as I tell people PowerShell is easy to use once you understand its core concepts, that isn't always the case.\u00a0 This is a problem my friend Gladys Kravitz brought to my attention some time ago. Like her,\u2026","rel":"","context":"In &quot;Active Directory&quot;","block_context":{"text":"Active Directory","link":"https:\/\/jdhitsolutions.com\/blog\/category\/active-directory\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/09\/Get-bits-revised-ad.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/09\/Get-bits-revised-ad.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/09\/Get-bits-revised-ad.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/09\/Get-bits-revised-ad.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/09\/Get-bits-revised-ad.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8097","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=8097"}],"version-history":[{"count":0,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8097\/revisions"}],"wp:attachment":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=8097"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=8097"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=8097"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}