Find Co-Workers of an Account Listed in Active Directory

When managing user accounts in MS Active Directory one of the frequent request we get is to relocate the Home Directory for an employee.  There could be a number of different reasons for this,  but some common causes for the request are:

  • The relocation of an employee to a new city or work location.
  • A Home Directory has grown too large and needs to be relocated for diskspace load balancing.
  • The Home Directory folder is not located in a location that provides fast enough access speed across the WAN.

When we are relocating a Home Directory one of the common things we need to know is What server provides employees the best access speed for the new location of the requesting employee“?  One easy way to answer this question is by determining what server the employee’s new or current Co-Workers are using.  In this case Co-workers means those employees that report to the same manager.

What is a good way to find the homedirectory of an employee and his peers if you are not familiar with their workgroup?

The following PowerShell function provides a solution to that question.

<#
.SYNOPSIS
This script is used to get detailed information on a user account found in Active Directory.
.DESCRIPTION
This script is used to get detailed information on a user account found in Active Directory.
The result can be sent to the output screen and the Out-GridView cmdlet.
Get-QADUser is required; part of the Quest AD management software.
Found here: http://www.quest.com/powershell/activeroles-server.aspx

.PARAMETER <paramName>
UserID – The account that will searched in the domain detailed by -Domain.

.EXAMPLE
Get-UserInfo AA9999
This will search the default domain for an account using the standard ATT account type. The default domain is ITServices.
.EXAMPLE
Get-UserInfo “LastName, FirstName MI”
This will search the default domain for an account using the Full Display Name. The default domain is ITServices.

#>

#This function will provide a work of employees that work with an employee. They all have the same manager.
#Name, displayname, homedirectory, and email-address are returned.

function get-coworkers([PSObject] $UserID) {
if ((Get-QADUser $userID | select-object manager) -ne $null){

Get-QADUser -Manager (Get-QADUser -Identity $UserID | select-object manager).manager | select-object name, displayname,homedirectory | sort-object homedirectory | ft -AutoSize

}

else {

write-host “$UserID was not valid, or no manager was listed for the account.” -foregroundcolor red

}

}

get-coworkers $UserID -UserID $Args[0]
#End

Here is a sample of the function being run using my ATTUID as the input:

 

Sample of the Get-Coworker function being run using my ATTUID as the input (Some Output Obscured)

Another simple way to run it is by applying the “Full Display Name to the function input:


Sample of the Get-Coworker function being run using my Full Display Name as the input (Some Output Obscured)

If you apply an account to the function, or the account does not have a manager applied to it you will see the following error:

 

Sample of the Get-Coworker function being called on an invalid AD account(Some Output Obscured)

To download the full text of this script please go here:  Get-CoWorkers.PS1

Get-DriveSpace on One or Multiple Computers

One common administrative task is to find the  available disk space on a server.  The standard methods to do this are connecting to the computer remotely to verify disk space, and using VBScript scripting to gather the data.  But there is a better way…

With Powershell’s extensive use of WMI and the “piping” options, a very useful one-liner can be used to retrieve the disk space for one or more servers.

Here is the WMI property that we will be using: Win32_LogicalDisk.

To find the disk space available for one computer you would use this one-liner:

get-wmiobject Win32_LogicalDisk -computername Server001 | select __server, Name, Description, FileSystem, @{Label=”Size”;Expression={“{0:n0} MB” -f ($_.Size/1mb)}}, @{Label=”Free Space”;Expression={“{0:n0} MB” -f ($_.FreeSpace/1mb)}} | out-gridview -Title “Disk Space Scan Results”

Lets take a look at the different sections of that one-liner.

get-wmiobject Win32_LogicalDisk -computername Server001 |

This is the standard cmdlette for accessing WMI in Powershell.  The number of available WMI classes is quite extensive.  In the above example, -computername would be followed by a valid computer name. The output of that is piped  into the  Select-Object cmdlette.

select __server, Name, Description, FileSystem, @{Label=”Size”;Expression={“{0:n0} MB” -f ($_.Size/1mb)}}, @{Label=”Free Space”;Expression={“{0:n0} MB” -f ($_.FreeSpace/1mb)}} |

Select-Object, in this one-liner aliased as select, allows us to choose which properties of the returned query we want to use.  By default the Win32_LogicalDisk class provides us with the following properties:

DeviceID     : C:

DriveType    : 3

ProviderName :

FreeSpace    : 10997723136

Size         : 21478666240

VolumeName   : C_Drive

We do two things differently with our one-liner. First we grab an extra property that is always available, but not always needed.  We are requesting the “__server” property.  This will be useful when we put everything in columns later on, and really useful when we are asking for the disk space on multiple servers.

