Showing posts with label Metrics. Show all posts
Showing posts with label Metrics. Show all posts

Thursday, September 19, 2013

How to store AD metrics in SharePoint 2010


PowerShell Metrics Series: Active Directory Reporting
How to generate and report basic AD account metrics
How to generate complex AD account metrics part 1
How to generate complex AD account metrics part 2
How to store AD metrics in SharePoint 2010
How to present AD metrics in a SharePoint 2010 dashboard
Introduction

In the previous posting in this series, we explored how to generate more complex AD account metrics using PowerShell. In this posting, we'll explore how to store these metrics in a SharePoint Server 2010 list for convenient access. This will involve the following four steps:
  1. Creating a new list with appropriate fields.
  2. Adding the Active Directory remote management tools to the SharePoint host.
  3. Modifying the PowerShell script developed in previous postings to write results to this list.
  4. Running the script to verify metrics harvest from Active Directory and their storage in the list.
To prepare for this procedure, the Northwind Traders database was added to a new site collection. All nine of the employees were added to Active Directory and made members of a new group, Northwind. Additionally, the SharePoint Server 2010 service accounts, sp_admin, sp_web and sp_app, were also made members of the Northwind group, along with a test account, sp_test, and the administrators account, brens, for a total of 14 accounts in the Northwind AD group.

NOTE: PowerShell is sensitive to field name case!  Field names, when first created in a SharePoint 2010 list, are case-sensitive: $Item["fieldname"] is different than $Item["Fieldname"].

Step 1: create list
  1. Create a new custom list in SharePoint Server 2010. Give the list a short name to simplify referencing it in PowerShell.
  2. Add to this list all of the basic metrics developed previously, including:
    1. Total accounts
    2. Total admin accounts
    3. Total service accounts
    4. Total test accounts
    5. Total end-user accounts
  3. Format these fields as numbers with 0 decimal places
Step 2: add tools
  1. Open Server Manager.
  2. Click Add Features.
  3. Select Remote Server Administration Tools | Role Administration Tools | AD DS and AD DS Tools:
  4. Install the tools.
Step 3: modify script
  1. Open a PowerShell window on the SharePoint Server.
  2. Add the PowerShell snap-in for SharePoint.
  3. Import the PowerShell module for Active Directory
  4. Follows is the modified script, simplified and with most comments removed:
Import-Module ActiveDirectory
Add-PSSnapin Microsoft.SharePoint.PowerShell
$DateTime = Get-Date
# Get the Northwind group accounts only
$NorthWindAccounts = (Get-ADGroup 'Northwind').DistinguishedName
# Extract general metrics
$AllAccounts = Get-ADUser -Filter {(memberof -eq $NorthWindAccounts)} -Properties Name, Givenname, Surname, DistinguishedName, Enabled, LastLogonDate, LastLogonTimeStamp, LockedOut, SAMAccountName, CreateTimeStamp, Created, PasswordLastSet, Description
[array]$AllAdminAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Admin*'}
[array]$AllServiceAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Service*'}
[array]$AllTestingAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Testing*'}
[array]$AllUserAccounts = $AllAccounts | Where-Object {($_.Description -NotLike '*Admin*') -and ($_.Description -NotLike '*Service*') -and ($_.Description -NotLike '*Testing*')}
# Handle null values
if (($AllAccounts.count -eq $NULL) -or ($AllAccounts.count -eq 0)){
    $AllAccountsValue = 0
}
else{
    $AllAccountsValue = $AllAccounts.count
}
if (($AllAdminAccounts.count -eq $NULL) -or ($AllAdminAccounts.count -eq 0)){
    $AllAdminAccountsValue = 0
}
else{
    $AllAdminAccountsValue = $AllAdminAccounts.count
}
if (($AllServiceAccounts.count -eq $NULL) -or ($AllServiceAccounts.count -eq 0)){
    $AllServiceAccountsValue = 0
}
else{
    $AllServiceAccountsValue = $AllServiceAccounts.count
}
if (($AllTestingAccounts.count -eq $NULL) -or ($AllTestingAccounts.count -eq 0)){
    $AllTestingAccountsValue = 0
}
else{
    $AllTestingAccountsValue = $AllTestingAccounts.count
}
if (($AllUserAccounts.count -eq $NULL) -or ($AllUserAccounts.count -eq 0)){
    $AllUserAccountsValue = 0
}
else{
    $AllUserAccountsValue = $AllUserAccounts.count
}
# Get the site object
$SiteURL = "http://spdev12:4000/"
$Site = Get-SPWeb $SiteURL
# Get the list object from this site
$ListName = "dl_ml"
$List = $Site.Lists[$ListName]
# Prepare a new list row
$NewItem = $List.Items.Add()
    $NewItem["Title"] = $DateTime
    $NewItem["TotalAllAccounts"] = $AllAccountsValue
    $NewItem["TotalAdminAccounts"] = $AllAdminAccountsValue
    $NewItem["TotalServiceAccounts"] = $AllServiceAccountsValue
    $NewItem["TotalTestAccounts"] = $AllTestingAccountsValue
    $NewItem["TotalUserAccounts"] = $AllUserAccountsValue
# Add the new list row
$NewItem.Update()
# Dispose the site object
$Site.Dispose()
Step 4: test script
  1. On the SharePoint Server 2010 host, open the PowerShell ISE.
  2. Paste the script above into a new tab.
  3. Modify server names, site URLs, list names and column names as necessary.
  4. Run the script under an account that has at least read privileges to the domain controller.
  5. Open a browser, and then connect to the site to view the list:
Summary

In this posting, we explored how to generate AD metrics from the server hosting SharePoint Server 2010 Enterprise and then store those metrics in a SharePoint Server 2010 list. All references consulted in writing this posting are listed below. In the next posting in this series, we'll explore how to present these metrics in the Data View and Chart web parts.

References
Notes
  • Microsoft.SharePoint.PowerShell: From what I've found thus far, there doesn't appear to be a way to install the this snap-in on other machines to facilitate remote scripting. The only options found were: remote desktop or remote PowerShell session.
  • Import-Module ActiveDirectory: this isn't normally needed for the machine hosting SharePoint Server 2010. However, it is needed in order to interact with domain controllers and extract account metrics from them.
  • If you see this error after running the above PowerShell script,
    check the case of the fieldnames that you are using against what they are in the SharePoint list.

Sunday, September 15, 2013

How to generate complex AD account metrics part 2


PowerShell Metrics Series: Active Directory Reporting
How to generate and report basic AD account metrics
How to generate complex AD account metrics part 1
How to generate complex AD account metrics part 2
How to store AD metrics in SharePoint 2010
How to present AD metrics in a SharePoint 2010 dashboard
Introduction

In the first posting of this series, we explored the basic process for generating AD metrics and saving them to a file.  In the second posting, we explored generating somewhat more complex metrics.  In this posting, we will conclude this exploration by extracting and categorizing AD account last logons again using the simplest approach.

Obtaining user account last logons provides immediate business value to system administrators, management and customers, as they show infrastructure usage.  Capturing and archiving these values supports trending analysis and more accurate budget planning.

The AD account attribute that will be used is LastLogonDate.  This attribute is a conversion of the LastLogonTimeStamp long integer value into a friendly time format that is formatted according to your local time zone and settings.  The LastLogonTimeStamp attribute is replicated (by default) between 9 to 14 days among the domain controllers and thus LastLogonDate as well.

Review

