Created
July 27, 2014 13:48
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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