Tagged: Active Directory Toggle Comment Threads | Keyboard Shortcuts

  • Chris 12:03 am on August 22, 2010 Permalink | Reply
    Tags: Active Directory, Computer Objects,   

    Stale Computer Accounts 

    You know stale computer accounts are like stale peanuts . You just want to get rid of them as fast as possible. Its a good idea to have a script that is scheduled to run for this type of task. The same thing can be said for stale user accounts but let’s focus on the stale computer accounts.

    Here is the script in its entirety :

    Function Process-ComputerObject ($server)
    {

    # set the date to be used as a limit - 180 days earlier than the current date
    $old = (Get-Date).AddDays(-180)

    #Disabled Computers OU
    $DestOU = "contoso.com/disabled Computers"

    #This pipeline creates the report.
    Get-QADComputer -Identity $server.Name -IncludedProperties pwdLastSet -SizeLimit 0 | where { $_.pwdLastSet -le $old }|select-object Name,ParentContainer,OperatingSystem,Description,pwdLastSet |Format-Table -AutoSize| Out-File -Append -Width 700 ".\Disabled_Computers.txt"

    #This pipeline is to actually Disable the server and move it to the disabled computers OU
    Get-QADComputer -Identity $server.Name -IncludedProperties pwdLastSet -SizeLimit 0 | where { $_.pwdLastSet -le $old } |%{ Disable-QADComputer $_ } | %{Move-QADObject $_ -NewParentContainer $DestOU}

    }

    Function Send-EmailReport ()
    {

    #Send Mail message
    send-mailmessage -from "ServerTeam@contoso.com" -to "Supportperson@contoso.com" -subject "180 Day Stale Computer Object Report.**PLEASE DO NOT REPLY**" -body "Please see the following attached text file for Computer objects that were disabled and moved to the disabled computers OU." -Attachments ".\Disabled_Computers.txt" -smtpServer mysmtpserver

    }

    ####################Entry Point of Script##########################

    #Load Quest Cmdlets
    Add-PSSnapin Quest.ActiveRoles.ADManagement

    # No Errors shown
    $ErrorActionPreference = "SilentlyContinue"

    #Builds an Array of Ad Computer Objects and Uses the Quest CmdLets.This is where 2 filters are defined.
    #One that excludes the OU's that we do not want to search and another that defines the Type of Systems we want to search.
    #$Computers is the variable that holds this Array.

    $Computers = Get-QADObject -SizeLimit 0 -SearchScope OneLevel |? {$_.Name -ne "Australia"} | ? {$_.Name -ne "Disabled Computers"} | ? {$_.Name -ne "NetIQRecycleBin"} | % {Get-QADComputer -SearchRoot $_.DN -Includedproperties pwdLastSet -sizelimit 0 -OSName 'Windows 2000 Server*','Windows Server 2003*','Windows Server 2008*'}

    #Start pipeline
    $Computers | %{ `

    #Clear Errors
    $error.clear()

    # Load .net Ping Class Object
    $net = New-Object System.Net.NetworkInformation.Ping

    #perform ping on Server
    $result =$net.send($_.Name)
    if ($Error)
    {

    Process-ComputerObject $_

    }

    }

    #Call the Send-emailmessage function
    Send-EmailReport

    sleep -Seconds 10

    #Delete Text File
    del ".\disabled_computers.txt"

    Now that you see the script let me explain some of the parts .There are 2 functions : one to process the object and another to send an e-mail to the support team that includes a report attached.

    Let’s start at the entry point into the script :

    I’m using the Quest cmdlets which are really easy to work with . So that is what I do first is load the PSnappin.
    Add-PSSnapin Quest.ActiveRoles.ADManagement

    Remember we are going to run this as a scheduled task and want to make sure that the quest ad cmdlets get loaded.

    Next is we do not want errors shown . (I may change this in the future) $ErrorActionPreference = “SilentlyContinue”

    The next part is a bit tricky .We have a variable $computers . What we are doing is creating a list of OU’s we want to exclude. You might not want to search everyOU.

    So we set $computers to get every object on the root level of AD then we build our exclude list : In this case I DO NOT want to search the Australia OU ,Disabled ComputersOU or the NetIQrecyclebin OU.

    The rest of the objects pass thru the pipeline. Now I use the Get-QADComputer cmdlet to get computers (only servers in this case) 2000,2003,2008 Servers . I include the pwdlstset property which I’m interested in.

    Now $computers is set to go … I start my final pipeline ….

    Clear any errors from $error. Load the .net ping class .

    I perform a ping on the System to see if its offline . This is important cause you will find some systems like Cluster Names that might have a stale pwdlast set value but they are very much alive and needed . That might be because they haven’t failed over to the other node in a long time. So I want two conditions met (Not online and pwdlastset greater than 180 days.)

    If not online then I call the process computer object function.

    This function processes the computer object ,disables it if its past 180’s and moves it to the disabled computers OU . I also creates the text file to be used in the report.

    Last but not least I call the mail function which uses the send-mailmessage cmdlet .

    Hope this helps you fight those stale computer objects in your environment. Now where did I put those peanuts again ? 🙂

    Advertisements
     
    • ServerGuyScott 10:55 am on August 22, 2010 Permalink

      Great script, Chris!

    • Joshua 9:08 am on October 23, 2013 Permalink

      I don’t know if you still monitor this or not… but I wanted to ask a couple of questions
      1. Can you modify this to ONLY do computers and not servers
      2. Can you remove the ping option?

  • Chris 12:18 pm on March 24, 2008 Permalink | Reply
    Tags: Active Directory, Home Directories,   

    Doing Some File info gathering in Powershell for Home Directories 

    I haven’t written anything in awhile and I apologize for that . This blog though should be interesting . Have you ever wanted to run a report on lets say How much disk usage your users are using for there home directory or maybe want to echo back the users H drive path from Active Directory . This information can be helpful in many ways . It can verify that the uses home directory path in ad is pointing to the correct path . How do you do this ? Well most likely your users home directory is the name of the User account ID in Active Directory .What you want to do is get all the directories in for example \\servername\homedirs\then go thru each directory name and basically connect to AD to verify Home directory path . You may also want to see if the account is disabled or not . Lets face it all this info is useful . Users come and go they move around so having some kind of reporting is a good thing . You do not need fancy software to do it either which will make your boss happy 🙂 .

    I’m going to show you the full script then talk about it alittle :


    #****************************************************************
    #*ScriptName: Verify-ADUserProfile

    1. *Date : 03/06/2008

    #****************************************************************

    function AdUserProps($UserName,[object]$folder)
    {
    $root = New-Object system.DirectoryServices.DirectoryEntry("LDAP://dc=Microsoft,dc=com")
    $search = New-Object system.DirectoryServices.DirectorySearcher($root)
    $search.Filter = "(&(objectcategory=user)(saMAccountname=" + $UserName+ "))"
    $found = $search.findOne()
    $user = New-Object system.DirectoryServices.DirectoryEntry($found.path)
    $Displayname = $user.Displayname
    write-host ($user.name)"&"($Displayname)"&"($user.HomeDirectory)"&"([int]($folder.Size/$conversion_factor))"&"($user.useraccountcontrol)
    }<Create the conversion factor to make it megabytes
    $CONVERSION_FACTOR = 1048576

    #create a FileSystem Object
    $fsO = New-Object -ComObject ("Scripting.FileSystemObject")

    "UserID&DisplayName&HomeDrivePath&HomeDriveSize&Activeornot"
    ""

    #create the first Pipeline to get the path of all Directories listed
    $homdirs = Get-ChildItem "\\ServerName\homedir$" |?{$_.PsIsContainer} | % {$_.FullName} | % { $folder = $fso.getfolder($_) ;$UserName = $Folder.name; AdUserProps $UserName $folder }

    Now this is not a very hard script it outputs to the screen but you could pipe it to a text file . The text fields are split up by a & character kind of like a comma delimitted file . So you can take the info and import it into excel .

    Lets go thru the script :

    Lets skip the function at the top for now we will get back to it later .

    $CONVERSION_FACTOR = 1048576

    This is a conversion to present the data in Megabytes . Believe me its much easier to look at this way then using bytes .

    #create a FileSystem Object
    $fsO = New-Object -ComObject (“Scripting.FileSystemObject”)

    Here he define our com object (Filesystem) because we want to know the size of the directories . So we instantiate it here so we can use it later .

    “UserID&DisplayName&HomeDrivePath&HomeDriveSize&Activeornot”
    “”

    This is top line of the text file . Kind of like a header file for the excel sheet . You notice that it is broken up with the & character to easily import it into excel later .

    #create the first Pipeline to get the path of all Directories listed
    $homdirs = Get-ChildItem “\\ServerName\homedir$” |?{$_.PsIsContainer} | % {$_.FullName} | % { $folder = $fso.getfolder($_) ;$UserName = $Folder.name; AdUserProps $UserName $folder }

    This is the bread and butter . (Note : this is one pipeline . One Line . Sorry for the formatting . ) Lets take a close look at this pipeline .

    We have our variable $homdirs = get-childitem . We get all the files and folders under our path \\servername\homedir$ .Notice that I didn’t use recursive because I’m not worried about sub-directories . This gets piped | to ?{$_.PsIsContainer} which gets only the directories. This goes into a foreach-object (%) pipe to get the Fullname which is the Full Path . The next bit is interesting . I make $folder variable = to our $fso which remember is our Filesystem object . I use the getfolder method which we will use when we call our function later . Now the next part doesn’t get piped $UserName = $Folder.name . (I will have to look at this again but because it may seem like I’m creating the same thing over again but basically we are creating the 2 variables $Folder and $username which we will call the function AdUserProps) .

    This function returns all the info we are looking for . Now there are many ways to connect to Active directory . you can use the way you feel most comfortable . I use the LDAP method but you can use Quests AD cmdlets too .

    $root = New-Object system.DirectoryServices.DirectoryEntry(“LDAP://dc=Microsoft,dc=com”)
    $search = New-Object system.DirectoryServices.DirectorySearcher($root)
    $search.Filter = “(&;(objectcategory=user)(saMAccountname=” + $UserName+ “))”
    $found = $search.findOne()
    $user = New-Object system.DirectoryServices.DirectoryEntry($found.path)
    $Displayname = $user.Displayname
    write-host ($user.name)”&;”($Displayname)”&;”($user.HomeDirectory)”&;”([int]($folder.Size/$conversion_factor))”&;”($user.useraccountcontrol)

    What us happening here is I’m conneting to the root of the domain and searching for the Username that I passed in . Remember we don’t know where these users are in AD . Once I find the User name I display its userID ($user.name) , the Display Name $user.Displayname,Users Home directory $user.HomeDirectory

    int]($folder.Size/$conversion_factor — here is where we use the $folder variable to figure out what size the Directory is .

    $user.useraccountcontrol — Last but not least if the account is Disabled or not . 512 is Active , A 514 is disabled .

    Thats the gist of it . I hope this gives you some idea’s on how to account for Homedirectories . Lets face it Cleanup is not a fun part of the Job but if you are able to get some info it could help lead you in the right path .

    Hope this helps !

    Chris

     
    • halr9000 4:32 pm on March 26, 2008 Permalink

      Chris, did you know you can just use ‘1MB’ as a constant for the conversion factor? Works for kb, and gb as well.

      -hal

    • Chris 1:19 pm on March 27, 2008 Permalink

      Thanks Hal

      Chris

  • Chris 11:25 am on January 11, 2008 Permalink | Reply
    Tags: Active Directory, , Output   

    Binding to Active Directory in C# 

    Geez I haven’t had a lot of time to blog in awhile .  I wanted to quickly put something down about how to connect to active directory using C# . If you do a search Google you will see a Ton of posts,blogs about the subject . As you can find out that there is an issue with returning a users groups . That being that you will not get the primary group (usually Domain users ) . This also affects Group membership too . The reason is because the ‘memberof’ attribute doesn’t contain primary group . So what you must use is Token groups . For me this is very confusing . Since the token groups attribute is not present by default you have to use the user.refreshcache() method .

    I found another way to do this . By using this assembly from the 3.5 framework called System.DirectoryServices.Accountmanagement .

    I will give an example this weekend but do a search in google . This solves the issue of missing users in groups and lists all groups a user is a member of .

    Bye for now .

    Chris

     
  • Chris 2:04 pm on December 29, 2007 Permalink | Reply
    Tags: Active Directory,   

    Binding to an Active Directory Object with PowerShell 

    I wanted to talk about a powershell script I wrote recently . I work as a systems administrator at a large company so scripting is a necessity of life . Fortunately we have a powerfull Shell to work with POWERSHELL . I really like it because it allows for some great flexibility to do different things . If you haven’t worked with Powershell yet you might want to take a look at it . It kind of reminds me of Perl .

    So let me get right to it . First off you need a good editor if you want your scripts to look good . May I recommend PowerGui . Their editor is free and has tons of features . Did I mention its free ?

     So now the script that I wrote basically changes the primary group of a User in Active Directory . We had some users that didn’t have Domain Users as there primary group which was causing issues . So I put together a script that changes this attribute .

    I will display the Script then walk you thru it :

    1. *********************************************************************
    2. * NAME:PrimaryGroup.ps1
    3. * Description:Change the primary Group for a user in Active Directory
    4. * Created by : Chris Federico
    5. * Date 12/06/07
    6. *********************************************************************

    #Create a variable and add the contents of Userlist.txt to it
    $UserList = Get-content ".\UserList.txt"
    $LogFile = "Logfile.txt"

    1. Create our Log File for This Script

    $CreateLogFile = New-Item -Path . -Name "$LogFile" -type "File" -force

    1. Step thru the array

    foreach ($User in $UserList) {

    1. Bind to each User Account

    $User = [adsi] "ldap://cn=$User, OU=Users, dc=Microsoft,dc=local"

    #Display the Current User
    Add-Content -path $LogFile -value ($user.name)

    #create a variable that holds the value of the primaryGroupID
    $primaryGroupID = $User.primaryGroupID

    1. Display the Currentprimary Group ID

    Add-Content -path $LogFile -value ("Current PrimaryGroupID = $primaryGroupID")

    if ($user.primaryGroupID -ne '513'){

    1. Change the Property

    $User.primaryGroupID = '513'

    1. Commit the Changes to AD

    $User.CommitChanges()

    1. Display After Change

    Add-Content -Path $LogFile -Value (" Verification of change = $primaryGroupID")
    Add-Content -Path $LogFile -Value ("")
    }
    else
    {
    Add-Content -Path $LogFile -Value ("The Primary Group is Domain Users already ")
    Add-Content -Path $LogFile -Value ("")
    }
    }

    If your new to programming this script may seem daunting but I tried to comment it as much as possible . You will notice that comments are shown with the # in front . The same way you would comment a host file . I’m sure you have hear that you can never comment to much when your scripting .

    Before you begin get a list of users that you want to check or fix their primary Group . You can do this by exporting a list of users from “Users and Computers ” mmc . Once you have this list save it as UserList.txt (you can save it any name you like as long as you reference it correctly ) .

    Start by creating and Array by getting the content of your User List


    #Create a variable and add the contents of Userlist.txt to it
    $UserList = Get-content ".\UserList.txt"

    I also like to create a log file and that is just what I’m doing here:

    1. Create our Log File for This Script

    $CreateLogFile = New-Item -Path . -Name "$LogFile" -type "File" -force

    Next we are going to step thru the array of user names with a For each command like this : (This looks exactly like its done in Perl)


    foreach ($User in $UserList) {

    Inside the For Each loop you are going to Bind to each user .

    1. Bind to each User Account

    $User = [adsi] "ldap://cn=$User, OU=Users, dc=Microsoft,dc=local"

    What’s going on here is its reading ,for example,the first user in the list ($User) holds that name . It makes an LDAP connection and binds to it . When you bind to an object you get access to all the attributes of the user as we will see in a bit . You can also use the .net framework to bind to a user . I believe you would use some thing like System.DirectoryServices.Directoryentry (“LDAP://Your AD Path”). Now you can get errors if say there is no object found or you do not have rights .

    Next I’m displaying the Current User

    #Display the Current User
    Add-Content -path $LogFile -value ($user.name)

    Notice I’m using the name property . This is being written to that logfile we created . Everything that gets written gets appended to the text file .

    Next I want to create a variable that will hold the value of the primary Group and display the users current Primary Group . The primary group property doesn’t display name but it displays a number . Nothing to fear though .


    #create a variable that holds the value of the primaryGroupID
    $primaryGroupID = $User.primaryGroupID

    1. Display the Currentprimary Group ID

    Add-Content -path $LogFile -value ("Current PrimaryGroupID = $primaryGroupID")

    Domain users group ID number is 513.So the next section checks to see if the current users primary group Id is equal to 513 . If it is then it prints out that they are already have their group set . If it doesn’t it sets the value . All of this gets appended to a text file .


    if ($user.primaryGroupID -ne '513'){

    1. Change the Property

    $User.primaryGroupID = '513'

    1. Commit the Changes to AD

    $User.CommitChanges()

    1. Display After Change

    Add-Content -Path $LogFile -Value (" Verification of change = $primaryGroupID")
    Add-Content -Path $LogFile -Value ("")
    }
    else
    {
    Add-Content -Path $LogFile -Value ("The Primary Group is Domain Users already ")
    Add-Content -Path $LogFile -Value ("")
    }
    }

    The only problem that I came across was users that didn’t belong to the domain users group obviously that is a problem . I was able to do 100’s of users in about 10 to 15 minutes .I hope that you enjoy this blog . I hope that this helps someone trying to work with active directory . Overall powershell is here to stay and I can see that it is very powerful .

     
    • Chris Federico 2:09 pm on December 29, 2007 Permalink

      I’m just noticing how awful the code is looking while I pasted it in between the tags . I can attach the script if anyone wants to see it .

    • sandrar 8:43 am on September 10, 2009 Permalink

      Hi! I was surfing and found your blog post… nice! I love your blog. 🙂 Cheers! Sandra. R.

    • Chris 11:30 am on September 10, 2009 Permalink

      @Sandra

      Thank you 🙂

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel