{"id":3035,"date":"2013-08-15T00:01:00","date_gmt":"2013-08-15T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/08\/15\/use-powershell-to-log-changes-to-ad-ds-attributes\/"},"modified":"2013-08-15T00:01:00","modified_gmt":"2013-08-15T00:01:00","slug":"use-powershell-to-log-changes-to-ad-ds-attributes","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-log-changes-to-ad-ds-attributes\/","title":{"rendered":"Use PowerShell to Log Changes to AD DS Attributes"},"content":{"rendered":"<p><strong>Summary<\/strong>: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to log changes made to Active Directory Domain Services attribute values.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" alt=\"Hey, Scripting Guy! Question\" \/>&nbsp;Hey, Scripting Guy! We are in the process of merging a couple of resource domains, and we need to modify some user accounts prior to the move. I have been tasked with making the changes, and I plan to use Windows PowerShell to perform the actual work. I need to create before and after logs. The before log shows the value of the attributes that I am going to change prior to running the script, and the after log will show the value of the attributes after running the script. Can you show me how I might go about doing this? Thanks, Scripting Guy, you are the best!<\/p>\n<p>&mdash;CX<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" alt=\"Hey, Scripting Guy! Answer\" \/>&nbsp;Hello CX,<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sitting on the lanai, and sipping a cup of English Breakfast tea. I put a bit of lemon grass, hibiscus flower, rose hips, spearmint, and a cinnamon stick in the tea. The flowers give it a citrus flavor, and the mint makes it very refreshing. The trick is that I only let it steep for three minutes, and that keeps it from becoming too bitter. It took me several tries to get this one just right. Because it is pretty early, it is not too hot or humid outside yet. I have my Surface&nbsp;RT, and am checking my <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a> email.<\/p>\n<p>So, CX, you did not specify how you want your logging to take place, but I decided that exporting to a CSV file would work out well. Then you could import it into Microsoft Excel if you want to do so.<\/p>\n<h2>Finding the attribute and values<\/h2>\n<p>The first thing to do is to create a little script that will populate an attribute with before values. I am going to populate the Post Office Box attribute, so I need to look it up in ADSI edit. I come up with the following (surprisingly, it is named <strong>postOfficeBox<\/strong>):<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0172.HSG-8-15-13-01.png\"><img decoding=\"async\" title=\"Image of menu\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0172.HSG-8-15-13-01.png\" alt=\"Image of menu\" \/><\/a><\/p>\n<p>I write a little script to add values to this attribute. Here is the script:<\/p>\n<p style=\"padding-left: 30px\">Import-Module activeDirectory<\/p>\n<p style=\"padding-left: 30px\">$ou = &#8220;ou=testou,dc=iammred,dc=net&#8221;<\/p>\n<p style=\"padding-left: 30px\">$i = 1<\/p>\n<p style=\"padding-left: 30px\">Get-ADUser -Filter * -SearchBase $ou |<\/p>\n<p style=\"padding-left: 30px\">ForEach-Object {<\/p>\n<p style=\"padding-left: 30px\">Set-ADUser $_ -POBox &#8220;Post Office Box $i&#8221;<\/p>\n<p style=\"padding-left: 30px\">$i++ }<\/p>\n<p>Now I want to see how many different cities are represented by the users in the organizational unit (OU). I modify my script a bit and use the <strong>&ndash;Unique<\/strong> parameter from the <strong>Select-Object<\/strong> command. This is shown here:<\/p>\n<p style=\"padding-left: 30px\">Get-ADUser -Filter * -SearchBase $ou -properties $properties | select l -Unique<\/p>\n<p>The following output tells me that I have three cities: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Atlanta&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Charlotte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Jacksonville&nbsp;&nbsp;<\/p>\n<p>Therefore, I need to add a bit of logic to detect the city. If the city is Atlanta, I will set the <strong>postOfficeBox <\/strong>attribute to 222; if it is Charlotte, I will set it to 333; and if it is Jacksonville, I will set it to 444.<\/p>\n<h2>Making the changes<\/h2>\n<p>The first thing I do is use the <strong>Get-ADUser<\/strong> cmdlet to return the user name and the <strong>postOfficeBox<\/strong> attribute. I use the <strong>Select-Object<\/strong> cmdlet to get these two attributes, and I pipe the output to <strong>Export-CSV<\/strong>. No problem&hellip;until I open the spreadsheet in Excel. Here is the results:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0550.HSG-8-15-13-02.png\"><img decoding=\"async\" title=\"Image of spreadsheet\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0550.HSG-8-15-13-02.png\" alt=\"Image of spreadsheet\" \/><\/a><\/p>\n<p>The issue is that for some reason, the <strong>postOfficeBox<\/strong> attribute is a collection. I therefore modify my script a bit, and I select the first PO Box. Here is the script:<\/p>\n<p style=\"padding-left: 30px\">Import-Module activeDirectory<\/p>\n<p style=\"padding-left: 30px\">$ou = &#8220;ou=testou,dc=iammred,dc=net&#8221;<\/p>\n<p style=\"padding-left: 30px\">$Before = &#8220;c:\\fso\\before.csv&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">$properties = &#8220;PostOfficeBox&#8221;<\/p>\n<p style=\"padding-left: 30px\">Get-ADUser -Filter * -SearchBase $ou -properties $properties |<\/p>\n<p style=\"padding-left: 30px\">Select name, @{L=&#8217;pobox&#8217;;E={$_.postofficebox[0]}} |<\/p>\n<p style=\"padding-left: 30px\">Export-Csv -Path $before -NoTypeInformation -Force<\/p>\n<p>Now I open the script in Excel, and it appears like I expected:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2744.HSG-8-15-13-03.png\"><img decoding=\"async\" title=\"Image of spreadsheet\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2744.HSG-8-15-13-03.png\" alt=\"Image of spreadsheet\" \/><\/a><\/p>\n<p>So now I use the <strong>Get-ADUser<\/strong> cmdlet to retrieve my user objects. I pipe everything to a <strong>Foreach-Object<\/strong> cmdlet, and I use a <strong>Switch<\/strong> statement inside the <strong>Foreach-Object<\/strong>. I read a <strong>Switch<\/strong> statement like a series of <strong>If <\/strong>statements, for example: If the city matches Atlanta, then I set the POBox variable to 222.<\/p>\n<p>I then use the <strong>Set-ADUser<\/strong> cmdlet inside the <strong>Foreach-Object<\/strong> cmdlet to make the actual changes. Here is the script:<\/p>\n<p style=\"padding-left: 30px\">Import-Module activeDirectory<\/p>\n<p style=\"padding-left: 30px\">$ou = &#8220;ou=testou,dc=iammred,dc=net&#8221;<\/p>\n<p style=\"padding-left: 30px\">$properties = &#8220;l&#8221;,&#8221;PostOfficeBox&#8221;<\/p>\n<p style=\"padding-left: 30px\">Get-ADUser -Filter * -SearchBase $ou -properties $properties |<\/p>\n<p style=\"padding-left: 30px\">ForEach-Object {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Switch ($_.l)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;{ &#8220;Atlanta&#8221; {$pobox = &#8220;POBox 222&#8221;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; &#8220;Charlotte&#8221; {$pobox = &#8220;POBox 333&#8221;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; &#8220;Jacksonville&#8221; {$pobox = &#8220;POBox 444&#8221;} }<\/p>\n<p style=\"padding-left: 30px\">Set-ADUser $_ -POBox $pobox<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>Now I run my documentation script again and open the Excel spreadsheet. I can see that the changes took place as expected. Cool.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6523.HSG-8-15-13-04.png\"><img decoding=\"async\" title=\"Image of spreadsheet\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6523.HSG-8-15-13-04.png\" alt=\"Image of spreadsheet\" \/><\/a><\/p>\n<p>CX, that is all there is to using Windows PowerShell to make changes to AD&nbsp;DS attribute values and to log the changes. Active Directory Week will continue tomorrow when I will talk about different ways of working with Active Directory.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to log changes made to Active Directory Domain Services attribute values. &nbsp;Hey, Scripting Guy! We are in the process of merging a couple of resource domains, and we need to modify some user accounts prior to the move. I have been tasked with making [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[7,3,20,45],"class_list":["post-3035","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-scripting-guy","tag-user-accounts","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to log changes made to Active Directory Domain Services attribute values. &nbsp;Hey, Scripting Guy! We are in the process of merging a couple of resource domains, and we need to modify some user accounts prior to the move. I have been tasked with making [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3035","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\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=3035"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3035\/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=3035"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=3035"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=3035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}