The second thing we are doing differently is to apply formatting to the “Size: Property and “Free Space” property. If you notice above the output is in bytes.  We are use to thinking of hard drives in MB or GB, not bytes.  That is way too weird.  So we are going to created two calculated properties.  There is a calculated property for “freespace” and “size”.

The calculated property is much simpler than it might first appear. To specify a calculated property we need to create a hash table; that’s what the @{} syntax does for us.  Inside the curly braces we specify the two elements of our hash table: the property Label (in this case Size or Free Space) and the property Expression (that is, the script block we’re going to use to calculate the property value).  The Label property is easy enough to specify; we simply assign a string value to the Name, like so:

Label=”Size” and Label=”Free Space”

And, believe it or not, the Expression property (which is separated from the name by a semicolon) isn’t much harder to configure; the only difference is that Expression gets assigned a script block rather than a string value:

Expression={“{0:n0} MB” -f ($_.Size/1mb)}} and Expression={“{0:n0} MB” -f ($_.FreeSpace/1mb)}} are the expressions we are using.  So what actually is going on here?

Using .NET to Format Numbers in Windows PowerShell

Powershell doesn’t have any built-in functions or cmdlettes for formatting numbers. But that’s OK; we don’t need any built-in functions or cmdlettes. Instead, we can use the .NET Framework formatting methods.

The heart-and-soul of our command is this little construction: “{0:N0}”. That’s a crazy-looking bit of code to be sure, but it’s also a bit of code that can easily be dissected:

The initial 0 (That’s a zero)  (the one that comes before the colon) represents the index number of the item to be formatted. For the time being, leave that at 0 and everything should work out just fine.

The N represents the type of format to be applied; in this case, the N is short for Numeric. Are there other types of formats we can apply? Yes there are, and we’ll show you a few of those in just a moment.

The second 0 (the one after the N) is known as the “precision specifier,” and, with the Numeric format, indicates the number of decimal places to be displayed. In this case we don’t want any decimal places, so we set this parameter to 0. Suppose we wanted to display three decimal places? No problem; this command takes care of that: “{0:N3}” -f $a. Run that command and you’ll end up with output that looks like this: 19,385,790,464.000.

That’s about all we have to do; after specifying the format type we tack on the –f (format) parameter, then follow that by indicating the value we want to format $_.FreeSpace and $_.Size.

In our one-liner we are dividing the number variables $_.size and $_.freespace by the Powershell constant mb. We could do kb or gb as well. It depends what output you want to see.

For a more extensive discussion on .net formatting, please go here:

http://technet.microsoft.com/en-us/library/ee692795.aspx

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

This is the source I used for much of this information.

The final section of the one-liner outputs the results to the Out-Gridview window.  I have modified the “title” property so that it shows what we are attempting to do with the query.

| out-gridview -Title “Disk Space Scan Results”

 

The above information details how to find the disk space for one server.  Because the “computername” property of the Get-WmiObject cmdlette will accept an array, or a single string.  This allows us to check mutiple servers with the same one liner.  This can be done two ways.

In the first method, the computer names can be directly type into the one liner:

get-wmiobject Win32_LogicalDisk -computername server1, server2, server3

In the second method the computer names can be read from a test file using the get-content cmdlette.

get-wmiobject Win32_LogicalDisk -computername (Get-Content c:\temp\computers.txt) `

select __server, Name, Description, FileSystem, @{Label=”Size”;Expression={“{0:n0} MB” -f ($_.Size/1mb)}},`

