Skip to content

Instantly share code, notes, and snippets.

@Nora-Ballard
Created July 27, 2014 13:48
Show Gist options
  • Select an option

  • Save Nora-Ballard/34a059f197281997a8b6 to your computer and use it in GitHub Desktop.

Select an option

Save Nora-Ballard/34a059f197281997a8b6 to your computer and use it in GitHub Desktop.
Module of various functions for working with Directory Services in Powershell. Some of these capabilities are now available in the native AD module, however this module has the advantage of not requiring the web service to work, they use straight LDAP so they work with all domains, ADAM/ADLDS, and third party LDAP services.
function Select-DsEntry
{
param(
[Parameter(ParameterSetName='AutoQuery')]
[string]$Name = '*',
[Parameter(ParameterSetName='AutoQuery')]
[ValidateSet('User','Group','Computer','Organizational-Unit')]
[string]$ObjectCategory = '*',
[Parameter(ParameterSetName='ManualQuery')]
[string]$LdapQuery,
[Parameter()]
[string]$LdapServer = (([DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).name.ToString()),
[Parameter()]
[int32]$LdapPort = 389,
[Parameter()]
[string]$LdapRoot,
[Parameter()]
[ValidateSet('Anonymous', 'Simple', 'Secure')]
$AuthenticationType = 'Secure',
[Parameter()]
[PsCredential] $Credential,
[Parameter()]
[switch]$FindAll,
[Parameter()]
[switch]$Raw
)
$PSBoundParameters | ForEach-Object {
Write-Debug ('{0} = {1}' -f $_.Key, $_.Value)
}
if ($PsCmdlet.ParameterSetName -eq "AutoQuery") {
$SearchFilter = '(&(objectCategory={0})(|(name={1})(sAMAccountName={1})(userPrincipalName={1})(displayName={1})))' -f $ObjectCategory, $Name
}
elseif ($PSCmdlet.ParameterSetName -eq "ManualQuery") {
$SearchFilter = $LdapQuery
}
Write-Debug "SearchFilter = $searchFilter"
$ldapPath = 'LDAP://{0}:{1}' -f $LdapServer, $LdapPort
if ($PSBoundParameters.ContainsKey('LdapRoot')) {
$ldapPath += '/{0}' -f $ldaproot.Trim('/')
}
Write-Debug "ldapPath = $ldapPath"
if ($AuthenticationType -eq 'Anonymous') {
$AuthenticationTypeValue = [System.DirectoryServices.AuthenticationTypes]::Anonymous
$DirectoryEntry = New-Object System.DirectoryServices.DirectoryEntry($ldapPath, $null, $null, $AuthenticationTypeValue)
}
elseif ($AuthenticationType -eq 'Simple') {
$AuthenticationTypeValue = [System.DirectoryServices.AuthenticationTypes]::None
$DirectoryEntry = New-Object System.DirectoryServices.DirectoryEntry($ldapPath, $Credential.UserName, $credential.GetNetworkCredential().Password, $AuthenticationTypeValue)
}
else {
$AuthenticationTypeValue = [System.DirectoryServices.AuthenticationTypes]::Secure
if ($PSBoundParameters.ContainsKey('Credential')) {
$DirectoryEntry = New-Object System.DirectoryServices.DirectoryEntry($ldapPath, $Credential.UserName, $Credential.GetNetworkCredential().Password, $AuthenticationTypeValue)
}
else {
$DirectoryEntry = New-Object System.DirectoryServices.DirectoryEntry($ldapPath)
}
}
$Searcher = New-Object DirectoryServices.DirectorySearcher($DirectoryEntry)
$Searcher.Filter = $SearchFilter
$Searcher.PageSize = 1000
if ($FindAll) {
$Result = $Searcher.FindAll()
}
else {
$Result = $Searcher.FindOne()
}
Write-Debug ('Result.Count = {0}' -f $Result.Count)
$Result | ForEach-Object {
if ($_ -is [System.DirectoryServices.SearchResult]) {
if ($Raw) {
Write-Output $_
}
else {
$ADSIobject = [adsi]$($_.Properties['adspath'])
write-output $ADSIobject
}
}
}
}
function Show-DsEntry
{
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[System.DirectoryServices.DirectoryEntry]$InputObject
)
$ObjectCopy = $InputObject | Select * -ExcludeProperty userCertificate, NativeObject, Password
foreach ($Property in $ObjectCopy.psobject.Properties) {
try {
$Property.Value = [datetime]::fromfiletime($InputObject.ConvertLargeIntegerToInt64($Property.Value[0]))
}
catch {
if ($error[0].FullyQualifiedErrorId -eq 'ArgumentOutOfRangeException') {$Property.Value = $null}
}
if (($Property.TypeNameOfValue -eq 'System.DirectoryServices.PropertyValueCollection') -and ($Property.Value.Count -eq 1)) {
$Property.Value = $Property.Value.Value
}
if ($Property.Name -eq 'objectGUID') { $Property.Value = [guid]$Property.Value}
if ($Property.Name -eq 'objectSID') { $Property.Value = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $Property.value,0 }
if ($Property.Name -eq 'sIDHistory') { $Property.Value = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $Property.value,0 }
if ($Property.Name -eq 'groupType') { $Property.Value = ConvertFrom-DsGroupType $Property.Value}
if ($Property.Name -eq 'sAMAccountType') { $Property.Value = ConvertFrom-DsSamAccountType $Property.Value}
}
if ($ObjectCopy.objectClass -contains 'Person') {
Add-Member -InputObject $ObjectCopy -MemberType NoteProperty -Name 'accountDisabled' -Value $InputObject.PsBase.InvokeGet("AccountDisabled")
Add-Member -InputObject $ObjectCopy -MemberType NoteProperty -Name 'accountLocked' -Value $InputObject.PsBase.InvokeGet("IsAccountLocked")
Add-Member -InputObject $ObjectCopy -MemberType NoteProperty -Name 'passwordExpirationTime' -Value $InputObject.PsBase.InvokeGet("PasswordExpirationDate")
Add-Member -InputObject $ObjectCopy -MemberType NoteProperty -Name 'passwordExpired' -Value ($ObjectCopy.passwordExpirationTime -lt (Get-Date))
}
Write-Output $ObjectCopy
}
function ConvertFrom-DsSamAccountType {
param(
[Parameter()]
$Type
)
$ADS_SAM_ACCOUNT_TYPE_ENUM = @{
0x0 = 'DOMAIN_OBJECT'
0x10000000 = 'GROUP_OBJECT'
0x10000001 = 'NON_SECURITY_GROUP_OBJECT'
0x20000000 = 'ALIAS_OBJECT'
0x20000001 = 'NON_SECURITY_ALIAS_OBJECT'
0x30000000 = 'NORMAL_USER_ACCOUNT'
0x30000001 = 'MACHINE_ACCOUNT'
0x30000002 = 'TRUST_ACCOUNT'
0x40000000 = 'APP_BASIC_GROUP'
0x40000001 = 'APP_QUERY_GROUP'
0x7fffffff = 'ACCOUNT_TYPE_MAX'
}
$bandTypes = $ADS_SAM_ACCOUNT_TYPE_ENUM.GetEnumerator() | Where {$_.Key -band $Type}
Write-Output $bandTypes.Value
}
function ConvertFrom-DsGroupType {
param(
[Parameter()]
$Type
)
$ADS_GROUP_TYPE_ENUM = @{
0x00000002 = 'GLOBAL_GROUP'
0x00000004 = 'DOMAIN_LOCAL_GROUP'
0x00000008 = 'UNIVERSAL_GROUP'
0x80000000 = 'SECURITY_ENABLED'
}
$bandTypes = $ADS_GROUP_TYPE_ENUM.GetEnumerator() | Where {$_.Key -band $Type}
Write-Output $bandTypes.Value
}
function Get-DsGroupMembers
{
param(
[Parameter(Mandatory, ValueFromPipeline)]
[ValidateScript({$_.psobject.properties.name -contains 'member'})]
[System.DirectoryServices.DirectoryEntry]$InputObject
)
PROCESS{
$SeenGroups = @()
ForEach ($Member In $InputObject.member)
{
$AdsiMember = [ADSI]"LDAP://$Member"
if ($AdsiMember.objectClass -contains 'group')
{
if ($Member -notin $SeenGroups) {
$SeenGroups.Add($Member)
Get-DsGroupMembers $AdsiMember
}
}
else
{
Write-Output $AdsiMember
}
}
}
}
function Show-DsAccountStatus {
param(
[Parameter(Mandatory, ValueFromPipeline)]
[System.DirectoryServices.DirectoryEntry]$InputObject
)
Show-DsEntryFromAllControllers $InputObject | Select-Object 'sAMAccountName', 'DomainController', 'Site',
'badPasswordTime', 'lockoutTime', 'IsAccountLocked', 'IsAccountDisabled', 'badPwdCount', 'pwdLastSet'
}
function Show-DsEntryFromAllControllers {
param(
[Parameter(Mandatory, ValueFromPipeline)]
[System.DirectoryServices.DirectoryEntry]$InputObject
)
$Controllers = Get-DsDomainController -FindAllDiscoverable
ForEach ($Controller in $Controllers) {
$AdsiObject = [ADSI]"LDAP://$($Controller.Name)/$($InputObject.distinguishedName)"
$Output = $AdsiObject | Show-DsEntry
Add-Member -InputObject $Output -MemberType NoteProperty -Name 'DomainController' -Value $Controller.Name
$Output.Site = $Controller.SiteName
Write-Output $Output
}
}
<#
workflow Show-DsEntryFromAll {
param(
[Parameter(Mandatory, ValueFromPipeline)]
[string]$Path
)
$InputObject = [adsi]$Path
$Controllers = Get-DsDomainController -FindAllDiscoverable
foreach -Parallel ($Controller in $Controllers) {
$AdsiObject = [ADSI]"LDAP://$($Controller.Name)/$($InputObject.distinguishedName)"
$Output = $AdsiObject
# | Show-DsEntry
#Add-Member -InputObject $Output -MemberType NoteProperty -Name 'DomainController' -Value $Controller.Name
#Add-Member -InputObject $Output -MemberType NoteProperty -Name 'Site' -Value $Controller.SiteName -Force
Write-Output $Output
}
}
#>
Function Get-DsForest {
Write-Output ([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest())
}
Function Get-DsDomain {
param(
[string]$DomainName
)
if ($DomainName)
{
$DirectoryContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain", $DomainName)
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DirectoryContext)
Write-Output $Domain
}
else
{
$Domain = [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
Write-Output $Domain
}
}
function Get-DsDomainEntry {
param(
[Parameter()]
[string]$LdapServer = (([DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).name.ToString()),
[Parameter()]
[int32]$LdapPort = 389
)
[adsi]("LDAP://{0}:{1}" -f $LdapServer, $LdapPort)
}
Function Get-DsTrustedDomain {
([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).GetAllTrustRelationships()
}
function Get-DsDomainController {
param(
[switch]$FindAllDiscoverable,
[switch]$FindAll
)
if ($FindAllDiscoverable) { [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().FindAllDiscoverableDomainControllers() }
elseif ($FindAll) { [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().FindAllDomainControllers()}
else {[DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().FindDomainController()}
}
function Get-DsTimeSkew {
param(
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]
$ComputerName = $(Get-DsDomainController).Name
)
New-TimeSpan -Seconds (w32tm /stripchart /dataonly /computer:$ComputerName /samples:1)[3].split(' ')[1].TrimEnd('s')
}
function Test-DsTimeSkew {
param(
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]
$ComputerName = $(Get-DsDomainController).Name
)
$MaxTimeSkew = New-TimeSpan -Minutes 5
$IsTimeSkewWithinLimit = $(Get-DsTimeSkew -ComputerName $ComputerName).Duration() -lt $MaxTimeSkew
Write-Output $IsTimeSkewWithinLimit
}
function ConvertFrom-SID
{
param(
[Parameter(Mandatory)]
[string]$SID
)
(New-Object System.Security.Principal.SecurityIdentifier($SID)).Translate( [System.Security.Principal.NTAccount])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment