PowerShell Remove Disabled Users From All Groups

As a follow up to my PowerShell Update Accounts from Multiple Domains post I needed to find a way to remove the student accounts which were in a non-active status from all security/distribution groups.  Each student may be in groups from multiple domains as well as the resource domain so each had to be addressed.  To do this I created a function to handle locating the group and using a switch statement to assign the domain controller to use for that particular group.

Let’s walk through it starting with the function:

Function GetGroup

{

Since the function is called during the meat and potatoes of the script for each domain, it will be passed data and therefore build an array of groups each user is a member of

$userGrps = $other.memberOf

Then for each group in that array, the global catalog is queried to pull the distinguishedName for each

foreach($grp in $userGrps)

{

$UADGroup = Get-ADGroup -Identity $grp -Server servername.dc.dc:3268 -Properties distinguishedName

$UADGroup | ForEach-Object -Process {

$DNGroup = $UADGroup.distinguishedName

} #end foreach-object

A switch statement using a wildcard is used to assign a domain controller for the domain each group belongs

switch -Wildcard ($DNGroup)

{

“*,OU=Groups,DC=XX,DC=XX” {$server = “servername.xx.xx”}

“*,DC=Child1,DC=XX,DC=XX” {$server = “servername.child1.xx.xx”}

“*,DC=Child2,DC=XX,DC=XX” {$server = “servername.child2.xx.xx”}

} #end switch

Then using each group with a usable domain controller, the remove-adgroupmember is used to remove the users in the $other array based on their group memberships in the $grp array.  If it is unable to remove the user it will print to the console the user’s DN and group to be removed from and the server that was attempted to troubleshooting.

Try

{

$grp | Remove-ADGroupMember -Members $other -Server $server -Confirm:$false

} #end try

Catch

{

Write-Host “Cannot remove $other from $UADGroup on $server”

} #end catch

}

Since this function will be called multiple times, we clean up the variables

$userGrps = $null

$DNGroup = $null

$UADGroup = $null

} #end Function

Now we will query Active Directory for any account in each domain using the ‘Title’ attribute.  You can use any filter to pull a certain subset of accounts but this is what was required for me.  We will also call the function, disable the account and move it to a specific organization unit.

#begin

$otherUsers = get-aduser -filter {((Title -eq “Drop”) -or (Title -eq “Cancel”) -or (Title -eq “Back Out”) -or (Title -eq “Suspension”)  -or (Title -eq “Leave of Absence”))} -Properties * -server Child1.XX.XX.XX -SearchBase “OU=Students,DC=XX,DC=XX,DC=XX”

foreach ($other in $otherUsers)

{

GetGroup($other)

disable-adaccount -identity $other

move-adobject -identity $other -targetpath “OU=DisabledUsers,DC=,DC=XX,DC=XX”

}

write-host “Resetting otherUsers”

$otherUsers = $null

Repeat that block of code for each domain in the forest starting at #begin

Powershell to Update Accounts in multiple domains

I have been searching and searching through articles and blogs and discussion forums for a way to accomplish my latest endeavor, a way to extract information from our student information system and populate the matching Active Directory accounts.

The issue I have run into from all of the aforementioned electronic stops is the fact that our forest has 18 domains.  Finding an easy way to update the accounts in one CSV file to an account which can be in any domain at any time has been quite a challenge.  However, I finally figured out a way that worked for me and thought I would share as I have not been able to find anything in the past four months that did the job in one swoop.

First off I setup my Windows 8 workstation by enabling the PowerShell 3.0 ISE 64bit console and the windows SQL Server 2008 R2 client tools.  The workstation is also located on a subnet which can access not only the SQL server of the SIS database but also one domain controller for every domain in our forest.  I was also provided with an account to the database which has the permission to read the tables for the data I need to extract and an account which has the ability to update all student Active Directory accounts.

I know this may sound IT101 but for those just stepping into these shoes, every little bit of knowledge which may be obvious to those of us seniors in the game is not to those just learning to walk.  And the one thing I have learned in the 13 years in this business is to never assume others know anything.

Once the workstation that will be running the script is all set and tested, open the 64bit ISE console.

First we must be able to make a connection to the SQL server and Active Directory.

import-module ActiveDirectory                                                                                         Add-PSSnapin SqlServerCmdletSnapin100                                                                 Add-PSSnapin SqlServerProviderSnapin100

Next we enter the t-sql used to query the SIS database and then export it to a CSV file (note: going into the sql code required for this is beyond this post)

$SQLquery =@”        

SQL code here                                                                                                                    “@ 

$result = invoke-sqlcmd -query $SQLquery -serverinstance “servername” -database dbname                                                                                                                          

$result | export-csv “C:\PSScripts\Update_Students.csv” -notypeinformation

Next we will import the CSV file and set the script to create a log file to review errors after the script completes.

$SyIDOutputFile = “C:\PSScripts\UpdateReport.log”                                                   $upn = import-csv “C:\PSScripts\Update_Students.csv”

Now that we’ve completed the setup, let’s get down to business.  We will setup the loop to handle each account in the CSV file and do some work.  Instead of throwing all at you at once, I’m going to continue to break it down so you will know what each line is actually doing.  This should make it easier for you to take this script and make it your own.

We create the ‘foreach’ loop then cycle through each line in the CSV file pulling the information we will need to use and setting it to a variable.

foreach ($u in $upn)                                                                                                                {                                                                                                                            $emailAddress = $u.email                                                                                           $stuNum = $u.StuNumber                                                                                       $empNumber = $u.StudentID

Now let’s query the Global Catalog for each student in the CSV file and pull the distinguished name attribute and assign to a variable.

$ADUser = get-adobject -Filter {mail -like $emailAddress} -server servername:3268 -Properties distinguishedName | select-object -property distinguishedName

$ADUser | ForEach-Object -process                                                                                   {                                                                                                                                            $dn = $ADUser.distinguishedName

Now we will need a Switch statement for each domain.   We will use a wildcard since the distinguished name for each user will contain the domain name but they may be in different organization units.  I have only included two entries below but you would need a statement for each domain in your forest.  You can also include other variables with each statement that pertains to that domain such as a specific display name, department, etc.  You are populating LDAP attributes and no longer just the ones available to the Global Catalog so the list is long of what you can include.  For simplicity we are just including the server which is needed to update that student account.

switch -Wildcard ($dn)

{

“*,DC=X1,DC=X,DC=X” {$server = “child1.X1.X.X”}

“*,DC=X2,DC=X,DC=X” {$server = “child2.X2.X.X”}

} #end switch

Now let’s take all of the information we have gathered and either update the account or write to the log file that it cannot be done listing the distinguished name reported and the server that was tried.  This should help troubleshoot those that could not be updated.

Try{

set-aduser -Identity $stuNum -employeeNumber $empNumber -server $server

Write-host “$stuNum $emailAddress will be set to $empNumber on $server”

} #end Try

Catch

{

write-warning “$stuNum does not exist on $server to be updated as $dn”

Out-File -FilePath $SyIDOutputFile -InputObject (“$stuNum does not exist on $server to be updated as $dn”) -Encoding UTF8 -append

}#end Catch

}#end foreach-object

}# end foreach

Now let’s send the log file to our account managers to review any errors that occurred during the script

write-host “End of Active Directory Updates”

#Send Log File via email

$SmtpServer = “enter ip address of smtp relay server”

$Smtp = New-Object Net.Mail.SmtpClient($SmtpServer)

$SmtpFile = New-Object Net.Mail.Attachment($SyIDOutputFile)

$SmtpMsg = New-Object Net.Mail.MailMessage

$SmtpMsg.From = “enter address to send email from”

$SmtpMsg.To.Add(“enter email address to send log to”)

$SmtpMsg.Subject = “Student Update Log”

$SmtpMsg.Body = “Attached is the latest student update log.”

$SmtpMsg.Attachments.Add($SmtpFile)

$Smtp.Timeout = “30000”

$Smtp.Send($SmtpMsg)

Lastly, let’s clean things up

#Clean up

$SmtpFile.Dispose()

remove-item “C:\PSScripts\Update_Students.csv”

remove-item “C:\PSScripts\UpdateReport.log”

And that’s it.  Now I do like to give credit where it is deserved.  The email portion which sends the log file I found in the Technet blogs from Roman Zarka pertaining to Office 365.  But it works regardless of what the script does and I have used it many times over.

I hope this will help the many I read entries from looking for the same solution.

Shibboleth: The Journey Begins

ShibboWhat?

It is quite comical to listen to the folks around me discuss this service.  I know when I first saw it come across my screen several years ago I was a little hesitant to speak it in front of others.  So true to form, I google’d it (funny how this is now a verb in popular vernacular) and learned the correct pronunciation prior to a meeting.  Some attendees slid in a ‘w’ and some were no where close so I would not have been alone in my verbal hiccup.

However, I am that person.  I hate to participate in a conversation and not be fully prepared.  So for the meeting in question I not only learned the correct way to say Shibboleth but also researched what it did, how it worked and what else was available that provided the same functions.  I came across Active Directory Federation Services 1.0 at that time and being a Microsoft shop leaned more in that direction.  That of course led us to finally adopting ADFS v2 in 2012.

The test has been with other third party vendors not quite ready to easily interoperate with ADFS.  In my limited experience it seems that if you have the ability to except SAML tokens it should work, but it stills baffles a few developers, therefore in response I decided to put up a Shibboleth IDP (identity provider) server.  As this was quite the experience, I thought I would share and hopefully save someone else from needless hours of aggravation.

First I went to Internet2’s web source and reviewed the install documentation.  Two ways, ok not uncommon.  I then did a search for forums where others went through the process to see what they did.  I came across a few more ways.  There were several web server applications to chose from and one blog even used both Tomcat and Microsoft’s IIS.  So which did I pick?  Any and all that would work on Windows 2008 R2.

I started with the blog centered around Tomcat 6 and IIS.  I could get the default IIS page on port 80 but 443 rendered nothing and yes I did bind the certificate.  I could get the Tomcat default page on 8080 but 8443 again rendered blank.  I did try this process twice using the directions provided then scrapped it.

I then decided to start over using IIS and Tomcat but using the quick installer.  Nothing worked.  Blank all the way.  Bust number two.

Next I decided to use the instructions on Internet2 and installed Tomcat first then ran the Shib installer.  Tomcat default page rendered on 8080, 8443 was blank and the Shib pages on 443 were frustratingly absent again.

Finally I just decided to run the quick installer by itself after uninstalling IIS and Tomcat.  At this point I had installed and uninstalled IIS, Shibboleth and Tomcat approximately four times.  I was very confused and could not quite figure out the issues causing all of the other trials to fail.  Low and behold, however, just running the quick installer seemed to be the trigger.  I was finally able to go to the next steps and test it out.

Using the test service provider listed in the Internet2 documentation it just worked.  I was so relieved after hours of installs and uninstalls.  I’m not usually a pusher of the quick anything, but I must say this one just worked and I would recommend this method to anyone.

Once my initial testing worked, I had those in the department try it out in different browsers.  Everything still seemed to be moving forward.  Since I have the service using the global catalog it just as easily authenticated users in other domains within our large complex forest.  The only complaint I received was the untrusted certificate.  I thought, “I can deal with that quickly”.  As it turned out, not as quickly has I initially believed.

I had to figure out exactly what a keystore was, how it really worked, how it was accessed, what formats it could be, and how to use a wildcard that is stored as a pfx file.  Remember, I work for a Microsoft based shop and had always used the management console.  This was tons of fun also.  But after about eight hours start to finish I finally had a complete Shibboleth IDP server with a third party issued wildcard certificate.  A deep breath was in order.

So today I began working on the look of the sign-on page.  I needed to make it match exactly to our ADFS authentication form.  I really have not worked much with jsp pages but CSS is CSS and luckily this was not too difficult.

So what challenges still lay ahead for me?  Making ADFS and the Shibboleth server use the same authentication method so users do not have to type domain\username in one and just their user ID in the other.  But that’s tomorrows problem.

A Singularity Worth The Trouble

As a woman with many hats, why would I want to add to the rack?  To grab a star for the top.  I love my work.  I love making others tasks easier.  This means we offer almost quarterly new services to make their jobs more efficient.  Other than service management for us, what’s the biggest downside to this rapid growth?  The number of accounts our users must remember in order to access these great new awesome services.

This has become a big concern over the past couple of years for which I have invested a little of my limited time during this period into federation and single sign-on education.  The more I’ve read, the more I’ve wanted to dive deep into this subject.  And I am happy to report that with the upgrade for our Live@EDU domains to Office 365 for Education, this gave me the career in I desperately seek.

It allowed me to attend TechED 2012 and a pre-conference for Sharepoint and Federated login with Active Directory Federation Services.  The presenter was great and very knowledgable on this subject.  I was even able to contact him via email a few weeks later with a question for which he responded.  This actually surprised me and made me respect him that much more.  Just shows there are a few of us left in the industry that willingly lend a hand to help others pursue their passions in the IT field.

Within a few weeks of the conference, I had our ADFSv2 environment all setup, tested and ready to go.  I must admit deploying with the Office 365 trial tenant was very easy.  The steps are well documented and their support was awesome.  I enjoyed this so much that I centered my Masters thesis project around federating accounts and the security behind it.

Now as a company we are looking to move more of our services into this realm which has provided me with the opportunity to learn more about Windows Identity Foundation and the protocols involved with federating identities and providing single sign-on to our users.

I am also diving into online communities and volunteering my time to work on projects surrounding this technology to hopefully work on advancements, learn even more and help others just getting started with their own solutions.

This may be a lot of work and a lot of invested time on my part, but knowing that the ability to allow our users to access disparate systems using a single company managed account instead of dozens of different portals is well worth the time spent.