@{Label=”Free Space”;Expression={“{0:n0} MB” -f ($_.FreeSpace/1mb)}}`

| out-gridview -Title “Disk Space Scan Results”

I prefer the second method because you can gather the disk information on many servers very quickly.

Please let me know if you have any questions about this procedure.  I would be glad to explain anything, or answer any questions.

Thanks,

Patrick

Test Multiple Network Locations with Test-Path

Frequently we relocate a large number of employee home folders in bulk and we need to verify that the move was successful, or we want to test the validity of a large number of network shared folders. This utility does that utilizing the Powershell test-path commandlette.

If you want a basic understanding of how the test-path commandlette works, type this in your Powershell console window:

get-help test-path –full

Here is a general description of what this script utility, Test-Paths.ps1 does:

.SYNOPSIS

This script will test the validity of paths that are contained in the paths.ini file. Output is generated to a CSV file, and to Out-GridView.

.DESCRIPTION

The targets of the test-path command are pulled from the “paths.ini” file that is collocated with the test-paths.ps1 file.

Each target is tested using the Powershell test-path commandlette. Results are stored along with the path name in two output methods.

out-gridview and filename.csv

.PARAMETERS

-nogridview: Prevents the script from generating the Out-GridView window.

-noexport: Prevents the script from generating the exported CSV file.

-outfile filename.csv: Use an alternative name for the output file. CSV extension is best. The default if this switch is not added is testpathresult.csv.

.EXAMPLES

This will give two outputs. A file named testpathresult.csv and the out-gridview window:

.\test-paths.ps1

This example will give no out-gridview window, but will save a CSV file named patrick.csv:

.\test-paths.ps1 -nogridview -outfile patricks.csv

This example will give only the out-gridview window:

.\test-paths.ps1 –noexport

Here are a couple of examples with the script in action. In this first one I will get all failed status results for the test-path commands, but that is because I am using simulated directory paths.

Here are the contents of the paths.ini file which is collocated with the script:

Figure 1: Contents of Paths.ini File

Here are a few screen shots of the utility being run, and some of the selected output screen shots.

.\test-paths.ps1

Figure 2: Command Window Output

You can see that the Powershell command window echoes the target currently being tested.

Since the above example did not use either the of the two exclusion switches, both out-gridview and a CSV file were generated. Here are images of both types of output:

Figure 3: Out-gridview

Figure 4: Testpathresult.CSV File

Notice there are two columns in Figure 3: Accessible and HomeDirPath. In each of these the path tested was shown as False because the path was not found.

Here is another example, but this one excludes the export to the CSV file.

.\test-paths.ps1 –noexport

I added “c:windows” to the paths.ini file to show that the test-path can actually find a valid path. With this one we still see the out-gridview window, but no CSV file is generated. Notice that now we have a True in the Accessible column.

Figure 5: True Path Now Found

And finally, the last example where an alternate output file name is generated using the –outfile parameter:

.\test-paths.ps1 –outfile february28th.csv -nogridview

With this one no out-gridview window is generated, but the output file is unique and will not be overwritten the next time the utility is run.

Figure 6: Alternate Output File Naming

In summary, this utility provides an easy way to test a few, or thousands of network paths very easily.

It is run in a Windows Powershell environment. The target paths are inserted in the paths.ini text file, and the command is run as detailed above.

Let me know if you have any questions about this.

Thanks

Patrick Parkison

Below is the code used in the test-paths.ps1 script.

###################################################################################

<#

.Patrick Parkison

pp1071@att.com

.SYNOPSIS

This script will test the validity of paths that are contained in the paths.ini file. Output is generated to a CSV file, and to Out-GridView.

.DESCRIPTION

The targets of the test-path command are pulled from the “paths.ini” file that is co-located with the test-paths.ps1 file.

Each target is tested using the Powershell test-path commandlette. Results are stored along with the path name in two output methods.

out-gridview and filename.csv

.PARAMETER

-nogridview: Prevents the script from generating the Out-GridView window.

-noexport: Prevents the script from generating the exported CSV file.

-outfile: Use an alternative name for the output file. CSV extension is best. The default if this switch is not added is testpathresult.csv

.EXAMPLES

This will give two outputs. A file named testpathresult.csv and the out-gridview window:

.\test-paths.ps1

This example will give no out-gridview window, but will save a CSV file named patrick.csv:

.\test-paths.ps1 -nogridview -outfile patricks.csv

This example will give only the out-gridview window:

.\test-paths.ps1 -noexport

#>

param([switch] $noGridview, [switch] $noExport, [string]$outfile = “testpathresult.csv”)

#Change the title bar of the script window. This is helpful for long running scripts.

$Host.UI.RawUI.WindowTitle = “Running test-path utility.”

#Makes an array, or a collection to hold all the object of the same fields.

$dataColl = @()

#Get location of the script. Info will be used for getting location of all test targetrs, and for saving output to the same folder.

function Get-ScriptPath

{

Split-Path $myInvocation.ScriptName

}

#ScriptPath will be used to place the output file.

$scriptPath = get-scriptpath

#Paths.ini is a text file containing a list of targets e.g. \servernamesharename

$sourcefile = $scriptPath + “paths.ini”

<#

This is the output CSV file. It is overwritten each time the script is run.

If a historical record is desired, a date can be appended to the file name. See this reference on how to do that: https://thescriptlad.com/?s=date

#>

$outputfile = $scriptPath + “” + $outfile

foreach ($path in (gc $sourcefile)){

$dataObject = New-Object PSObject

Write-Host “Scanning: $path”

Add-Member -inputObject $dataObject -memberType NoteProperty -name “Accessible” -value (Test-Path $path )

Add-Member -inputObject $dataObject -memberType NoteProperty -name “HomeDirPath” -value $path

$dataColl += $dataObject

}

#This section is used to generate the out-gridview display.

if (!$noGridview)

{

$label = “Test-Path Results. Total Responses: ” + $dataColl.count

$dataColl | Out-GridView -Title $label

}

#Output to the CSV file for use in Excel.

if (!$noExport)

{

$dataColl | Export-Csv -noTypeInformation -path $outputfile

}

#Restore the default command window title bar.

$Host.UI.RawUI.WindowTitle = $(get-location)