Here's the script generated thus far:
##################################### # Name:        AD Report Generator # Author:      [your name] # Date:        [date] # Description: ##################################### Import-module ActiveDirectory # Create the report container # --------------------------- # Save the data and time.  This date and time # will be used also for generating the report # filename. $DateTime = Get-Date # Use this date/time to generate the report file name $DateTimeFileString = $DateTime.ToString("yyyyMMddHHmmss") # Now generate the path/file string $FilePathString = "\\[YourPath]\ADReport_" + $DateTimeFileString + ".txt" # Create a new text file New-Item $FilePathString -Type File # Write the report date/time # -------------------------- # Add the date/time to the top of the file [string]$StringToWrite = $DateTime Set-Content $FilePathString $StringToWrite # and then add a couple of lines after Add-Content $FilePathString "" Add-Content $FilePathString "" # Add a header to the report # -------------------------- $StringToWrite = "AD Domain Accounts Report" Add-Content $FilePathString $StringToWrite $StringToWrite = "Generated on host " + $env:Computername + " by " + $env:UserName Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "=====================================================" Add-Content $FilePathString "" Add-Content $FilePathString "" Add-Content $FilePathString ""   # Build the report # ---------------- # This next line of code interrogates AD and builds the array # that contains all accounts in AD and the desired properties.   # It effectively generates a list of accounts and their # properties that you can parse and filter as needed.  This only # needs to be performed once, for the entire report, as all of # the rest of the attention will be focused on this array. [array]$AllAccounts = Get-ADUser -Filter * -Properties Name, Givenname, Surname, DistinguishedName, Enabled, LastLogonDate, LastLogonTimeStamp, LockedOut, msExchHomeServerName, SAMAccountName, CreateTimeStamp, Created, PasswordLastSet, Description # This line gets the total number of accounts and report it.   # It effectively counts all of the rows in the array. $StringToWrite = "Total number of AD domain accounts of all types: " + $AllAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of accounts having Exchange # mailboxes. The Where-Object performs all of the complex # interaction necessary for filtering the array - you simply # need to provide it with the filter parameters.  Note the use # of "$_", which is a shorthand reference to the object being # filtered.  Note too how Boolean equations are written.   # Boolean operators are denoted by a hyphen "-".  See the # References for additional discussion on this notation. [array]$AllMailboxUsers = $AllAccounts | Where-Object {$_.msExchHomeServerName -NotLike $NULL} $StringToWrite = "Total number of users who have email accounts: " + $AllMailboxUsers.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of administrative accounts # using the # same approach as previous.  As discussed earlier, # it assumes that admin accounts are distinguished by having # the word "Admin" in their Description field.  Other fields # may also be used - if so, use them instead. [array]$AllAdminAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Admin*'} $StringToWrite = "Total number of Administrative accounts: " + $AllAdminAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of service accounts.  Same approach as # previous. Assumes that service accounts are distinguished # by having the word "Service" in their Description field. [array]$AllServiceAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Service*'} $StringToWrite = "Total number of Service accounts: " + $AllServiceAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of accounts used for testing.  Same approach # as previous. Assumes that testing accounts are distinguished by # having the word "Testing" in their Description field. [array]$AllTestingAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Testing*'} $StringToWrite = "Total number of Testing accounts: " + $AllTestingAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of end user accounts.  Same approach as # previous, but this time the array is filtered for NOT having # certain keywords in their their Description field.   [array]$AllUserAccounts = $AllAccounts | Where-Object {($_.Description -NotLike '*Admin*') -and ($_.Description -NotLike '*Service*') -and ($_.Description -NotLike '*Testing*')} $StringToWrite = "Total number of User accounts: " + $AllUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of user accounts that # are enabled. [array]$AllEnabledUserAccounts = $AllUserAccounts | Where-Object {$_.Enabled -eq $True} $StringToWrite = "Total number of Enabled User accounts: " + $AllEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of user accounts that # are disabled. [array]$AllDisabledUserAccounts = $AllUserAccounts | Where-Object {$_.Enabled -eq $False} $StringToWrite = "Total number of Disabled User accounts: " + $AllDisabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of enabled users # accounts that have been locked out. [array]$AllEnabledLockedUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LockedOut -eq $True} $StringToWrite = "Total number of Enabled User accounts that are locked out: " + $AllEnabledLockedUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of enabled users # that have never logged in. [array]$AllEnabledUserAccountsNeverlogon = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -eq $NULL} $StringToWrite = "Total number of Enabled User accounts that have never logged on: " + $AllEnabledUserAccountsNeverlogon.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString ""

LastLogon Metrics

Here is the script to be added.  Let's look at the first metric: users who have logged in within the past 365 days.
# This line gets the number of enabled user accounts that # have logged in within the past 365 days. This time, we # filter the array using a time value, which is obtained # by subtracting 365 from the variable holding the time # value obtained at the start of this script. $365Days = $DateTime.AddDays(-365) [array]$LastLogon365EnabledUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -ge $365Days} $StringToWrite = "Total number of enabled users who have logged in within the past 365 days: " + $LastLogon365EnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" test It follows the same general approach used previously. Repeat this approach for the other date categories, including: 180, 90, 45, and 30 days. $180Days = $DateTime.AddDays(-180) [array]$LastLogon180DaysEnabledUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -ge $180Days} $StringToWrite = "Total number of enabled users who have logged in within the past 180 days: " + $LastLogon180DaysEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" $90Days = $DateTime.AddDays(-90) [array]$LastLogon90DaysEnabledUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -ge $90Days} $StringToWrite = "Total number of enabled users who have logged in within the past 90 days: " + $LastLogon90DaysEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" $45Days = $DateTime.AddDays(-45) [array]$LastLogon45DaysEnabledUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -ge $45Days} $StringToWrite = "Total number of enabled users who have logged in within the past 45 days: " + $LastLogon45DaysEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" $30Days = $DateTime.AddDays(-30) [array]$LastLogon30DaysEnabledUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -ge $30Days} $StringToWrite = "Total number of enabled users who have logged in within the past 30 days: " + $LastLogon30DaysEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" $15Days = $DateTime.AddDays(-15) [array]$LastLogon15DaysEnabledUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -ge $15Days} $StringToWrite = "Total number of enabled users who have logged in within the past 15 days: " + $LastLogon15DaysEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString ""
Summary

This posting, the third in this series, has presented script for extracting additional Active Directory user account metrics.  It uses the LastLogonDate attribute.  The default replication frequency determines the default window of accuracy of LastLogonDate . The default replication frequency works out to be approximately 9-14 days.  This accuracy is good enough for time windows of 30, 60, 90 days, and so on, but is insufficiently accurate when seeking time windows of 1, 2, or 7 days. In a later posting, we'll explore how to improve this accuracy and thus obtain more immediate usage metrics.

References

Thursday, September 12, 2013

How to generate complex AD account metrics


PowerShell Metrics Series: Active Directory Reporting
How to generate and report basic AD account metrics
How to generate complex AD account metrics part 1
How to generate complex AD account metrics part 2
How to store AD metrics in SharePoint 2010
How to present AD metrics in a SharePoint 2010 dashboard
Introduction

In the previous posting in this series, we explored how to generate and report simple Active Directory metrics, such as total number of accounts by type and total number of accounts with mail boxes. In this posting, we will explore how to generate more complex metrics, including:
  • Total number of enabled user accounts
  • Total number of disabled user accounts
  • Total number of user accounts that have been locked out
  • Total number of enabled user accounts that have never logged on
Review

