├── A02 ├── 01_Preparations.ps1 ├── 02_Domain_Infos.ps1 └── 03_Replication.ps1 ├── A03 ├── 01_Create_User.ps1 ├── 02_Create_User_Bulk.ps1 ├── 03_Create_Group_add_Member.ps1 ├── 04_Managing_AD_Objects.ps1 ├── 05_Create_OUs.ps1 ├── 06_Move_Objects_OU.ps1 ├── 07_gMSA.ps1 └── users.csv ├── A04 ├── 01_Resetting_Password_Unlocking_Accounts.ps1 ├── 02_Search_stale_accounts.ps1 ├── 03_Users_without_Manager.ps1 ├── 04_Password_Expiration.ps1 ├── 05_Group_Membership_Report.ps1 └── 06_Account_Events.ps1 ├── A05 ├── 01_Create_AD_Backup.ps1 ├── 02_Create_PSO.ps1 ├── 03_Recycle_Bin.ps1 ├── 04_Change_Users_UPN.ps1 └── 05_Password_Expiration.ps1 ├── Email_prep.ps1 ├── Links.txt ├── README.md ├── UserGroups.xlsx └── automate ├── .DS_Store ├── A01 ├── 01_02_Creating_New_Users_from_Spreadsheet.ps1 ├── 01_03_Using_an_Existing_User_as_Template.ps1 ├── 01_04_Reset_Password.ps1 ├── 01_05_Creating_and_Populating_New_Groups.ps1 └── UserUpdate.xlsx ├── A02 ├── .DS_Store ├── 02_01_Creating_Group_Policies.ps1 ├── 02_02_Backup_and_restore_GPO.ps1 └── 02_03_Finding_Unused_Group_Policy_Objects.ps1 ├── A03 ├── 03_01_Active_Directory_Replication.ps1 ├── 03_02_Defender_protection.ps1 ├── 03_03_Inactiveuser_Report.ps1 ├── 03_04_Move_FSMO.ps1 ├── 03_05_Creating_Printable_Contact_List.ps1 └── 03_06_Generating_Group_Membership_Report.ps1 └── Links.txt /A02/01_Preparations.ps1: -------------------------------------------------------------------------------- 1 | #Declare variables 2 | $domainName = "corp.pri" 3 | $dsrmPassword = ConvertTo-SecureString "yourpassword" -AsPlainText -Force 4 | $NetbiosName = "CORP" 5 | 6 | #Install the AD Domain Services role 7 | Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools -IncludeAllSubFeature 8 | 9 | #Import the ServerManager module 10 | Import-Module ServerManager 11 | 12 | #Install the AD Domain Services 13 | Install-ADDSForest ` 14 | -CreateDnsDelegation:$false ` 15 | -DatabasePath "C:\Windows\NTDS" ` 16 | -DomainMode "WinThreshold" ` 17 | -DomainName $domainName ` 18 | -DomainNetbiosName $NetbiosName ` 19 | -ForestMode "WinThreshold" ` 20 | -InstallDns:$true ` 21 | -LogPath "C:\Windows\NTDS" ` 22 | -NoRebootOnCompletion:$true ` 23 | -SysvolPath "C:\Windows\SYSVOL" ` 24 | -Force:$true ` 25 | -SafeModeAdministratorPassword $dsrmPassword 26 | 27 | #Install RSAT Tools 28 | Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 29 | 30 | #(Optional) Install all RSAT Tools 31 | Get-WindowsCapability -Name RSAT* -Online | Add-WindowsCapability -Online 32 | 33 | #Import AD-Module 34 | Import-Module ActiveDirectory 35 | 36 | #Displaying the number of CMDLETs from the AD module 37 | (Get-Command -Module ActiveDirectory).count -------------------------------------------------------------------------------- /A02/02_Domain_Infos.ps1: -------------------------------------------------------------------------------- 1 | #Search for some master roles 2 | Get-ADDomain corp | Select-Object InfrastructureMaster, RIDMaster, PDCEmulator 3 | 4 | #The PDCEmulator is important to know for the Event IDs: 4625 and 4740 5 | #These contain information about bad password and account blocking 6 | 7 | #Search for some master roles 8 | Get-ADForest corp | Select-Object DomainNamingMaster, SchemaMaster 9 | 10 | #List domaincontrollers and OperationMasterRoles 11 | Get-ADDomainController -Filter * | Select-Object Name, Domain, Forest, OperationMasterRoles 12 | 13 | #Search RSAT tool 14 | Get-WindowsCapability -Online | Where-Object -Property Name -Like *group* 15 | 16 | #Install RSAT Tools 17 | Add-WindowsCapability -Online -Name Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0 -------------------------------------------------------------------------------- /A02/03_Replication.ps1: -------------------------------------------------------------------------------- 1 | #Check the replication errors 2 | Get-ADReplicationFailure -Target dc01 3 | 4 | #For a given domain controller we can find its inbound replication partners 5 | Get-ADReplicationPartnerMetadata -Target dc01.corp.pri 6 | 7 | #We can list down all the inbound replication partners for given domain 8 | Get-ADReplicationPartnerMetadata -Target "corp.pri" -Scope Domain 9 | 10 | #We can review AD replication site objects 11 | Get-ADReplicationSite -Filter * 12 | 13 | #We can review AD replication site links on the AD forest 14 | Get-ADReplicationSiteLink -Filter * -------------------------------------------------------------------------------- /A03/01_Create_User.ps1: -------------------------------------------------------------------------------- 1 | #We are looking for the cmdlet 2 | Get-Command *aduser* 3 | 4 | #Create a new user, but how? 5 | Get-Help New-ADUser -Examples 6 | 7 | #Lets update the help files 8 | Update-help * -UICulture en-US -Force 9 | 10 | #Create a user 11 | New-ADUser BobS 12 | 13 | #Account is created, but the account is inactive (password is missing) and doesn't have much additional info 14 | Get-ADUser -Identity Bobs 15 | 16 | #Delete the account 17 | Remove-ADUser -Identity BobS 18 | 19 | #Create the account again 20 | New-ADUser -Name BobS -Department Technik -Title Manager -City Luzern 21 | 22 | #Yes, the details are correct, but still inactive 23 | Get-ADUser -Identity Bobs -Properties City, Department, Title 24 | 25 | #Delete the account 26 | Remove-ADUser -Identity BobS 27 | 28 | #Create the account again (I can't do that, but why?) 29 | New-ADUser -Name BobS -Department Technik -Title Manager -City Luzern -AccountPassword "Pass123!" 30 | 31 | #Let's look at it and the help 32 | Get-Help New-ADUser -Parameter accountpassword 33 | Get-Help ConvertTo-SecureString 34 | 35 | #Create a variable with the "secure" password 36 | $newPassword = ConvertTo-SecureString -String "Pass123!" -AsPlainText -Force 37 | 38 | #Now we create the account again 39 | New-ADUser -name BobS -Department Technik -Title Manager -City Luzern -AccountPassword $newPassword -Enabled $true 40 | 41 | #Let's check 42 | Get-ADUser -Identity Bobs -Properties City, Department, Title -------------------------------------------------------------------------------- /A03/02_Create_User_Bulk.ps1: -------------------------------------------------------------------------------- 1 | #Importing the .csv file 2 | $ADUsers = Import-Csv "C:\GitHub\Active_Directory_Manage_with_PowerShell\A03\users.csv" -Delimiter ";" 3 | 4 | #UPN-Suffix 5 | $UPN = "corp.pri" 6 | 7 | foreach ($User in $ADUsers) { 8 | 9 | #Here is a listing 10 | $username = $User.username 11 | $password = $User.password 12 | $firstname = $User.firstname 13 | $lastname = $User.lastname 14 | $initials = $User.initials 15 | $email = $User.email 16 | $streetaddress = $User.streetaddress 17 | $city = $User.city 18 | $zipcode = $User.zipcode 19 | $state = $User.state 20 | $telephone = $User.telephone 21 | $jobtitle = $User.jobtitle 22 | $company = $User.company 23 | $department = $User.department 24 | 25 | #Warning, if user already exists! 26 | if (Get-ADUser -Filter { SamAccountName -eq $username }) { 27 | Write-Warning "A user account with username $username already exists in Active Directory." 28 | } 29 | else { 30 | 31 | #If user does not exist yet: 32 | New-ADUser ` 33 | -SamAccountName $username ` 34 | -UserPrincipalName "$username@$UPN" ` 35 | -Name "$firstname $lastname" ` 36 | -GivenName $firstname ` 37 | -Surname $lastname ` 38 | -Initials $initials ` 39 | -Enabled $True ` 40 | -DisplayName "$lastname, $firstname" ` 41 | -City $city ` 42 | -PostalCode $zipcode ` 43 | -Company $company ` 44 | -State $state ` 45 | -StreetAddress $streetaddress ` 46 | -OfficePhone $telephone ` 47 | -EmailAddress $email ` 48 | -Title $jobtitle ` 49 | -Department $department ` 50 | -AccountPassword (ConvertTo-secureString $password -AsPlainText -Force) -ChangePasswordAtLogon $True 51 | 52 | #Output: 53 | Write-Host "The user account $username is created." -ForegroundColor Cyan 54 | } 55 | } -------------------------------------------------------------------------------- /A03/03_Create_Group_add_Member.ps1: -------------------------------------------------------------------------------- 1 | #Create new group 2 | New-ADGroup -Name "Marketing" -GroupScope DomainLocal 3 | New-ADGroup -Name "Logistics" -GroupScope Global 4 | 5 | #By default, a security group is created "GroupCategory: Security". 6 | Get-ADGroup "Marketing" 7 | 8 | #Create a new group with more information 9 | New-ADGroup -Name 'Tech' ` 10 | -Description 'Security group for all tech users' ` 11 | -DisplayName 'Tech' ` 12 | -GroupCategory Security ` 13 | -GroupScope Global ` 14 | -SAMAccountName 'Tech' ` 15 | -PassThru 16 | 17 | #Add user to group 18 | Add-ADGroupMember -Identity 'Tech' -Members "Boris.Jones", "Leonard.Clark" -PassThru 19 | 20 | #Did it work? (As far as OK, but I had to "search" the account specifically). 21 | Get-ADGroupMember -Identity 'Tech' 22 | 23 | #This works even better 24 | New-ADGroup -Name 'Manager' ` 25 | -Description 'Security group for all managers' ` 26 | -DisplayName 'Manager' ` 27 | -GroupCategory Security ` 28 | -GroupScope Global ` 29 | -SAMAccountName 'Manager' ` 30 | -PassThru 31 | 32 | #Create a variable 33 | $ManagerArray = (Get-ADUser -Filter {Title -like "*Manager*" } ` 34 | -Properties Title).SAMAccountName 35 | 36 | #Is the variable OK? 37 | $ManagerArray 38 | 39 | #Now we add the content of the variable to the group 40 | Add-ADGroupMember -Identity "Manager" -Members $ManagerArray -PassThru 41 | 42 | #Did it work? 43 | Get-ADGroupMember -Identity Manager ` 44 | | Get-ADUser -Properties Title ` 45 | | Format-Table -AutoSize SAMAccountName,Name,Title -------------------------------------------------------------------------------- /A03/04_Managing_AD_Objects.ps1: -------------------------------------------------------------------------------- 1 | #We need to change the scope 2 | Set-ADGroup "Marketing" -GroupScope Universal 3 | 4 | #Control 5 | Get-ADGroup "Marketing" 6 | 7 | #Then surely we can change from Global to Domainlocal? 8 | Get-ADGroup "Logistics" 9 | Set-ADGroup "Logistics" -GroupScope DomainLocal 10 | 11 | #This can be done only by an intermediate step 12 | Set-ADGroup "Logistics" -GroupScope Universal 13 | Set-ADGroup "Logistics" -GroupScope Domainlocal 14 | 15 | #Did it work? 16 | Get-ADGroup "Logistics" 17 | 18 | #We need a new security group, no problem! 19 | New-ADGroup -Name "IT" -GroupScope Global 20 | 21 | #We need to add the accounts from IT to this group, which users are in IT? 22 | Get-ADUser -Filter {department -eq "IT"} -Properties department 23 | 24 | #Perfect, then I can extend this right away (Error, why? Add-ADGroupMember wants a list with groups not Members) 25 | Get-ADUser -Filter {department -eq "IT"} -Properties department | Add-ADGroupMember "IT" 26 | 27 | #OK, this is how it works 28 | Get-ADUser -Filter {department -eq "IT"} -Properties department | Add-ADPrincipalGroupMembership -MemberOf "IT" 29 | 30 | #Did it work? 31 | Get-ADGroupMember "IT" | Get-ADUser -Properties department 32 | 33 | #Which groups is Jonathan Fisher in? 34 | Get-ADPrincipalGroupMembership "Jonathan.Fisher" -------------------------------------------------------------------------------- /A03/05_Create_OUs.ps1: -------------------------------------------------------------------------------- 1 | #Create a new OU 2 | New-ADOrganizationalUnit -Name "Engineers" 3 | 4 | #Short check 5 | Get-ADOrganizationalUnit -Filter * 6 | 7 | #Still two new OU's 8 | New-ADOrganizationalUnit -Name "Luzern" 9 | 10 | New-ADOrganizationalUnit -Path "OU=Luzern,DC=prime,DC=pri" -Name "Engineers" 11 | 12 | #Now there is a problem where is the OU Engineers? 13 | Get-ADOrganizationalUnit Engineers 14 | 15 | #What does the help say? 16 | Get-Help Get-ADOrganizationalUnit 17 | Get-Help Get-ADOrganizationalUnit -Parameter identity 18 | 19 | #Identify the OUs 20 | Get-ADOrganizationalUnit -Identity "OU=Engineers,OU=Luzern,DC=prime,DC=pri" 21 | Get-ADOrganizationalUnit -Identity "OU=Engineers,DC=prime,DC=pri" 22 | 23 | #Error, correctly I have to specify the path 24 | Remove-ADOrganizationalUnit "Engineers" 25 | 26 | #Access is denied, but I am logged in as admin 27 | Remove-ADOrganizationalUnit "OU=Engineers,DC=prime,DC=pri" 28 | 29 | #With which account am I logged in? 30 | whoami 31 | 32 | #Let's take a close look at the OU 33 | Get-ADOrganizationalUnit "OU=Engineers,DC=prime,DC=pri" -Properties * 34 | 35 | #We set the value to False 36 | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $false -Identity "OU=Engineers,DC=prime,DC=pri" 37 | 38 | #Now we can delete the OU 39 | Remove-ADOrganizationalUnit "OU=Engineers,DC=prime,DC=pri" 40 | 41 | #Did it work? 42 | Get-ADOrganizationalUnit -Identity "OU=Engineers,DC=prime,DC=pri" -------------------------------------------------------------------------------- /A03/06_Move_Objects_OU.ps1: -------------------------------------------------------------------------------- 1 | #The AD has no command for OUs to move content 2 | Get-Command *org* 3 | 4 | #We need to help ourselves with the cmdlet get-adobject. What does the help give us? 5 | Get-Help Get-ADObject -Examples 6 | 7 | #Let's search for accounts 8 | Get-ADObject -SearchBase "DC=prime,DC=pri" -Filter * 9 | 10 | #By department 11 | Get-ADUser -Filter "department -eq 'IT'" 12 | 13 | #By department and city 14 | Get-ADUser -Filter "department -eq 'IT' -and city -eq 'Luzern'" 15 | 16 | #Listed a little bit better 17 | Get-ADUser -Filter "department -eq 'IT' -and city -eq 'Luzern'" -Properties department, city | Select-Object name, city, department 18 | 19 | #Now we move these three accounts 20 | Get-ADUser -Filter "department -eq 'IT' -and city -eq 'Luzern'" -Properties department, city | Move-ADObject -TargetPath "OU=Engineers,OU=Luzern,DC=prime,DC=pri" 21 | 22 | #Did it work? 23 | #So we do not get a list 24 | Get-ADObject -SearchBase "OU=Engineers,OU=Luzern,DC=prime,DC=pri" -Filter * 25 | 26 | #So is better 27 | $OUpath = "OU=Engineers,OU=Luzern,DC=prime,DC=pri" 28 | Get-ADUser -Filter * -SearchBase $OUpath | Select-object Name, UserPrincipalName -------------------------------------------------------------------------------- /A03/07_gMSA.ps1: -------------------------------------------------------------------------------- 1 | #The first step, create the root key 2 | 3 | #Use this command in productive environment (Important wait 10h - replication) 4 | Add-KdsRootKey -EffectiveImmediately 5 | 6 | #This command is intended for a test environment 7 | Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)) 8 | 9 | #Create a new group 10 | New-ADGroup -Name TestMSA ` 11 | -GroupScope DomainLocal ` 12 | -Description "Group for servers of TestMSA" ` 13 | -DisplayName "Test gMSA group" ` 14 | -GroupCategory Security ` 15 | -SAMAccountName TestMSA ` 16 | -PassThru 17 | 18 | #To this group I now add the "Members 19 | Add-ADGroupMember -Identity TestMSA ` 20 | -Members "dc01$","dc02$" ` 21 | -PassThru 22 | 23 | #Control 24 | Get-ADGroupMember -Identity TestMSA 25 | 26 | #Now create a new account 27 | New-ADServiceAccount -Name SvcAcnt1 ` 28 | -DNSHostName SvcAcnt1.corp.pri ` 29 | -PassThru 30 | 31 | #The account will be edited now 32 | Set-ADServiceAccount -Identity SvcAcnt1 ` 33 | -PrincipalsAllowedToRetrieveManagedPassword TestMSA ` 34 | -PrincipalsAllowedToDelegateToAccount TestMSA ` 35 | -PassThru 36 | 37 | #Before running this cmdlet, the systems must be restarted (so that group membership is applied) 38 | Invoke-Command -ComputerName dc02 -ScriptBlock {Restart-Computer -Force} 39 | 40 | #Install the service account on DC02 41 | Invoke-Command -ComputerName dc02 -ScriptBlock {Install-ADServiceAccount -Identity SvcAcnt1} 42 | 43 | #Control 44 | Invoke-Command -ComputerName dc02 -ScriptBlock {Test-ADServiceAccount -Identity SvcAcnt1} 45 | 46 | #Now in services we can select this account for a specific service -------------------------------------------------------------------------------- /A03/users.csv: -------------------------------------------------------------------------------- 1 | FirstName;Initials;Lastname;Username;Email;StreetAddress;City;ZipCode;Country;Department;Password;Telephone;JobTitle 2 | Max;MF;Pane;Max.Pane;Max.Pane@prime.pri;Bahnhofstrasse 8;Bern;3000;Switzerland;IT;Q+/7_]Tc;44123456780;Engineer 3 | Piers;PB;Dodge;Piers.Dodge;Piers.Dodge@prime.pri;Bahnhofstrasse 8;Bern;3000;Switzerland;Marketing;RW-cn3N);44123456781;Manager 4 | Kylie;KD;Davidson;Kylie.Davidson;Kylie.Davidson@prime.pri;Bahnhofstrasse 8;Bern;3000;Switzerland;IT;3VKr2.Wm;44123456782;Engineer 5 | Richard;RG;Grant;Richard.Grant;Richard.Grant@prime.pri;Bahnhofstrasse 8;Bern;3000;Switzerland;Marketing;)N3ZYJvS;44123456783;Teamleader 6 | Boris;BC;Jones;Boris.Jones;Boris.Jones@prime.pri;Bahnhofstrasse 8;Bern;3000;Switzerland;IT;9ZesQ]pq;44123456784;Engineer 7 | Nicholas;NM;Murray;Nicholas.Murray;Nicholas.Murray@prime.pri;Bahnhofstrasse 8;Luzern;6000;Switzerland;IT;KX*rB72p;44123456785;Manager 8 | Leonard;LC;Clark;Leonard.Clark;Leonard.Clark@prime.pri;Bahnhofstrasse 8;Luzern;6000;Switzerland;IT;AJ+(}c3$;44123456786;Engineer 9 | Ruth;RD;Dickens;Ruth.Dickens;Ruth.Dickens@prime.pri;Bahnhofstrasse 8;Luzern;6000;Switzerland;Logistics;Jgv4{Bb$;44123456787;Manager 10 | Jonathan;JF;Fisher;Jonathan.Fisher;Johnathan.Fisher@prime.pri;Bahnhofstrasse 8;Luzern;6000;Switzerland;IT;u*PQJAx5;44123456788;Engineer 11 | Grace;GR;Rees;Grace.Rees;Grace.Rees@prime.pri;Bahnhofstrasse 8;Luzern;6000;Switzerland;Logistics;w([6p&Kt;44123456789;Manager -------------------------------------------------------------------------------- /A04/01_Resetting_Password_Unlocking_Accounts.ps1: -------------------------------------------------------------------------------- 1 | #Get-Member 2 | Get-ADUser -Filter * -Properties * | Get-Member -MemberType property 3 | 4 | #Resetting passwords 5 | #Current state 6 | Get-ADUser 'Jonathan.Fisher' -Properties PasswordExpired,LockedOut | Format-Table Name,PasswordExpired,LockedOut 7 | 8 | #Reset the password 9 | $securePassword = ConvertTo-SecureString 'P@ssw0rd' -AsPlainText -Force 10 | Set-ADAccountPassword 'Jonathan.Fisher' -NewPassword $securePassword -Reset 11 | 12 | #Force a password change 13 | Set-ADUser 'Jonathan.Fisher' -ChangePasswordAtLogon $true 14 | 15 | #Current state 16 | Get-ADUser 'Jonathan.Fisher' -Properties PasswordExpired,LockedOut | Format-Table Name,PasswordExpired,LockedOut 17 | 18 | #Unlocking accounts 19 | #Current State 20 | Get-ADUser 'Leonard.Clark' -Properties LockedOut | Format-Table Name,LockedOut 21 | 22 | #Unlock that account 23 | Unlock-ADAccount 'Leonard.Clark' -------------------------------------------------------------------------------- /A04/02_Search_stale_accounts.ps1: -------------------------------------------------------------------------------- 1 | #Let me explain my "stale" 2 | #1. Haven't logged in for X days 3 | #2. Hasn't logged in 4 | #3. Created at least X days ago 5 | 6 | #Using Search-ADAccount 7 | Search-ADAccount -AccountInactive -TimeSpan '90.00:00:00' -UsersOnly 8 | 9 | #Using a filter 10 | Get-ADUser "Leonard.Clark" -Properties LastLogonTimeStamp | Select-Object Name,LastLogonTimeStamp 11 | 12 | #If it is older than $LogonDate 13 | $LogonDate = (Get-Date).AddHours(-1).ToFileTime() 14 | Get-ADUser -Filter {LastLogonTimeStamp -lt $LogonDate} 15 | 16 | #If it doesn't have value 17 | Get-ADUser -Filter {LastLogonTimeStamp -notlike "*"} -Properties LastLogonTimeStamp | 18 | Select-Object Name,LastLogonTimeStamp 19 | 20 | #And if the account was created before $createdDate 21 | $createdDate = (Get-Date).AddDays(-14) 22 | Get-ADUser -Filter {Created -lt $createdDate} -Properties Created | 23 | Select-Object Name,Created 24 | 25 | #Add them all together: 26 | $filter = { 27 | ((LastLogonTimeStamp -lt $logonDate) -or (LastLogonTimeStamp -notlike "*")) 28 | -and (Created -lt $createdDate) 29 | } 30 | 31 | Get-ADuser -Filter $filter | Select-Object SamAccountName 32 | 33 | #Functionize it 34 | Function Get-ADStaleUsers { 35 | [cmdletbinding()] 36 | Param ( 37 | [datetime]$NoLogonSince = (Get-Date).AddDays(-90), 38 | [datetime]$CreatedBefore = (Get-Date).AddDays(-14) 39 | ) 40 | $NoLogonString = $NoLogonSince.ToFileTime() 41 | $filter = { 42 | ((LastLogonTimeStamp -lt $NoLogonString) -or (LastLogonTimeStamp -notlike "*")) 43 | -and (Created -lt $createdBefore) 44 | } 45 | Write-Host $filter 46 | Get-ADuser -Filter $filter 47 | } 48 | 49 | #Usage 50 | Get-ADStaleUsers 51 | 52 | #Usage 53 | Get-ADStaleUsers -NoLogonSince (Get-Date).AddDays(-30) -CreatedBefore (Get-Date).AddDays(-1) -------------------------------------------------------------------------------- /A04/03_Users_without_Manager.ps1: -------------------------------------------------------------------------------- 1 | #Define needed info 2 | $properties = 'Name','Department','Title','GivenName','SurName' 3 | 4 | #Get those users 5 | Get-ADUser -Filter * -Properties * | Format-Table $properties 6 | 7 | #We can filter for specific managers 8 | Get-ADUser -Filter {Manager -eq 'Nicholas.Murray'} 9 | 10 | #But not empty manager 11 | Get-ADUser -Filter {Manager -eq ''} 12 | 13 | #Using an LDAPFilter 14 | Get-ADUser -LDAPFilter "(!manager=*)" -Properties Manager | Format-Table Name,Manager 15 | 16 | #Combine both into an LDAP filter 17 | $properties += 'Manager' 18 | $ldapFilter = "(|(!$($properties[0])=*)" 19 | For($x=1;$x -lt $properties.count; $x++){ 20 | $ldapFilter += "(!$($properties[$x])=*)" 21 | } 22 | $ldapFilter += ')' 23 | $ldapFilter 24 | 25 | Get-ADUser -LDAPFilter $ldapFilter -Properties $properties | Format-Table $properties -------------------------------------------------------------------------------- /A04/04_Password_Expiration.ps1: -------------------------------------------------------------------------------- 1 | #Getting the password expiration date 2 | #msDS-UserPasswordExpiryTimeComputed property 3 | $userParams = @{ 4 | Identity = 'Leonard.Clark' 5 | Properties = 'Name','msDS-UserPasswordExpiryTimeComputed' 6 | } 7 | Get-ADUser @userParams | Format-Table $userParams['Properties'] 8 | 9 | #Save to a variable 10 | $user = Get-ADUser @userParams 11 | 12 | #Try Get Date 13 | Get-Date $user.'msDS-UserPasswordExpiryTimeComputed' 14 | 15 | #.NET 16 | [datetime]::FromFileTime($user.'msDS-UserPasswordExpiryTimeComputed') 17 | $expirationDate = [datetime]::FromFileTime($user.'msDS-UserPasswordExpiryTimeComputed') 18 | 19 | #Now how far away is that? 20 | New-TimeSpan -Start (Get-Date) -End $expirationDate 21 | 22 | #Finding all users' with soon expiring passwords 23 | #First we need a filter: 24 | $filter = {Enabled -eq $true -and PasswordNeverExpires -eq $false} 25 | 26 | #Get all those users 27 | Get-ADUser -Filter $filter 28 | 29 | #Then define what 'soon' is 30 | $days = 7 31 | 32 | #Convert that to filetime 33 | $date = (Get-Date).AddDays($days).ToFileTime() 34 | 35 | $date 36 | 37 | #And get all the users 38 | Get-ADUser -Filter $filter -Properties 'msDS-UserPasswordExpiryTimeComputed' | ` 39 | Where-Object {$_.'msDS-UserPasswordExpiryTimeComputed' -lt $date} | Select-Object UserPrincipalName -------------------------------------------------------------------------------- /A04/05_Group_Membership_Report.ps1: -------------------------------------------------------------------------------- 1 | #Some Preparations 2 | Install-Module ImportExcel 3 | Import-Module ImportExcel 4 | 5 | #Gather info 6 | #Single User's group membership: 7 | (Get-ADUser 'Leonard.Clark' -Properties MemberOf).MemberOf 8 | 9 | #Nicely formated 10 | (Get-ADUser 'Leonard.Clark' -Properties MemberOf).MemberOf | ForEach-Object {Get-ADGroup $_} 11 | 12 | #Multiple Users 13 | Get-ADUser -Filter {Title -like '*Engineer*'} -Properties MemberOf 14 | 15 | #Format 16 | $users = Get-ADUser -Filter {Title -like '*Engineer*'} -Properties MemberOf 17 | foreach($user in $users){ 18 | [pscustomobject]@{ 19 | Name = $user.Name 20 | User = $user.SamAccountName 21 | Memberships = ($user.MemberOf | ForEach-Object{Get-ADGroup $_}).Name 22 | } 23 | } 24 | 25 | #Make it presentable 26 | $userGroups = @() 27 | $users = Get-ADUser -Filter {Title -like '*Engineer*'} -Properties MemberOf 28 | foreach($user in $users){ 29 | $userGroups += [pscustomobject]@{ 30 | User = $user.SamAccountName 31 | Name = $user.Name 32 | Memberships = ($user.MemberOf | ForEach-Object{Get-ADGroup $_}).Name -join ', ' 33 | } 34 | } 35 | $userGroups | Export-Excel .\UserGroups.xlsx -Title 'Engineer Group Memberships' 36 | 37 | #Validate 38 | Import-Excel .\UserGroups.xlsx -StartRow 2 -------------------------------------------------------------------------------- /A04/06_Account_Events.ps1: -------------------------------------------------------------------------------- 1 | #Remote Session 2 | Enter-PSSession -ComputerName DC01 3 | 4 | #Prep work for lockouts 5 | #Account lockout Event ID 6 | $LockOutID = 4740 7 | 8 | #Find the PDC 9 | (Get-ADDomain).PDCEmulator 10 | $PDCEmulator = (Get-ADDomain).PDCEmulator 11 | 12 | #Query event log 13 | Get-WinEvent -ComputerName $PDCEmulator -FilterHashtable @{ 14 | LogName = 'Security' 15 | ID = $LockOutID 16 | } 17 | 18 | #Parse the event 19 | #Assign to a variable 20 | $events = Get-WinEvent -ComputerName $PDCEmulator -FilterHashtable @{ 21 | LogName = 'Security' 22 | ID = $LockOutID 23 | } 24 | 25 | #Examine some properties 26 | $events[0].Message 27 | 28 | #Cool, but not as easy as: 29 | $events[0].Properties 30 | $events[0].Properties[1].Value 31 | 32 | #For all events: 33 | ForEach($event in $events){ 34 | [pscustomobject]@{ 35 | UserName = $event.Properties[0].Value 36 | CallerComputer = $event.Properties[1].Value 37 | TimeStamp = $event.TimeCreated 38 | } 39 | } -------------------------------------------------------------------------------- /A05/01_Create_AD_Backup.ps1: -------------------------------------------------------------------------------- 1 | #Session to DC01 2 | Enter-PSSession -ComputerName DC01 3 | 4 | #Install feature 5 | Install-WindowsFeature -Name Windows-Server-Backup 6 | 7 | #Update-Help 8 | Update-Help -Module WindowsServerBackup -Force 9 | 10 | #A list of modules, but not very helpful 11 | Get-Command -Module WindowsServerBackup 12 | 13 | #This is a bit better 14 | Get-Command -Module WindowsServerBackup | Sort-Object Noun,Verb | Format-Table -AutoSize Verb,Noun 15 | 16 | #We start with a new policy 17 | $newWbPol = New-WBPolicy 18 | 19 | #Which drives are present 20 | Get-WBVolume -AllVolumes 21 | 22 | #The backup of drive C 23 | $wbVol = Get-WBVolume -VolumePath C: 24 | 25 | #The drive will be added to the policy 26 | Add-WBVolume -Policy $newWBPol -Volume $wbVol 27 | 28 | #The following 2 variables are used to include and exclude files 29 | $incFSpec = New-WBFileSpec -FileSpec "C:\Temp" 30 | $excFSpec = New-WBFileSpec -FileSpec "C:\ps" -Exclude 31 | 32 | #These two variables are added to the policy 33 | Add-WBFileSpec -Policy $newWBPol -FileSpec $incFSpec 34 | Add-WBFileSpec -Policy $newWBPol -FileSpec $excFSpec 35 | 36 | #Let's quickly look at the contents of the variables 37 | $newWBPol 38 | 39 | #A new variable with the contents of the disks 40 | $wbDisks = Get-WBDisk 41 | 42 | #Which disk do I write the backup to 43 | $wbDisks 44 | 45 | #Add the disk to the policy 46 | $wbTarget = New-WBBackupTarget -Disk $wbDisks[1] 47 | Add-WBBackupTarget -Policy $newWBPol -Target $wbTarget 48 | 49 | #With BMR 50 | Add-WBBareMetalRecovery -Policy $newWBPol 51 | 52 | #Is set to "True" 53 | $newWBPol 54 | 55 | #Incl. Systemstate 56 | Add-WBSystemState -Policy $newWBPol 57 | 58 | #Schedule 59 | Set-WBSchedule -Policy $newWBPol -Schedule 12:00,20:00 60 | 61 | #is now created 62 | $newWBPol 63 | 64 | #Before I make another change to the policy, I save the settings in the following variable 65 | $curPol = Get-WBPolicy 66 | 67 | #Do not overwrite the backup 68 | Set-WBPolicy -Policy $newWBPol -AllowDeleteOldBackups:$False -Force 69 | 70 | #Did it work? 71 | Get-WBPolicy 72 | 73 | #Lets go! 74 | Start-WBBackup -Policy $newWBPol 75 | 76 | #Some Infos 77 | Get-WBSummary -------------------------------------------------------------------------------- /A05/02_Create_PSO.ps1: -------------------------------------------------------------------------------- 1 | #What are the settings? 2 | Get-ADDefaultDomainPasswordPolicy 3 | 4 | #New OU for executives 5 | New-ADOrganizationalUnit CFO 6 | 7 | #And a group 8 | New-ADGroup -Name "Executives" ` 9 | -GroupScope Universal ` 10 | -Description "Executives of corp.pri" ` 11 | -GroupCategory "Security" ` 12 | -Path "OU=CFO,DC=corp,DC=pri" ` 13 | -SAMAccountName "Executives" ` 14 | -PassThru 15 | 16 | #New CFO needs an account 17 | New-ADUser -Name "Erika Meister" ` 18 | -GivenName "Erika" ` 19 | -SurName "Meister" ` 20 | -Department "Finance" ` 21 | -Description "Chief Financial Officer" ` 22 | -ChangePasswordAtLogon $True ` 23 | -EmailAddress "Erika.Meister@corp.pri" ` 24 | -Enabled $True ` 25 | -PasswordNeverExpires $False ` 26 | -SAMAccountName "Erika.Meister" ` 27 | -AccountPassword (ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force) ` 28 | -Title "Chief Financial Officer" ` 29 | -PassThru 30 | 31 | #This account is a member of the new group 32 | Add-ADPrincipalGroupMembership -Identity "Erika.Meister" ` 33 | -MemberOf "Executives" ` 34 | -PassThru 35 | 36 | #Did it work? 37 | Get-ADGroupMember "Executives" | Select-Object SamAccountName 38 | 39 | #Now we create a PSO 40 | New-ADFineGrainedPasswordPolicy ` 41 | -description:"Minimum 12 characters for all executives" ` 42 | -LockoutDuration 00:10:00 ` 43 | -LockoutObservationWindow 00:10:00 ` 44 | -LockoutThreshold 5 ` 45 | -MaxPasswordAge 65.00:00:00 ` 46 | -MinPasswordLength 12 ` 47 | -Name:"Management Pwd Policy" ` 48 | -Precedence 10 ` 49 | -PassThru 50 | 51 | #We set this new PSO to the new group 52 | Get-ADGroup -Identity "Executives" ` 53 | | Add-ADFineGrainedPasswordPolicySubject ` 54 | -Identity "Management Pwd Policy" 55 | 56 | #And see if it worked => check can also be done in AD management center 57 | Get-ADFineGrainedPasswordPolicySubject -Identity "Management Pwd Policy" -------------------------------------------------------------------------------- /A05/03_Recycle_Bin.ps1: -------------------------------------------------------------------------------- 1 | #Gather Information 2 | Get-ADOptionalFeature -Identity "Recycle Bin Feature" 3 | 4 | #Enable 5 | Enable-ADOptionalFeature ` 6 | -Identity "Recycle Bin Feature" ` 7 | -Scope ForestOrConfigurationSet ` 8 | -Target "corp.pri" ` 9 | -Confirm:$False 10 | 11 | #Search for a user 12 | Get-ADUser -Identity "Boris.Jones" 13 | 14 | #Delete 15 | Get-ADUser -Identity "Boris.Jones" | Remove-ADUser -Confirm:$False 16 | 17 | #We check 18 | Get-ADUser -Identity "Boris.Jones" 19 | 20 | #We look closer 21 | Get-ADObject -Filter {Name -like "Boris Jones*"} -IncludeDeletedObjects 22 | 23 | #Restore 24 | Get-ADObject -Filter {Name -like "Boris Jones*"} ` 25 | -IncludeDeletedObjects | Restore-ADObject 26 | 27 | #We check 28 | Get-ADObject -Filter {Name -like "Boris Jones"} -------------------------------------------------------------------------------- /A05/04_Change_Users_UPN.ps1: -------------------------------------------------------------------------------- 1 | #Get a list of the UPN suffixes 2 | Get-ADForest | Format-List UPNSuffixes 3 | 4 | #Let’s add the UPN suffix 5 | Get-ADForest | Set-ADForest -UPNSuffixes @{add="tomrocks.ch"} 6 | 7 | #Get a list of the UPN suffixes 8 | Get-ADForest | Format-List UPNSuffixes 9 | 10 | #List of all the AD Users in the organization 11 | Get-ADUser -Filter * | Sort-Object Name | Format-Table Name, UserPrincipalName 12 | 13 | #Change the UPN for all the AD users in the organization 14 | $LocalUsers = Get-ADUser -Filter {UserPrincipalName -like '*corp.pri'} -Properties UserPrincipalName -ResultSetSize $null 15 | $LocalUsers | ForEach-Object {$newUpn = $_.UserPrincipalName.Replace("corp.pri","tomrocks.ch"); $_ | Set-ADUser -UserPrincipalName $newUpn} 16 | 17 | #Confirm that the UPN is changed 18 | Get-ADUser -Filter * | Sort-Object Name | Format-Table Name, UserPrincipalName -------------------------------------------------------------------------------- /A05/05_Password_Expiration.ps1: -------------------------------------------------------------------------------- 1 | #Getting the password expiration date 2 | #msDS-UserPasswordExpiryTimeComputed property 3 | $userParams = @{ 4 | Identity = 'Leonard.Clark' 5 | Properties = 'Name','msDS-UserPasswordExpiryTimeComputed' 6 | } 7 | Get-ADUser @userParams | Format-Table $userParams['Properties'] 8 | 9 | #Save to a variable 10 | $user = Get-ADUser @userParams 11 | 12 | #Try Get Date 13 | Get-Date $user.'msDS-UserPasswordExpiryTimeComputed' 14 | 15 | #.NET 16 | [datetime]::FromFileTime($user.'msDS-UserPasswordExpiryTimeComputed') 17 | $expirationDate = [datetime]::FromFileTime($user.'msDS-UserPasswordExpiryTimeComputed') 18 | 19 | #Now how far away is that? 20 | New-TimeSpan -Start (Get-Date) -End $expirationDate 21 | 22 | #Finding all users' with soon expiring passwords 23 | #First we need a filter: 24 | $filter = {Enabled -eq $true -and PasswordNeverExpires -eq $false} 25 | 26 | #Get all those users 27 | Get-ADUser -Filter $filter 28 | 29 | #Then define what 'soon' is 30 | $days = 7 31 | 32 | #Convert that to filetime 33 | $date = (Get-Date).AddDays($days).ToFileTime() 34 | 35 | $date 36 | 37 | #And get all the users 38 | Get-ADUser -Filter $filter -Properties 'msDS-UserPasswordExpiryTimeComputed' | ` 39 | Where-Object {$_.'msDS-UserPasswordExpiryTimeComputed' -lt $date} | Select-Object UserPrincipalName 40 | 41 | #Function to send an email 42 | Function Send-ADPasswordReminders { 43 | [cmdletbinding()] 44 | param ( 45 | [int]$DaysTillExpiration, 46 | [string]$From, 47 | [pscredential]$EmailCredential = $cred 48 | ) 49 | $htmlTemplate = @" 50 |
Your password expires soon. In fact, it expires in {1}.
52 |Make sure you reset it before it becomes a problem 😊
53 |Thanks!
54 |Your friendly, neighborhood PowerShell automation system.
55 | "@ 56 | $adUserParams = @{ 57 | Filter = {Enabled -eq $true -and PasswordNeverExpires -eq $false} 58 | Properties = 'msDS-UserPasswordExpiryTimeComputed','EmailAddress' 59 | } 60 | $expFileTime = (Get-Date).AddDays($DaysTillExpiration).ToFileTime() 61 | $users = Get-ADUser @adUserParams | Where-Object {$_.'msDS-UserPasswordExpiryTimeComputed' -lt $expFileTime} 62 | ForEach ($user in $users){ 63 | $ts = New-TimeSpan -Start (Get-Date) -End ([datetime]::FromFileTime($user.'msDS-UserPasswordExpiryTimeComputed')) 64 | $html = $htmlTemplate -f $User.GivenName, "$($ts.Days) days" 65 | $EmailParams = @{ 66 | To = $user.UserPrincipalName 67 | From = $from 68 | Subject = 'Password Expiration Notification' 69 | Body = $html 70 | BodyAsHtml = $true 71 | UseSSL = $true 72 | Port = 587 73 | SmtpServer = 'smtp.office365.com' 74 | Credential = $EmailCredential 75 | } 76 | Send-MailMessage @EmailParams 77 | } 78 | } 79 | 80 | # Usage 81 | Send-ADPasswordReminders -DaysTillExpiration 50 -From $params['From'] -------------------------------------------------------------------------------- /Email_prep.ps1: -------------------------------------------------------------------------------- 1 | $cred = Get-Credential 2 | 3 | $params = @{ 4 | To = 'email@email.com' 5 | From = 'email@email.com' 6 | Credential = $cred 7 | Subject = 'Email subject line' 8 | Body = 'this is the paragraph
' 9 | BodyAsHtml = $true 10 | SmtpServer = 'smtp.office365.com' 11 | Port = 587 12 | UseSSL = $true 13 | } 14 | 15 | 16 | $global:From = 'email@email.com' 17 | $global:To = 'email@email.com' -------------------------------------------------------------------------------- /Links.txt: -------------------------------------------------------------------------------- 1 | https://docs.microsoft.com/en-us/powershell/module/activedirectory/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Active Directory Manage with PowerShell 2 | That's what this repo is all about! 3 | -------------------------------------------------------------------------------- /UserGroups.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomwechsler/Active_Directory_Manage_with_PowerShell/9fe836fe02bd3a8efc6bf2052b3e23919e991d5a/UserGroups.xlsx -------------------------------------------------------------------------------- /automate/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomwechsler/Active_Directory_Manage_with_PowerShell/9fe836fe02bd3a8efc6bf2052b3e23919e991d5a/automate/.DS_Store -------------------------------------------------------------------------------- /automate/A01/01_02_Creating_New_Users_from_Spreadsheet.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Enter-PSSession -Computername DC01 3 | Set-Location C:\ps\ 4 | Install-Module ImportExcel -Verbose -Force 5 | Import-Module ImportExcel 6 | Import-Module ActiveDirectory 7 | #> 8 | 9 | # Show modules 10 | Get-Module ImportExcel 11 | Get-Module ActiveDirectory 12 | 13 | (Get-ADDomainController).Name 14 | 15 | #region prep work 16 | # Import the spreadsheet 17 | $SpreadSheet = 'C:\ps\UserUpdate.xlsx' 18 | $Data = Import-Excel $SpreadSheet 19 | 20 | # Check the data 21 | $Data | Format-Table 22 | 23 | # Correlate fields 24 | $expectedProperties = @{ 25 | Name = 'Full Name' 26 | GivenName = 'First Name' 27 | SurName = 'Last Name' 28 | Title = 'Job Title' 29 | Department = 'Department' 30 | OfficePhone = 'Phone Number' 31 | } 32 | 33 | # Correlate 'Manager' field 34 | Get-Help New-ADUser -Parameter Manager 35 | 36 | <#