Showing posts with label AD Commandlets. Show all posts
Showing posts with label AD Commandlets. Show all posts

Tuesday, September 27, 2011

PowerShell ActiveDirectory Module vs Quest.ActiveRoles.ADManagement Snapin

I have used the Quest.ActiveRoles.ADManagement snapin for a few years and have enjoyed their ease of use. Now that we have migrated our domain controllers to 2008 R2, I often use the ActiveDirectory Module. In fact, I end up using both and see no reason to pick one over the other.

Being of curious nature, I wanted to compare the time it took for a standard query to run using both approaches. Following is a comparison of:
  • Quest.ActiveRoles.ADManagement snapin with Where-Object
  • Quest.ActiveRoles.ADManagement snapin with LDAP Filter
  • ActiveDirectory Module with Filter parameter
  • ActiveDirectory Module with LDAP Filter
The query is looking for "stale" servers and runs 10 times for each one and averages the result.

# Add required snapin and module    
Add-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue
Import-Module ActiveDirectory -ErrorAction SilentlyContinue

$d = ((Get-Date).AddDays(-90)).ToFileTime()
$LDAP = "(&(OperatingSystem=*Server*)(pwdLastSet<=$d)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
$server = "DC-P01"

# Quest.ActiveRoles.ADManagement with Where-Object
$QAD_Where = (1..10 | foreach {
(Measure-Command -Expression {
Get-QADComputer -Service DC-P01 -OSName '*Server*' -PasswordNotChangedFor 90 `
| Where-Object {-not $_.AccountIsDisabled}}).TotalSeconds
} | Measure-Object -Average
).Average

# Quest.ActiveRoles.ADManagement with LDAP filter
$QAD_LDAP = (1..10 | foreach {
(Measure-Command -Expression {
Get-QADComputer -Service $server -LDAPFilter $LDAP }).TotalSeconds
} | Measure-Object -Average
).Average

# Active Directory Module with Filter parameter
$AD_Filter = (1..10 | foreach {
(Measure-Command -Expression {
Get-ADComputer -Server $server -Filter { (OperatingSystem -like "*Server*") -AND
(PasswordLastSet -le $d) -AND (Enabled -eq $True)}}).TotalSeconds
} | Measure-Object -Average
).Average

# Active Directory Module with LDAP Filter
$AD_LDAP = (1..10 | foreach {
(Measure-Command -Expression {
Get-ADComputer -Server $server -LDAPFilter $LDAP}).TotalSeconds
} | Measure-Object -Average
).Average

"Quest.ActiveRoles.ADManagement with Where-Object took {0:N2} seconds." -f $QAD_Where
"Quest.ActiveRoles.ADManagement with LDAPFilter took {0:N2} seconds." -f $QAD_LDAP
"Active Directory Module with filter took {0:N2} seconds." -f $AD_Filter
"Active Directory Module with LDAPFilter took {0:N2} seconds." -f $AD_LDAP

The results (for the most part) are not surprising.
Quest.ActiveRoles.ADManagement with Where-Object took 4.97 seconds.
Quest.ActiveRoles.ADManagement with LDAPFilter took 4.19 seconds.
Active Directory Module with filter took 3.20 seconds.
Active Directory Module with LDAPFilter took 3.21 seconds.

At some point, I need to run this again with a long running query.

Is this consistent with your results?

Enjoy!

Thursday, June 3, 2010

Query AD & ND concurrently (Yep, you heard me right)

In our environment, we have Active Directory and Novell Directory Services. While I spend 95% of my time in AD, I do occasionally get asked to grab information from NDS. Instead of falling back on older tools, I thought I would look at querying NDS via PowerShell. After looking at a few .NET classes, I recalled that one of my handouts at a Central Ohio PowerShell Users Group meeting was NetCmdlets. These cmdlets greatly extend the features of Microsoft Windows PowerShell with a broad range of network management and messaging capabilities. They also happen to include Get-LDAP. Using this cmdlet, it is fairly straightforward to query NDS. Following is and example that queries AD and NDS in one line of script (broken up for readability.
Get-QADUser -Enabled -Department *92278*  Sort-Object samaccountname   `
ForEach-Object {
Get-LDAP -Server 'Novell-Server' -Search "cn=$($_.samaccountname)"
} Select-Object -Unique @{N="FullName";E={$_.FullName[0]}}, resultDN `
Export-Csv -Path c:\temp\NDS.csv -NoTypeInformation

So here is what happens:

  1. We query for enabled users in AD that are in Department 92278.
  2. We sort these users by SAMAccountName
  3. We iterate over each user calling Get-LDAP with an NDS server and the SAMAccountName as a parameter
  4. We then select FullName and the resultDN (there is a bit of magic going on here as we need to assist PowerShell with the formatting: -Unique gets rid of blank lines (don't ask me why they are there). FullName actually returns an array (once again, not sure why), we can easily grab what we want by using by forcing the format @{N="FullName";E={$_.FullName[0]}}
  5. Lastly, we kickout the results to a CSV ready for use in Excel

The results look like this...

FullNameresultDN
Alda, Alancn=Alda01,ou=IS,ou=OSU,ou=HOSP,ou=CAMPUS,o=OSU_MC
Burghoff, Garycn=Burg02,ou=IS,ou=OSU,ou=HOSP,ou=CAMPUS,o=OSU_MC
Farr, Jamiecn=Farr01,ou=IS,ou=OSU,ou=HOSP,ou=CAMPUS,o=OSU_MC

At some point, I will look at using the System.DirectoryServices Namespace to accomplish this instead of relying on a 3rd party, but for now I can check a few immediate NDS related tasks off my list.

Enjoy!

Thursday, May 28, 2009

File Migration with PowerShell

Was recently tasked with assisting our file migration project. Until the following script (assumes you are using Quest AD Commandlets), this was a manual process.
$Users = get-content -path c:\users.txt
foreach ($User in $Users) {
$SourceFolder = "\\HumanResources\vol10\Users\$User"
$NewFolderName = "$SourceFolder-Migrated"

$homeDir = "\\personal-p01\users$\" + $User.substring(0,1) + "\$User"
Copy-Item $SourceFolder -Destination $homeDir -Recurse

Set-QADUser
$User -ObjectAttributes @{'HomeDirectory'=$homeDir; 'HomeDrive'= 'P:'}
$rule=new-object System.Security.AccessControl.FileSystemAccessRule("OSUMC\$User","FullControl","Allow")

foreach ($file in $(Get-ChildItem $homeDir -recurse)) {
$acl=get-acl $file.FullName
$acl.SetAccessRule($rule)
set-acl $File.Fullname $acl
}
# set the acl on the root folder
set-acl $homeDir $acl

# Rename-item doesn't work, so copy and delete
Copy-item $SourceFolder -Destination "$SourceFolder-migrated" -Recurse
Remove-Item $SourceFolder -Recurse -Force
}
Enjoy!

Thursday, April 9, 2009

Quest Management Shell 1.2 – Updated AD cmdlets!

I just installed Quest’s latest version of their free AD cmdlets. After installing, I wanted to see what new cmdlets have been provided. The first thing I noticed in looking for the updated cmdlets was that you can no longer use Get-QADCommand to see the Quest Commands, that has been replaced with Get-QCommand. Looks like there are 9 new cmdlets:

  • Add-QADMemberOf – I see this one getting some use! Allows you to add a single object to one or many groups.
  • Approve-QARSApprovalTask – An ActiveRoles Server cmdlet. Looks like a workflow approval cmdlet
  • Get-QADMemberOf – This will be handy for auditing purposes! This cmdlet allows you to retrieve the groups that an object belongs to.
  • Get-QADPasswordSettingsObjectAppliesTo – This new cmdlet is specific to Windows Server 2008 Active Directory. Allows you to retrieve groups affected by a particular password settings object.
  • Get-QARSApprovalTask – Another ActiveRoles Server cmdlet. You can use this one to grab approval task records.
  • Get-QARSOperation - Another ActiveRoles Server cmdlet. Used to retrieve the operations records.
  • Reject-QARSApprovalTask – Like the Approve-QARSApprovalTask accept this one is used to reject the workflow task.
  • Remove-QADMemberOf – The opposite of Add-QADMemberOf. Use the cmdlet to remove an object from one or more groups. This one will get some use in our environment!
  • Restore-QADDeletedObject – Wish we had this one a few months ago! This cmdlet will allow you to undelete objects in AD by restoring tombstones into normal objects. An example from the help file demonstrates the power of this cmdlet:
    Get-QADUser -Tombstone -LastKnownParent '<DN of container>' -Name 'John Smith*' Restore-QADDeletedObject

Nice collection of new functionality!

When looking at the example in the help on Restore-QADDeletedObject, I saw the parameter –Tombstone used with Get-QADUser. Further investigation yields that Quest has added quite a few parameters to various QAD cmdlets.

This is a list of new parameters from the documentation supplied with the new version:

ParametersCmdlet added to
Tombstone
LastKnownParent
Get-QADComputer
Get-QADGroup
Get-QADObject
Get-QADPasswordSettingsObject
Get-QADUser
CreatedOn
CreatedAfter
CreatedBefore
LastChangedOn
LastChangedAfter
LastChangedBefore
Get-QADComputer
Get-QADGroup
Get-QADObject
Get-QADPasswordSettingsObject
Get-QADUser
Get-QARSAccessTemplate
Get-QARSAccessTemplateLink
Type
ObjectAttributes
Name
DisplayName
Description
Anr
Get-QADGroupMember
MemberOf
IndirectMemberOf
NotMemberOf
NotIndirectMemberOf
Get-QADComputer
Get-QADGroup
Get-QADObject
Get-QADUser
ContainsMember
ContainsIndirectMember
NotContainsMember
NotContainsIndirectMember
Get-QADGroup

Can’t wait to dive in a bit more and use the newest version.

Enjoy!

Monday, January 5, 2009

PrimalForms & PowerShell AD Tool

We are in the middle of a file migration and our policy dictates that as our file shares are moved they need to have the following structure:
  • Access.Neurosurgery.Public.Change
  • Access.Neurosurgery.Public.Full
  • Access.Neurosurgery.Public.Read
So every time a new group is requested, the admin has to create 3 distinct groups, assign the scope & type and add the "Managed By" username. Not hard, but time consuming. This looked like a great candidate for PrimalForms!

The UI is pretty straight forward. It asks for the group name, the scope and the owner.


When the Verify Group button is pressed, we perform a few checks before we create the groups. First we check to see if there are similar groups. In this case, the panel is now visible and the status bar indicates that like groups already exist.


Once we verify the group name, we need to verify that the entered group owner is in fact a legitimate AD object.


In this case, the user is not valid. Once all the data is verified, we give the user one last chance to cancel before the groups are created.


That's about it!

Enjoy!

Wednesday, October 29, 2008

Logon Restrictions

Was approached yesterday with the following request.
- Find all users that have a logon restriction
- Return Last, First name and the users login ID
- Indicate if they belong to any group like "Citrix.PatientLink.*"

Quest AD CMDLETS to the rescue (again).

First let's find all the users with a logon restriction and toss them into a CSV file.
GET-QADUser -SizeLimit 0 -IncludeAllProperties `
WHERE {$_.logonHours -ne $null} `
SELECT logonname, logonHours `
EXPORT-CSV -Path 'C:\logonRestrictions.csv' -NoTypeInformation

We have to use the parameter -IncludeAllProperties to expand the property logonHours.

Next we will use this list to grab the users last, first name, department, logonName and indicate if they belong to any group matching "Citrix.PatientLink.*".

function Get-LogonRestrictions {
foreach($Users in $AllUsers) {
$MemberOF = $Null
$User = Get-QADUser $Users.LogonName `
Select LastName, FirstName, Department, LogonName, MemberOf
$Groups = (Get-QADUser $Users.LogonName).MemberOf
foreach ($Group in $Groups){
if($Group -match 'Citrix.Patient') {
$MemberOF = (get-qadgroup $Group).Name
}
}
$obj = New-Object psObject
$obj Add-Member NoteProperty LastName $User.LastName
$obj Add-Member NoteProperty FirstName $User.FirstName
$obj Add-Member NoteProperty Department $User.Department
$obj Add-Member NoteProperty LogonName $User.LogonName
$obj Add-Member NoteProperty MemberOF $MemberOF
Write
-Output $obj
}
}

$AllUsers = Import-Csv -Path 'C:\logonRestrictions.csv'
$AllUsers Get-LogonRestrictions Export-Csv `
-Path 'C:\logonRestrictionsDetail.csv'

And we are done!