Here's the script that has been created thus far (below).  I've added additional comments to help you understand what is going on:
##################################### # Name:        AD Report Generator # Author:      [your name] # Date:        [date] # Description: ##################################### Import-module ActiveDirectory # Create the report container # --------------------------- # Save the data and time.  This date and time # will be used also for generating the report # filename. $DateTime = Get-Date # Use this date/time to generate the report file name $DateTimeFileString = $DateTime.ToString("yyyyMMddHHmmss") # Now generate the path/file string $FilePathString = "\\[YourPath]\ADReport_" + $DateTimeFileString + ".txt" # Create a new text file New-Item $FilePathString -Type File # Write the report date/time # -------------------------- # Add the date/time to the top of the file [string]$StringToWrite = $DateTime Set-Content $FilePathString $StringToWrite # and then add a couple of lines after Add-Content $FilePathString "" Add-Content $FilePathString "" # Add a header to the report # -------------------------- $StringToWrite = "AD Domain Accounts Report" Add-Content $FilePathString $StringToWrite $StringToWrite = "Generated on host " + $env:Computername + " by " + $env:UserName Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "=====================================================" Add-Content $FilePathString "" Add-Content $FilePathString "" Add-Content $FilePathString ""   # Build the report # ---------------- # This next line of code interrogates AD and builds the array # that contains all accounts in AD and the desired properties.   # It effectively generates a list of accounts and their # properties that you can parse and filter as needed.  This only # needs to be performed once, for the entire report, as all of # the rest of the attention will be focused on this array. [array]$AllAccounts = Get-ADUser -Filter * -Properties Name, Givenname, Surname, DistinguishedName, Enabled, LastLogonDate, LastLogonTimeStamp, LockedOut, msExchHomeServerName, SAMAccountName, CreateTimeStamp, Created, PasswordLastSet, Description # This line gets the total number of accounts and report it.   # It effectively counts all of the rows in the array. $StringToWrite = "Total number of AD domain accounts of all types: " + $AllAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of accounts having Exchange # mailboxes. The Where-Object performs all of the complex # interaction necessary for filtering the array - you simply # need to provide it with the filter parameters.  Note the use # of "$_", which is a shorthand reference to the object being # filtered.  Note too how Boolean equations are written.   # Boolean operators are denoted by a hyphen "-".  See the # References for additional discussion on this notation. [array]$AllMailboxUsers = $AllAccounts | Where-Object {$_.msExchHomeServerName -NotLike $NULL} $StringToWrite = "Total number of users who have email accounts: " + $AllMailboxUsers.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of administrative accounts # using the # same approach as previous.  As discussed earlier, # it assumes that admin accounts are distinguished by having # the word "Admin" in their Description field.  Other fields # may also be used - if so, use them instead. [array]$AllAdminAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Admin*'} $StringToWrite = "Total number of Administrative accounts: " + $AllAdminAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of service accounts.  Same approach as # previous. Assumes that service accounts are distinguished # by having the word "Service" in their Description field. [array]$AllServiceAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Service*'} $StringToWrite = "Total number of Service accounts: " + $AllServiceAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of accounts used for testing.  Same approach # as previous. Assumes that testing accounts are distinguished by # having the word "Testing" in their Description field. [array]$AllTestingAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Testing*'} $StringToWrite = "Total number of Testing accounts: " + $AllTestingAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of end user accounts.  Same approach as # previous, but this time the array is filtered for NOT having # certain keywords in their their Description field.   [array]$AllUserAccounts = $AllAccounts | Where-Object {($_.Description -NotLike '*Admin*') -and ($_.Description -NotLike '*Service*') -and ($_.Description -NotLike '*Testing*')} $StringToWrite = "Total number of User accounts: " + $AllUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString ""

Add Additional Active Directory Metrics

Below is what we will add.  The first metric to extract is the total number of enabled user accounts, and then we'll get the total number of disabled user accounts.  We already have an array that is composed of user accounts only, namely, $AllUserAccounts.  All that needs to be done is to filter this array further based upon the value of the account Enabled property, which is a Boolean.  Here again note that a single line of code is all that is needed to extract the desired metric:
# This line gets the total number of user accounts that # are enabled. [array]$AllEnabledUserAccounts = $AllUserAccounts | Where-Object {$_.Enabled -eq $True} $StringToWrite = "Total number of Enabled User accounts: " + $AllEnabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of user accounts that # are disabled. [array]$AllDisabledUserAccounts = $AllUserAccounts | Where-Object {$_.Enabled -eq $False} $StringToWrite = "Total number of Disabled User accounts: " + $AllDisabledUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString ""

The next couple of metrics to explore are the total number of locked out user accounts and the number of user accounts that have never logged in:
# This line gets the total number of enabled users # accounts that have been locked out. [array]$AllEnabledLockedUserAccounts = $AllEnabledUserAccounts | Where-Object {$_.LockedOut -eq $True} $StringToWrite = "Total number of Enabled User accounts that are locked out: " + $AllEnabledLockedUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of enabled users # that have never logged in. [array]$AllEnabledUserAccountsNeverlogon = $AllEnabledUserAccounts | Where-Object {$_.LastLogonDate -eq $NULL} $StringToWrite = "Total number of Enabled User accounts that have never logged on: " + $AllEnabledUserAccountsNeverlogon.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString ""

Summary

In this posting, we have explored how to generate more complex metrics.  These more complex metrics build upon the metrics already extracted previously. In the next posting, we'll complete our exploration of how to generate metrics by learning how to generate the various LastLogonDate categories typically of interest, such as 180, 90, 45, 30 and 14 day logons, to name a few.  Extracting LastLogonDate values brings real value to management and your customers, as it provides the raw data on actual system usage that management can use to more effectively perform trend analyses and justify and plan infrastructure budgets.

References

How to generate and report basic AD account metrics

PowerShell Metrics Series: Active Directory Reporting
How to generate and report basic AD account metrics
How to generate complex AD account metrics part 1
How to generate complex AD account metrics part 2
How to store AD metrics in SharePoint 2010
How to present AD metrics in a SharePoint 2010 dashboard
Background

In this series of postings, you will learn how to use PowerShell to quickly and easily interrogate Active Directory and generate metrics and reports on your domain accounts.  Active Directory has an excellent API, the ActiveDirectory module, that exposes all of Active Directory data and methods through .NET in simple and easy-to-understand language.  The SharePoint Server codebase rests on the .NET framework and it also has an API that exposes remarkably simple methods and properties, in simple language, that you can use to interact with SharePoint.   Integrating these two is PowerShell, which interacts directly with the .NET framework and thus provides one method for integrating software tools exposed to .NET, such as Active Directory, with tools based upon the .NET framework, such as SharePoint Server. Throughout this series, there will be nothing to buy, and nothing extraordinary to learn or assemble: just your time and effort is all that's needed.

Introduction

In this particular posting, the first of the series, you will learn how to use the following key objects, methods and properties:
  • ActiveDirectory module: the .NET API that exposes Active Directory data;  
  • Get-ADUser: the method that extracts data from Active Directory;
  • Set-Content: the method that creates a text file for storing analysis results;
  • Add-Content: the method that appends data to the text file;
  • Where-Object: a property/method object that enables arrays to be parsed;
  • $env: the system variable containing current computer and user information;
  • Arrays: PowerShell arrays for interim results storage.
See the references for more detailed information on these items. You will use these objects, methods and properties to accomplish the following tasks:
  • Connect to Active Directory on the domain controller and extract all account data into an array;
  • Analyze that array and extract counts for:
    • Total number of domain accounts
    • Total number of domain accounts having mail boxes
    • Total number of Admin accounts
    • Total number of Service accounts
    • Total number of Testing accounts
    • Total number of User accounts
You will need to coordinate with your management and network system administrators and their leads in order to identify the following:
  • All domains and their relative trust relationships
  • Names of all hosts functioning as domain controllers and their ranking
  • Replication frequency among the DCs (default is 15s for Windows 2k8)
  • ActiveDirectory module availability on DCs
  • Your access permissions to these DCs (remoting, scripting, etc)
  • Names of all Active Directory groups
  • All AD account properties currently employed
  • User account policies
  • Method used to distinguish domain account types (Description text, username modifications, etc) and their level of diligence in applying this method
In this particular posting, it is assumed that you will run the script below locally on a domain controller through remote desktop session, but this can just as easily be done through remote PowerShell scripting sessions, which will be explored later.  Latency among your domain controller replication will determine the accuracy of the report generated by this script.

The approach used here rests upon text parsing of the Description field and is the simplest approach of all.  Other, perhaps  more sophisticated approaches are possible.  For example, using the Get-ADGroup method you can immediately obtain groups of accounts by their memberships.  However, while this approach will obtain that group of users who are admins, it will not work for finding testing and service accounts, unless your sys admins have created special AD groups for these types of accounts.  Additionally, some care is needed with regard to this method in that individual accounts may be members of more than one group and thus skew the resultant metrics.  Coordinate with your system administrators to gain an understanding of how they categorize and group accounts, and then build a list of AD groups.  If they have diligently implementing a grouping scheme, then this approach is viable; however more complex coding will be needed.

To use the script below, just copy and past the different parts into a single text file with file ending ps1, then edit it to suit your needs and run on the domain controller or remotely from your workstation via remote session.

I. Prepare the Report

