Archive for the ‘ Active Directory ’ Category

Find orphaned accounts in Active Directory

As an administrator I would of course never forget to delete a computer account ;) , but if someone else should forget it quite a lot of orphaned accounts would exist in the Active Directory over time. So how would one detect accounts that hasn’t been used for a while? Well, again the answer is PowerShell. With this simple, little script below you are able to choose the age of the accounts you want displayed. Of course you could easily edit the script so it deleted the accounts right away by using Remove-QADObject. You could also use the Get-QADUser cmdlet to search for user accounts instead of computer accounts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Add-PSSnapin -name Quest.ActiveRoles.ADManagement
 
$searchRoot = "domain.local/Workstations"
$age = 60 # in days
 
$accounts = Get-QADComputer -IncludedProperties LastLogonTimeStamp -SearchRoot $searchRoot | Sort-Object -Property LastLogonTimeStamp -Descending
$today = Get-Date
 
foreach( $account in $accounts )
{
    if( $account.LastLogonTimeStamp -eq $null )
    {
        Write-Host $account.Name "last logon: Never"
    }
    else
    {
        $res = $today - $account.LastLogonTimeStamp
        $days = $res.Days
 
        if( $days -gt $age )
        {
            Write-Host $account.Name "last logon:" $days "days ago"
        }
    }
}

Extract Operating Systems from Active Directory

Prerequisites: ActiveRoles Management Shell for Active Directory must be installed on the host running this script.

On a forum I saw someone in need of a script that could display the operating systems of all the computers in Active Directory. Also it could help when you have to tell Microsoft how many licenses you need to pay for. This is an easy one so why not? :)

First I want to load the snappin so I don’t have to open the ActiveRoles Management Shell everytime I want to run the script.

Add-PSSnapin -name Quest.ActiveRoles.ADManagement

Next I’m going to fetch all computer accounts from Active Directory. For that I’m using the ‘Get-QADComputer’ cmdlet. You can add the attribute ‘-SearchRoot’ if you don’t want to search the entire Active Directory.

'Fetching computer accounts from Active Directory. This may take a while...'
$computers = Get-QADComputer | Sort-Object Name
'' + $computers.length + ' computer accounts fetched from Active Directory.'
'-----------------------------'

The abvious thing to do now is to run through the computers array and check their operating system, but I need a structure to save the statistics. For that I’m going to use a hashtable. In that way I will be able to use the name of the operating system as the key. First I declare the hashtable.

$stats = @{}

And then I collect the stats.

foreach( $computer in $computers )
{
    $OSName = $computer.OSName
   
    if( $OSName -eq $null )
    {
        $OSName = "Unknown OS"
    }
   
    $stats[$OSName]++

    #$computer.Name + "`t" + $computer.OSName + "`t" + $computer.OSVersion
}

As I run through the array I’m checking to see if the operating system value is $null. This is the case for e.g. the virtual names of a cluster service. I’m just going to list those as an unknown operating system. The physical nodes themselves will have the operating system property set. You can uncomment the last line if you want to display information about every single computer account.

That last thing to do is to display the collected statistics. You can just echo the $stats array, but if you want to sort the output you need to use ‘GetEnumerator()’.

You should get an output similiar to this:

Name                           Value                                          
----                           -----                                          
Windows Vista™ Ultimate        1                                              
Windows 7 Ultimate             1                                              
Windows 2000 Server            2                                              
Windows Server® 2008 Enterp... 3                                              
Windows 7 Professional         3                                              
Windows Server® 2008 Standard  6                                              
Windows Vista™ Business        9                                              
Windows Vista™ Enterprise      11                                             
Windows 7 Enterprise           11                                             
Unknown OS                     24                                             
Windows 2000 Professional      26                                             
Windows Server 2003            52                                             
Windows XP Professional        321                                            

Please note that Windows Server 2003 isn’t devided into several categories like Windows Server 2008. So you don’t know how many is Standard or Enterprise Edition.

Here’s the entire script: Display Operating Systems

Bulk Attribute Change of Users in Active Directory

Prerequisites: ActiveRoles Management Shell for Active Directory must be installed on the host running this script.

As mentioned in my post “Detect Orphaned HomeDirectories and Roaming Profiles” I was given the task to migrate data from one file server to the other. Since the paths to homedirectories and roaming profiles would change I needed to come up with a solution to change the paths of hundreds of users. Of course the solution would be a powershell script.

First I want to load the snappin so I don’t have to open the ActiveRoles Management Shell everytime I want to run the script.

Add-PSSnapin -name Quest.ActiveRoles.ADManagement

Next I want to fetch the users from Active Directory. This is done with the ‘get-QADUser’ cmdlet.

$users = Get-QADuser -SearchRoot 'mydomain.local/Users' -SizeLimit 0 | Sort-Object Name

This will return an array of all the users in the searchroot (it also searches in subcontainers). I’m piping the result to the ‘Sort-Object’ cmdlet as I want to sort the array by the names of the users.

Now that the users have been fetched from Active Directory all that is left to do is to run through the array, change the different paths, and commit the changes to Active Directory.

