├── MrAD ├── MrAD.psd1 ├── MrAD.psm1 └── public │ ├── Get-MrADUser.ps1 │ ├── Get-MrADLockOutInfo.ps1 │ ├── Test-MrADUserPassword.ps1 │ └── Compare-MrADGroup.ps1 ├── README.md ├── .gitattributes ├── .gitignore └── LICENSE /MrAD/MrAD.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikefrobbins/ActiveDirectory/HEAD/MrAD/MrAD.psd1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ActiveDirectory 2 | PowerShell Scripts, Functions, and Modules for managing Active Directory 3 | -------------------------------------------------------------------------------- /MrAD/MrAD.psm1: -------------------------------------------------------------------------------- 1 | #Dot source all functions in all ps1 files located in the module's public and private folders, excluding tests and profiles. 2 | Get-ChildItem -Path $PSScriptRoot\public\*.ps1, $PSScriptRoot\private\*.ps1 -Exclude *.tests.ps1, *profile.ps1 -ErrorAction SilentlyContinue | 3 | ForEach-Object { 4 | . $_.FullName 5 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mike F Robbins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MrAD/public/Get-MrADUser.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | function Get-MrADUser { 3 | 4 | [CmdletBinding()] 5 | param( 6 | [Parameter(Mandatory, 7 | ValueFromPipeline, 8 | ValueFromPipelineByPropertyName)] 9 | [String[]]$UserName 10 | ) 11 | 12 | PROCESS { 13 | 14 | foreach ($user in $UserName){ 15 | 16 | $Search = [adsisearcher]"(&(objectCategory=person)(objectClass=user)(samaccountname=$user))" 17 | 18 | foreach ($user in $($Search.FindAll())){ 19 | 20 | $stringSID = (New-Object -TypeName System.Security.Principal.SecurityIdentifier($($user.Properties.objectsid),0)).Value 21 | $objectGUID = [System.Guid]$($user.Properties.objectguid) 22 | 23 | [pscustomobject]@{ 24 | DistinguishedName = $($user.Properties.distinguishedname) 25 | Enabled = (-not($($user.GetDirectoryEntry().InvokeGet('AccountDisabled')))) 26 | GivenName = $($user.Properties.givenname) 27 | Name = $($user.Properties.name) 28 | ObjectClass = $($user.Properties.objectclass)[-1] 29 | ObjectGUID = $objectGUID 30 | SamAccountName = $($user.Properties.samaccountname) 31 | SID = $stringSID 32 | Surname = $($user.Properties.sn) 33 | UserPrincipalName = $($user.Properties.userprincipalname) 34 | } 35 | 36 | } 37 | 38 | } 39 | 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /MrAD/public/Get-MrADLockOutInfo.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | function Get-MrADLockOutInfo { 3 | 4 | <# 5 | .SYNOPSIS 6 | Get-MrADLockOutInfo returns a list of users who were locked out in Active Directory. 7 | 8 | .DESCRIPTION 9 | Get-MrADLockOutInfo is an advanced function that returns a list of users who were locked out in Active Directory 10 | by querying the event logs on the PDC emulator in the domain. 11 | 12 | .PARAMETER UserName 13 | The userid of the specific user you are looking for lockouts for. The default is all locked out users. 14 | 15 | .PARAMETER StartTime 16 | The datetime to start searching the event logs from. The default is the past three days. 17 | 18 | .PARAMETER Credential 19 | Specifies a user account that has permission to read the security event log on the PDC emulator. The default is 20 | the current user. 21 | 22 | .EXAMPLE 23 | Get-MrADLockOutInfo 24 | 25 | .EXAMPLE 26 | Get-MrADLockOutInfo -Credential (Get-Credential) 27 | 28 | .EXAMPLE 29 | Get-MrADLockOutInfo -UserName 'mikefrobbins' 30 | 31 | .EXAMPLE 32 | Get-MrADLockOutInfo -StartTime (Get-Date).AddDays(-1) 33 | 34 | .EXAMPLE 35 | Get-MrADLockOutInfo -UserName 'mikefrobbins' -StartTime (Get-Date).AddDays(-1) -Credential (Get-Credential) 36 | #> 37 | 38 | [CmdletBinding()] 39 | param ( 40 | [ValidateNotNullOrEmpty()] 41 | [string]$DomainName = $env:USERDOMAIN, 42 | 43 | [ValidateNotNullOrEmpty()] 44 | [string]$UserName = '*', 45 | 46 | [ValidateNotNullOrEmpty()] 47 | [datetime]$StartTime = (Get-Date).AddDays(-3), 48 | 49 | [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty 50 | ) 51 | 52 | try { 53 | $ErrorActionPreference = 'Stop' 54 | 55 | $PdcEmulator = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain(( 56 | New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $DomainName)) 57 | ).PdcRoleOwner.name 58 | 59 | Write-Verbose -Message "The PDC emulator in your forest root domain is: $PdcEmulator" 60 | $ErrorActionPreference = 'Continue' 61 | } 62 | catch { 63 | Write-Error -Message 'Unable to query the domain. Verify the user running this script has read access to Active Directory and try again.' 64 | } 65 | 66 | $Params = @{} 67 | If ($PSBoundParameters['Credential']) { 68 | $Params.Credential = $Credential 69 | } 70 | 71 | Invoke-Command -ComputerName $PdcEmulator { 72 | Get-WinEvent -FilterHashtable @{LogName='Security';Id=4740;StartTime=$Using:StartTime} | 73 | Where-Object {$_.Properties[0].Value -like "$Using:UserName"} | 74 | Select-Object -Property TimeCreated, 75 | @{Label='UserName';Expression={$_.Properties[0].Value}}, 76 | @{Label='ClientName';Expression={$_.Properties[1].Value}} 77 | } @Params | 78 | Select-Object -Property TimeCreated, UserName, ClientName 79 | } -------------------------------------------------------------------------------- /MrAD/public/Test-MrADUserPassword.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 -Modules ActiveDirectory 2 | function Test-MrADUserPassword { 3 | 4 | <# 5 | .SYNOPSIS 6 | Test-MrADUserPassword is a function for testing an Active Directory user account for a specific password. 7 | 8 | .DESCRIPTION 9 | Test-MrADUserPassword is an advanced function for testing one or more Active Directory user accounts for a 10 | specific password. 11 | 12 | .PARAMETER UserName 13 | The username for the Active Directory user account. 14 | 15 | .PARAMETER Password 16 | The password to test for. 17 | 18 | .PARAMETER ComputerName 19 | A server or computer name that has PowerShell remoting enabled. 20 | 21 | .PARAMETER InputObject 22 | Accepts the output of Get-ADUser. 23 | 24 | .EXAMPLE 25 | Test-MrADUserPassword -UserName alan0 -Password Password1 -ComputerName Server01 26 | 27 | .EXAMPLE 28 | 'alan0'. 'andrew1', 'frank2' | Test-MrADUserPassword -Password Password1 -ComputerName Server01 29 | 30 | .EXAMPLE 31 | Get-ADUser -Filter * -SearchBase 'OU=AdventureWorks Users,OU=Users,OU=Test,DC=mikefrobbins,DC=com' | 32 | Test-MrPassword -Password Password1 -ComputerName Server01 33 | 34 | .INPUTS 35 | String, Microsoft.ActiveDirectory.Management.ADUser 36 | 37 | .OUTPUTS 38 | PSCustomObject 39 | 40 | .NOTES 41 | Author: Mike F Robbins 42 | Website: http://mikefrobbins.com 43 | Twitter: @mikefrobbins 44 | #> 45 | 46 | [CmdletBinding(DefaultParameterSetName='Parameter Set UserName')] 47 | param ( 48 | [Parameter(Mandatory, 49 | ValueFromPipeline, 50 | ValueFromPipelineByPropertyName, 51 | ParameterSetName='Parameter Set UserName')] 52 | [Alias('SamAccountName')] 53 | [string[]]$UserName, 54 | 55 | [Parameter(Mandatory)] 56 | [string]$Password, 57 | 58 | [Parameter(Mandatory)] 59 | [string]$ComputerName, 60 | 61 | [Parameter(ValueFromPipeline, 62 | ParameterSetName='Parameter Set InputObject')] 63 | [Microsoft.ActiveDirectory.Management.ADUser]$InputObject 64 | 65 | ) 66 | 67 | BEGIN { 68 | $Pass = ConvertTo-SecureString $Password -AsPlainText -Force 69 | 70 | $Params = @{ 71 | ComputerName = $ComputerName 72 | ScriptBlock = {Get-Random | Out-Null} 73 | ErrorAction = 'SilentlyContinue' 74 | ErrorVariable = 'Results' 75 | } 76 | } 77 | 78 | PROCESS { 79 | if ($PSBoundParameters.UserName) { 80 | Write-Verbose -Message 'Input received via the "UserName" parameter set.' 81 | $Users = $UserName 82 | } 83 | elseif ($PSBoundParameters.InputObject) { 84 | Write-Verbose -Message 'Input received via the "InputObject" parameter set.' 85 | $Users = $InputObject 86 | } 87 | 88 | foreach ($User in $Users) { 89 | 90 | if (-not($Users.SamAccountName)) { 91 | Write-Verbose -Message "Querying Active Directory for UserName $($User)" 92 | $User = Get-ADUser -Identity $User 93 | } 94 | 95 | $Params.Credential = (New-Object System.Management.Automation.PSCredential ($($User.UserPrincipalName), $Pass)) 96 | 97 | Invoke-Command @Params 98 | 99 | [pscustomobject]@{ 100 | UserName = $User.SamAccountName 101 | PasswordCorrect = 102 | switch ($Results.FullyQualifiedErrorId -replace ',.*$') { 103 | LogonFailure {$false; break} 104 | AccessDenied {$true; break} 105 | default {$true} 106 | } 107 | } 108 | 109 | } 110 | 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /MrAD/public/Compare-MrADGroup.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 -Modules ActiveDirectory 2 | function Compare-MrADGroup { 3 | 4 | <# 5 | .SYNOPSIS 6 | Compares the groups of a the specified Active Directory users. 7 | 8 | .DESCRIPTION 9 | Compare-MrADGroup is a function that retrieves a list of all the Active 10 | Directory groups that the specified Active Directory users are a member 11 | of. It determines what groups are common between the users based on 12 | membership of 50% or more of the specified users. It then compares the 13 | specified users group membership to the list of common groups and returns 14 | a list of users whose group membership differentiates from that list. A 15 | minus (-) in the status column means the user is not a member of a common 16 | group and a plus (+) means the user is a member of an additional group. 17 | 18 | .PARAMETER UserName 19 | The Active Directory user(s) account object to compare. Can be specified 20 | in the form or SamAccountName, Distinguished Name, or GUID. This parameter 21 | is mandatory. 22 | 23 | .PARAMETER IncludeEqual 24 | Switch parameter to include common groups that the specified user is a 25 | member of. An equals (=) sign means the user is a member of a common group. 26 | 27 | .EXAMPLE 28 | Compare-MrADGroup -UserName 'jleverling', 'lcallahan', 'mpeacock' 29 | 30 | .EXAMPLE 31 | 'jleverling', 'lcallahan', 'mpeacock' | Compare-MrADGroup -IncludeEqual 32 | 33 | .EXAMPLE 34 | Get-ADUser -Filter {Department -eq 'Sales' -and Enabled -eq 'True'} | 35 | Compare-MrADGroup 36 | 37 | .INPUTS 38 | String 39 | 40 | .OUTPUTS 41 | PSCustomObject 42 | 43 | .NOTES 44 | Author: Mike F Robbins 45 | Website: http://mikefrobbins.com 46 | Twitter: @mikefrobbins 47 | #> 48 | 49 | [CmdletBinding()] 50 | param ( 51 | [Parameter(Mandatory, 52 | ValueFromPipeline)] 53 | [string[]]$UserName, 54 | 55 | [switch]$IncludeEqual 56 | ) 57 | 58 | BEGIN { 59 | $Params = @{} 60 | 61 | If ($PSBoundParameters['IncludeEqual']) { 62 | $Params.IncludeEqual = $true 63 | } 64 | } 65 | 66 | PROCESS { 67 | foreach ($name in $UserName) { 68 | try { 69 | Write-Verbose -Message "Attempting to query Active Directory of user: '$name'." 70 | [array]$users += Get-ADUser -Identity $name -Properties MemberOf -ErrorAction Stop 71 | } 72 | catch { 73 | Write-Warning -Message "An error occured. Error Details: $_.Exception.Message" 74 | } 75 | } 76 | } 77 | 78 | END { 79 | Write-Verbose -Message "The `$users variable currently contains $($users.Count) items." 80 | 81 | $commongroups = ($groups = $users | 82 | Select-Object -ExpandProperty MemberOf | 83 | Group-Object) | 84 | Where-Object Count -ge ($users.Count / 2) | 85 | Select-Object -ExpandProperty Name 86 | 87 | Write-Verbose -Message "There are $($commongroups.Count) groups with 50% or more of the specified users in them." 88 | 89 | foreach ($user in $users) { 90 | Write-Verbose -Message "Checking user: '$($user.SamAccountName)' for group differences." 91 | 92 | $differences = Compare-Object -ReferenceObject $commongroups -DifferenceObject $user.MemberOf @Params 93 | 94 | foreach ($difference in $differences) { 95 | [PSCustomObject]@{ 96 | UserName = $user.SamAccountName 97 | GroupName = $difference.InputObject -replace '^CN=|,.*$' 98 | Status = switch ($difference.SideIndicator){'<='{'-';break}'=>'{'+';break}'=='{'=';break}} 99 | 'RatioOfUsersInGroup(%)' = ($groups | Where-Object name -eq $difference.InputObject).Count / $users.Count * 100 -as [int] 100 | } 101 | } 102 | } 103 | } 104 | } --------------------------------------------------------------------------------