Below is the script used to create a new report container (text file) and add a header to it.  Note that the new text file is referenced at any time by its path and name.  Note too that the Add-Content method automatically writes to a new line - there's no need to add a line feed to your string.  This script assumes that your different user types (admin, service, test, user, etc) are distinguished through appropriate keywords in their Description fields and that the Description field is diligently and regularly maintained. It parses the Description field for keywords.  Other approaches to distinguishing among user types can also be scripted, such as prepending or appending a string to  account names ("svc", "adm", etc), or other such method, such as the Get-ADGroup approach discussed above.  Anyway, to customize this report to your needs, just review the code below and explore different strings to output what you want.
##################################### # Name:        AD Report Generator # Author:      [your name] # Date:        [date] # Description: ##################################### Import-module ActiveDirectory # Create the report container # --------------------------- # Save the data and time.  This date and time # will be used also for generating the report # filename. $DateTime = Get-Date # Use this date/time to generate the report file name $DateTimeFileString = $DateTime.ToString("yyyyMMddHHmmss") # Now generate the path/file string $FilePathString = "\\[YourPath]\ADReport_" + $DateTimeFileString + ".txt" # Create a new text file New-Item $FilePathString -Type File # Write the report date/time # -------------------------- # Add the date/time to the top of the file [string]$StringToWrite = $DateTime Set-Content $FilePathString $StringToWrite # and then add a couple of lines after Add-Content $FilePathString "" Add-Content $FilePathString "" # Add a header to the report # -------------------------- $StringToWrite = "AD Domain Accounts Report" Add-Content $FilePathString $StringToWrite $StringToWrite = "Generated on host " + $env:Computername + " by " + $env:UserName Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "=====================================================" Add-Content $FilePathString "" Add-Content $FilePathString "" Add-Content $FilePathString ""  

II. Get the Data

Below is the script you'll need to get the data from Active Directory.
# Build the report # ---------------- # This next line of code interrogates AD and builds the array # that contains all accounts in AD and the desired properties.   # It effectively generates a list of accounts and their # properties that you can parse and filter as needed.  This only # needs to be performed once, for the entire report, as all of # the rest of the attention will be focused on this array. [array]$AllAccounts = Get-ADUser -Filter * -Properties Name, Givenname, Surname, DistinguishedName, Enabled, LastLogonDate, LastLogonTimeStamp, LockedOut, msExchHomeServerName, SAMAccountName, CreateTimeStamp, Created, PasswordLastSet, Description
III. Parse the Data for Totals

The last bit of script below extracts metrics from the data:
# This line gets the total number of accounts and report it.   # It effectively counts all of the rows in the array. $StringToWrite = "Total number of AD domain accounts of all types: " + $AllAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of accounts having Exchange # mailboxes. The Where-Object performs all of the complex # interaction necessary for filtering the array - you simply # need to provide it with the filter parameters.  Note the use # of "$_", which is a shorthand reference to the object being # filtered.  Note too how Boolean equations are written.   # Boolean operators are denoted by a hyphen "-".  See the # References for additional discussion on this notation. [array]$AllMailboxUsers = $AllAccounts | Where-Object {$_.msExchHomeServerName -NotLike $NULL} $StringToWrite = "Total number of users who have email accounts: " + $AllMailboxUsers.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # This line gets the total number of administrative accounts # using the # same approach as previous.  As discussed earlier, # it assumes that admin accounts are distinguished by having # the word "Admin" in their Description field.  Other fields # may also be used - if so, use them instead. [array]$AllAdminAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Admin*'} $StringToWrite = "Total number of Administrative accounts: " + $AllAdminAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of service accounts.  Same approach as # previous. Assumes that service accounts are distinguished # by having the word "Service" in their Description field. [array]$AllServiceAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Service*'} $StringToWrite = "Total number of Service accounts: " + $AllServiceAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of accounts used for testing.  Same approach # as previous. Assumes that testing accounts are distinguished by # having the word "Testing" in their Description field. [array]$AllTestingAccounts = $AllAccounts | Where-Object {$_.Description -Like '*Testing*'} $StringToWrite = "Total number of Testing accounts: " + $AllTestingAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString "" # Get total number of end user accounts.  Same approach as # previous, but this time the array is filter for NOT having # certain keywords in their their Description field.   [array]$AllUserAccounts = $AllAccounts | Where-Object {($_.Description -NotLike '*Admin*') -and ($_.Description -NotLike '*Service*') -and ($_.Description -NotLike '*Testing*')} $StringToWrite = "Total number of User accounts: " + $AllUserAccounts.Count Add-Content $FilePathString $StringToWrite Add-Content $FilePathString ""
Summary

In this posting, you have learned how to pull account data from Active Directory and load it into an array; analyze the data in that array, and then write the analysis results to a file.  The next posting  builds upon the work performed thus far, by exploring how to generate counts on other important user metrics, such as Enabled, LockedOut, LastLogonDate, etc, and adding it to the current script. 

References