for( $i = 0; $i -lt $users.length; $i++ )
{
    $oldHomeDirectory = ""
    $oldProfilePath = ""
    $oldTsHomeDirectory = ""
    $oldTsProfilePath = ""

    $user = $users[$i]

    if( $user.HomeDirectory -ne $null ) # only if HomeDirectory is filled in
    {
        $oldHomeDirectory = $user.HomeDirectory
        $user.HomeDirectory = $user.HomeDirectory -replace "\\\\server01\\homedirectories\$", \\server02\homedirectories$
    }
    if( $user.ProfilePath -ne $null ) # only if ProfilePath is filled in
    {
        $oldProfilePath = $user.ProfilePath
        $user.ProfilePath = $user.ProfilePath -replace "\\\\server01\\profiles\$", \\server02\profiles$
    }
    if( $user.TsHomeDirectory -ne $null ) # only if TsHomeDirectory is filled in
    {
        $oldTsHomeDirectory = $user.TsHomeDirectory
        $user.TsHomeDirectory = $user.TsHomeDirectory -replace "\\\\server01\\homedirectories\$", \\server02\homedirectories$
    }
    if( $user.TsProfilePath -ne $null ) # only if TsProfilePath is filled in
    {
        $oldTsProfilePath = $user.TsProfilePath
        $user.TsProfilePath = $user.TsProfilePath -replace "\\\\server01\\tsprofiles\$", \\server02\tsprofiles$
    }
    ...
}

The loop runs through the array and does a ‘search and replace’ on the user attributes I want to change. If you want to change anything else, here’s where you want to add it. Just type “get-QADUser -?” to see all the attributes you can change. Also I’m saving the paths in a new set of variables before I change them. The only reason for this is that I want to use them for output e.g. to a log file. The last thing to do is simply to commit the changes and write some output lines for logging purposes.

$user.commitchanges()
$user.DisplayName + " (" + $user.sAMAccountName + ") updated"
"HomeDir:`t"       + $oldHomeDirectory +   " >> " + $user.HomeDirectory
"ProfilePath:`t"   + $oldProfilePath +     " >> " + $user.ProfilePath
"TsHomeDir:`t"     + $oldTsHomeDirectory + " >> " + $user.TsHomeDirectory
"TsProfilePath:`t" + $oldTsProfilePath +   " >> " + $user.TsProfilePath
"----------------------------------------------"

Here’s the entire script: Bulk Attribute Change of Users in Active Directory

Detect Orphaned HomeDirectories and Roaming Profiles

Prerequisites: ActiveRoles Management Shell for Active Directory must be installed on the host running this script.

I was given the task to migrate data from one file server to the other. Some of the data were the homedirectories and profiles (both for Windows clients and Terminal Services) of all users in Active Directory. Even though this could be solved quite easily with e.g. DFS and file replication, it seemed like a good time to finally write that script I’ve always wanted to write. A script that helps me locate folders that weren’t deleted when a user had been deleted in Active Directory. This will also help me minimize wasted disk space in the future which shortens backup time and (maybe more important) restoration time in case of a server failure. So here we go…

First I want to load the snappin so I don’t have to open the ActiveRoles Management Shell everytime I want to run the script.

add-pssnapin -name Quest.ActiveRoles.ADManagement

As I don’t want to delete the orphaned folders right away I want to move them to a different location. By doing this I can easily restore the data in case of a mistake (of course I would back it up on tape before deleting it permanently after a few days and yes, Volume Shadow Copy could also be a good idea). Also I like the idea of moving the orphaned folders to the same folder so I can select properties of the top folder and see how much space I’ve saved this time. Therefore I declare 2 arrays with 3 paths each.

$paths         = "\\fileserver\e$\homedirectories\", "\\fileserver\e$\profiles\", "\\fileserver\e$\tsprofiles\"
$orphanedPaths = "\\fileserver\e$\orphaned\homedirectories\", "\\fileserver\e$\orphaned\profiles\", "\\fileserver\e$\orphaned\tsprofiles\"

I want to be able to run this script over the network so I’m using ‘e$’ in my paths. $paths contains the paths in which to look for orphaned folders. $orphanedPaths containts the paths to which I want to store the orphaned folders temporarily.

 Next I want to run through the subfolders of the different paths.

for( $i = 0; $i -lt $paths.length; $i++ )
{
    $directories = Get-ChildItem -Path $paths[$i]

    ...
}

By using the ‘Get-ChildItem’ cmdlet I get an array ‘$directories’ containing all the subfolders in the given path. I want to run through this array of folders and check if a user with a corresponding name exists in Active Directory. Obviously this would require you to use %username% in the path for homedirectories and romaing profiles when you create a user in Active Directory.

for( $j = 0; $j -lt $directories.Length; $j++ )
{
    $currentDirectory = $directories[$j]

    $index1 = $currentDirectory.Name.ToLower().IndexOf( ".mydomain" )
    $index2 = $currentDirectory.Name.ToLower().IndexOf( ".v2" ) # vista og win7 profiles

    $sAMAccountName = $currentDirectory.Name.ToLower()

    if( $index1 -gt 0 )
    {
        $sAMAccountName = $sAMAccountName.Remove( $index1 )
    }
    if( $index2 -gt 0 )
    {
        $sAMAccountName = $sAMAccountName.Remove( $index2 )
    }
    ...
}

In some cases the profile directories are suffixed with .v2 (for Windows Vista and Windows 7 profiles) or the NetBIOS name of your domain. I want to strip those suffixes from the folder name to get the sAMAccountName I wish to search for in Active Directory. Also I convert everything to lowercase for easier comparison. The last thing we need to do now is to search for an owner in Active Directory and move the current folder if the search fails.

$user = Get-QADUser -SamAccountName $sAMAccountName

if( $user -eq $null )
{
    $currentDirectory.MoveTo( $orphanedPaths[$i] + $currentDirectory.Name  )
}

That’s all there is to it.

Here’s the entire script: Detect Orphaned HomeDirectories and Roaming Profiles