├── 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 |

Hello {0},

51 |

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 = '

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 | <# can be: 37 | SamAccountName 38 | DistinguishedName 39 | GUID 40 | SID 41 | #> 42 | 43 | Get-ADUser $Data[0].Manager 44 | 45 | Get-ADUser $Data[0].Manager.Replace(' ','.') 46 | 47 | # Manager 48 | $Data[0].Manager.Replace(' ','.') 49 | 50 | # SamAccountName 51 | "$($Data[0].'First Name').$($Data[0].'Last Name')" 52 | 53 | # Create a single user 54 | $user = $Data[0] 55 | $params = @{} 56 | ForEach($property in $expectedProperties.GetEnumerator()){ 57 | # If the new user has the property 58 | If($user."$($property.value)".Length -gt 0){ 59 | # Add it to the splat 60 | $params["$($property.Name)"] = $user."$($property.value)" 61 | } 62 | } 63 | # Deal with other values 64 | If($user.Manager.length -gt 0){ 65 | $params['Manager'] = $user.Manager.Replace(' ','.') 66 | } 67 | $params['SamAccountName'] = "$($user.$($expectedProperties['GivenName'])).$($user.$($expectedProperties['SurName']))" 68 | # Create the user 69 | New-ADUser @params 70 | 71 | # Did it work 72 | Get-ADUser $params.SamAccountName 73 | 74 | #endregion 75 | 76 | #region Create a function 77 | Function Import-ADUsersFromSpreadsheet { 78 | [cmdletbinding()] 79 | Param( 80 | [ValidatePattern('.*\.xlsx$')] 81 | [ValidateNotNullOrEmpty()] 82 | [string]$PathToSpreadsheet 83 | ) 84 | # Hashtable to correlate properties 85 | $expectedProperties = @{ 86 | Name = 'Full Name' 87 | GivenName = 'First Name' 88 | SurName = 'Last Name' 89 | Title = 'Job Title' 90 | Department = 'Department' 91 | OfficePhone = 'Phone Number' 92 | } 93 | # Make sure the xlsx exists 94 | If(Test-Path $PathToSpreadsheet){ 95 | $data = Import-Excel $PathToSpreadsheet 96 | ForEach($user in $data){ 97 | # Build a splat 98 | $params = @{} 99 | ForEach($property in $expectedProperties.GetEnumerator()){ 100 | # If the new user has the property 101 | If($user."$($property.value)".Length -gt 0){ 102 | # Add it to the splat 103 | $params["$($property.Name)"] = $user."$($property.value)" 104 | } 105 | } 106 | # Deal with other values 107 | If($user.Manager.length -gt 0){ 108 | $params['Manager'] = $user.Manager.Replace(' ','.') 109 | } 110 | $params['SamAccountName'] = "$($user.$($expectedProperties['GivenName'])).$($user.$($expectedProperties['SurName']))" 111 | # Create the user 112 | New-ADUser @params 113 | } 114 | } 115 | } 116 | 117 | # Usage 118 | Import-ADUsersFromSpreadsheet -PathToSpreadsheet '.\UserUpdate.xlsx' 119 | 120 | # Verify 121 | ForEach($user in $data){ 122 | Get-ADUser "$($user.'First Name').$($user.'Last Name')" | Select-Object Name 123 | } 124 | #endregion -------------------------------------------------------------------------------- /automate/A01/01_03_Using_an_Existing_User_as_Template.ps1: -------------------------------------------------------------------------------- 1 | #region Create a template user 2 | New-ADUser -Name 'Template User' -Enabled $false 3 | 4 | # Set all your template properties 5 | Set-ADUser 'Template User' -StreetAddress 'Bahnhofstrasse' -City 'Luzern' -State 'Luzern' -PostalCode '6000' 6 | 7 | # Add any groups 8 | $BaseGroups = 'AlleBenutzer','FreigabeZugriffAlle' 9 | ForEach($group in $BaseGroups){ 10 | Add-ADGroupMember $group -Members 'Template User' 11 | } 12 | 13 | # Verify 14 | Get-ADUser 'Template User' -Properties StreetAddress,City,State,PostalCode,MemberOf 15 | 16 | #endregion 17 | 18 | #region Creating users from the template 19 | # Retrieve the template user 20 | $user = Get-ADUser 'Template User' -Properties StreetAddress,City,State,PostalCode,MemberOf 21 | 22 | # Create a single user from that 23 | New-ADUser 'Walter White' -GivenName 'Walter' -Surname 'White' -Instance $user 24 | 25 | # Check Groups 26 | (Get-ADUser 'Walter White' -Properties MemberOf).MemberOf 27 | 28 | # Add that user to the same groups 29 | ForEach($group in $user.MemberOf){ 30 | Add-ADGroupMember $group -Members 'Walter White' 31 | } 32 | 33 | # Verify 34 | Get-ADUser 'Walter White' -Properties StreetAddress,City,State,PostalCode 35 | (Get-ADUser 'Walter White' -Properties MemberOf).MemberOf 36 | 37 | #endregion 38 | 39 | #region Function time! 40 | # Create your spreadsheet users using the template as well 41 | Function Import-ADUsersFromSpreadsheet { 42 | [cmdletbinding( 43 | DefaultParameterSetName = 'Plain' 44 | )] 45 | Param( 46 | [ValidatePattern('.*\.xlsx$')] 47 | [ValidateNotNullOrEmpty()] 48 | [Parameter( 49 | ParameterSetName = 'FromTemplate' 50 | )] 51 | [Parameter( 52 | ParameterSetName = 'Plain' 53 | )] 54 | [string]$PathToSpreadsheet, 55 | [Parameter( 56 | ParameterSetName = 'FromTemplate', 57 | Mandatory = $true 58 | )] 59 | [Microsoft.ActiveDirectory.Management.ADUser]$TemplateUser, 60 | [Parameter( 61 | ParameterSetName = 'FromTemplate' 62 | )] 63 | [ValidateNotNullOrEmpty()] 64 | [string[]]$Properties = @('StreetAddress','City','State','PostalCode') 65 | ) 66 | # Hashtable to correlate properties 67 | $expectedProperties = @{ 68 | Name = 'Full Name' 69 | GivenName = 'First Name' 70 | SurName = 'Last Name' 71 | Title = 'Job Title' 72 | Department = 'Department' 73 | OfficePhone = 'Phone Number' 74 | } 75 | # Make sure the xlsx exists 76 | If(Test-Path $PathToSpreadsheet){ 77 | $data = Import-Excel $PathToSpreadsheet 78 | ForEach($user in $data){ 79 | # Build a splat 80 | $params = @{} 81 | ForEach($property in $expectedProperties.GetEnumerator()){ 82 | # If the new user has the property 83 | If($user."$($property.value)".Length -gt 0){ 84 | # Add it to the splat 85 | $params["$($property.Name)"] = $user."$($property.value)" 86 | } 87 | } 88 | # Deal with other values 89 | If($user.Manager.length -gt 0){ 90 | $params['Manager'] = $user.Manager.Replace(' ','.') 91 | } 92 | $params['SamAccountName'] = "$($user.$($expectedProperties['GivenName'])).$($user.$($expectedProperties['SurName']))" 93 | # Create the user 94 | If($PSCmdlet.ParameterSetName -eq 'Plain'){ 95 | New-ADUser @params 96 | }ElseIf($PSCmdlet.ParameterSetName -eq 'FromTemplate'){ 97 | $props = $Properties + 'MemberOf' 98 | $template = Get-ADUser $TemplateUser -Properties $props 99 | New-ADUser @params -Instance $template 100 | ForEach($group in $template.MemberOf){ 101 | Add-ADGroupMember $group -Members $params['samaccountname'] 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | # Usage 109 | Import-ADUsersFromSpreadsheet -PathToSpreadsheet '.\UserUpdate.xlsx' -TemplateUser 'Template User' 110 | 111 | # Verify 112 | $SpreadSheet = '.\UserUpdate.xlsx' 113 | $data = Import-Excel $SpreadSheet 114 | ForEach($user in $data){ 115 | Get-ADUser "$($user.'First Name').$($user.'Last Name')" -Properties StreetAddress,MemberOf | Select-Object Name,StreetAddress,MemberOf 116 | } 117 | 118 | #endregion 119 | 120 | #region Enabling the account 121 | Set-ADUser 'Walter White' -Enabled $true 122 | 123 | # Generate a random password 124 | # [system.web.security.membership]::GeneratePassword(a,b) a = length, b = minimum non-alphanumeric characters 125 | # May need to: Add-Type -AssemblyName System.Web 126 | $randomPassword = [System.Web.Security.Membership]::GeneratePassword(10,1) 127 | 128 | # Set the new account with this info 129 | Set-ADAccountPassword -Identity 'Walter White' -NewPassword (ConvertTo-SecureString $randomPassword -AsPlainText -Force) -Reset 130 | 131 | # Enable the account 132 | Set-ADUser 'Walter White' -Enabled $true -ChangePasswordAtLogon $true 133 | 134 | # Verify 135 | Get-ADUser 'Walter White' -------------------------------------------------------------------------------- /automate/A01/01_04_Reset_Password.ps1: -------------------------------------------------------------------------------- 1 | #region Resetting passwords 2 | # Current state 3 | Get-ADUser 'Walter White' -Properties PasswordExpired,LockedOut | Format-Table Name,PasswordExpired,LockedOut 4 | 5 | # Reset the password 6 | $securePassword = ConvertTo-SecureString 'IWillNotForgetMyPasswordEverAgain8675309!' -AsPlainText -Force 7 | Set-ADAccountPassword 'Walter White' -NewPassword $securePassword -Reset 8 | 9 | # Force a password change 10 | Set-ADUser 'Walter White' -ChangePasswordAtLogon $true 11 | 12 | #endregion 13 | 14 | #region Functioning password resets 15 | Function Reset-ADUserPassword { 16 | [cmdletbinding( 17 | DefaultParameterSetName = 'Random' 18 | )] 19 | Param ( 20 | [Parameter( 21 | ValueFromPipeline = $true, 22 | ValueFromPipelineByPropertyName = $true, 23 | ParameterSetName = 'Plain', 24 | Position = 1 25 | )] 26 | [Parameter( 27 | ValueFromPipeline = $true, 28 | ValueFromPipelineByPropertyName = $true, 29 | ParameterSetName = 'Random', 30 | Position = 1 31 | )] 32 | [Microsoft.ActiveDirectory.Management.ADUser]$Identity, 33 | [Parameter( 34 | ParameterSetName = 'Plain', 35 | Mandatory = $true 36 | )] 37 | [ValidateNotNullOrEmpty()] 38 | [string]$Password 39 | ) 40 | Begin{ 41 | If($PSCmdlet.ParameterSetName -eq 'Plain'){ 42 | # If $Password is specified, convert it to a secure string 43 | $securePassword = ConvertTo-SecureString $Password -AsPlainText -Force 44 | }ElseIf($PSCmdlet.ParameterSetName -eq 'Random'){ 45 | # Otherwise add this type to use the GeneratePassword method 46 | Add-Type -AssemblyName System.Web 47 | } 48 | } 49 | Process{ 50 | If($PSCmdlet.ParameterSetName -eq 'Random'){ 51 | # Generate a new random password for each user 52 | $securePassword = ConvertTo-SecureString ([System.Web.Security.Membership]::GeneratePassword(10,1)) -AsPlainText -Force 53 | } 54 | # Set the password 55 | Set-ADAccountPassword $Identity -NewPassword $securePassword -Reset 56 | # Force a password change 57 | Set-ADUser $Identity -ChangePasswordAtLogon $true 58 | # Output the user's name and result 59 | [pscustomobject]@{ 60 | User = $Identity 61 | Password = [PScredential]::new("user",$SecurePassword).GetNetworkCredential().Password 62 | } 63 | } 64 | End{} 65 | } 66 | 67 | # Usage 68 | Reset-ADUserPassword 'Walter White' 69 | 70 | # Current State 71 | Get-ADUser -Filter {Title -like '*Health*'} -Properties PasswordExpired | Format-Table Name,PasswordExpired 72 | 73 | # Multipe accounts 74 | Get-ADUser -Filter {Title -like '*Health*'} | Reset-ADUserPassword -------------------------------------------------------------------------------- /automate/A01/01_05_Creating_and_Populating_New_Groups.ps1: -------------------------------------------------------------------------------- 1 | #region Creating groups 2 | # Global Security 3 | New-ADGroup 'Neueinstellungen' -GroupCategory Security -GroupScope Global 4 | 5 | # Verify 6 | Get-ADGroup 'Neueinstellungen' 7 | 8 | # Universal distribution 9 | New-ADGroup 'HR-Aktualisierungen' -GroupCategory Distribution -GroupScope Universal 10 | 11 | # Verify 12 | Get-ADGroup 'HR-Aktualisierungen' 13 | 14 | #endregion 15 | 16 | #region Populating a group 17 | # One user 18 | Add-ADGroupMember 'Neueinstellungen' -Members 'Walter White' 19 | 20 | # Verify 21 | Get-ADGroupMember 'Neueinstellungen' | Format-Table Name 22 | 23 | # Remove that user 24 | Remove-ADGroupMember 'Neueinstellungen' -Members 'Walter White' 25 | 26 | # Multiple Users 27 | Add-ADGroupMember 'Neueinstellungen' -Members 'Walter White','Esma.Font' 28 | 29 | # Add all users from a spreadsheet 30 | $SpreadSheet = '.\UserUpdate.xlsx' 31 | $Data = Import-Excel $SpreadSheet 32 | 33 | $data | ForEach-Object {Add-ADGroupMember 'Neueinstellungen' -Members $_.'Full Name'.replace(' ','.')} 34 | 35 | # Verify 36 | Get-ADGroupMember 'Neueinstellungen' | Format-Table Name 37 | 38 | # Manager group, current state 39 | (Get-ADGroupMember 'Managers').Count 40 | 41 | # Add users based on a filter 42 | Get-ADUser -Filter {Title -like '*manager*'} -Properties Title | Format-Table Name,Title 43 | Get-ADUser -Filter {Title -like '*manager*'} | ForEach-Object {Add-ADGroupMember 'Managers' -Members $_} 44 | 45 | # Verify 46 | (Get-ADGroupMember 'Managers').Count 47 | 48 | #endregion -------------------------------------------------------------------------------- /automate/A01/UserUpdate.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomwechsler/Active_Directory_Manage_with_PowerShell/9fe836fe02bd3a8efc6bf2052b3e23919e991d5a/automate/A01/UserUpdate.xlsx -------------------------------------------------------------------------------- /automate/A02/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomwechsler/Active_Directory_Manage_with_PowerShell/9fe836fe02bd3a8efc6bf2052b3e23919e991d5a/automate/A02/.DS_Store -------------------------------------------------------------------------------- /automate/A02/02_01_Creating_Group_Policies.ps1: -------------------------------------------------------------------------------- 1 | #Create a new Group Policy Object (GPO) 2 | New-GPO -Name "Desktop Einstellungen" 3 | 4 | #Get the GPO 5 | $GPO = Get-GPO -Name "Desktop Einstellungen" 6 | 7 | #Modify the GPO 8 | Set-GPRegistryValue -Name $GPO.DisplayName -Key "HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\ActiveDesktop" -ValueName 'NoChangingWallPaper' -Value 1 -Type Dword 9 | 10 | #Do Prevent changing desktop icons 11 | Set-GPRegistryValue -Name "Desktop Einstellungen" -Key "HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System" -ValueName 'NoDispBackgroundPage' -Value 1 -Type Dword 12 | 13 | #Desktop Wallpaper 14 | Set-GPRegistryValue -Name "Desktop Einstellungen" -Key "HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System" -ValueName 'WallpaperStyle' -Value 0 -Type Dword 15 | 16 | #Linking the GPO to the OU 17 | Get-GPO -Name "Desktop Einstellungen" | New-GPLink -target "OU=CFO,DC=corp,DC=pri" -LinkEnabled Yes 18 | 19 | #Create a new Group Policy Object (GPO) 20 | New-GPO -Name "TestGPO" 21 | 22 | #Configure a registry-based policy setting for a registry value 23 | $params = @{ 24 | Name = 'TestGPO' 25 | Key = 'HKCU\Software\Policies\Microsoft\Windows\Control Panel\Desktop' 26 | ValueName = 'ScreenSaveTimeOut' 27 | Value = 900 28 | Type = 'DWORD' 29 | } 30 | Set-GPRegistryValue @params 31 | 32 | #Configure a registry-based policy settings for multiple registry values 33 | $params = @{ 34 | Name = 'TestGPO' 35 | Key = 'HKCU\Software\Policies\Microsoft\ExampleKey' 36 | ValueName = 'ValueOne', 'ValueTwo', 'ValueThree' 37 | Value = 'String 1', 'String 2', 'String 3' 38 | Type = 'String' 39 | } 40 | Set-GPRegistryValue @params 41 | 42 | #Disable registry-based policy settings for a specific registry key 43 | Set-GPRegistryValue -Disable -Name 'TestGPO' -Key 'HKCU\Software\Policies\Microsoft\ExampleKey' -------------------------------------------------------------------------------- /automate/A02/02_02_Backup_and_restore_GPO.ps1: -------------------------------------------------------------------------------- 1 | #Step 1: Define the backup directory 2 | $backupDir = "C:\gpobackup" 3 | 4 | #Step 2: Create the backup directory 5 | New-Item -Path $backupDir -ItemType Directory -Force 6 | 7 | #Step 3: Backup the GPOs 8 | Backup-GPO -All -Path $backupDir 9 | 10 | #Step 4: Validate the backup 11 | Get-ChildItem -Path $backupDir 12 | 13 | #Step 5: Restore the GPOs 14 | Restore-GPO -Name "FirewallSettings" -Path $backupDir -------------------------------------------------------------------------------- /automate/A02/02_03_Finding_Unused_Group_Policy_Objects.ps1: -------------------------------------------------------------------------------- 1 | ### 2 | #A GPO that is either not linked or linked to empty OUs! 3 | ### 4 | 5 | #Sort OUs with GPO links by whether or not they have non-OU children 6 | 7 | #Get all OUs with GPO links: 8 | Get-ADOrganizationalUnit -Filter {LinkedGroupPolicyObjects -like "*"} | Format-Table Name 9 | 10 | #For each OU, we need to: 11 | $OU = 'OU=Desktop,OU=Luzern,DC=corp,DC=pri' 12 | Get-ADObject -Filter {ObjectClass -ne 'OrganizationalUnit'} -SearchBase $OU 13 | 14 | #Loop through them all 15 | ForEach($OU in Get-ADOrganizationalUnit -Filter {LinkedGroupPolicyObjects -like "*"}){ 16 | $objects = $null 17 | $objects = Get-ADObject -Filter {ObjectClass -ne 'OrganizationalUnit'} -SearchBase $OU 18 | If($objects){ 19 | [pscustomobject]@{ 20 | OU = $OU 21 | Empty = $false 22 | } 23 | }Else{ 24 | [pscustomobject]@{ 25 | OU = $OU 26 | Empty = $true 27 | } 28 | } 29 | } 30 | 31 | #Yes, functionize that please 32 | Function Get-ADOUStatus { 33 | param ( 34 | [string]$Filter = '*' 35 | ) 36 | ForEach($OU in Get-ADOrganizationalUnit -Filter $Filter){ 37 | $objects = $null 38 | $objects = Get-ADObject -Filter {ObjectClass -ne 'OrganizationalUnit'} -SearchBase $OU 39 | If($objects){ 40 | [pscustomobject]@{ 41 | OU = $OU 42 | Empty = $false 43 | LinkedGPOs = [bool]$OU.LinkedGroupPolicyObjects 44 | } 45 | }Else{ 46 | [pscustomobject]@{ 47 | OU = $OU 48 | Empty = $true 49 | LinkedGPOs = [bool]$OU.LinkedGroupPolicyObjects 50 | } 51 | } 52 | } 53 | } 54 | 55 | #Usage 56 | Get-ADOUStatus 57 | 58 | #Find GPOs linked to those empty OUs 59 | 60 | #Store the OU status in a variable 61 | $emptyOUs = Get-ADOUStatus | Where-Object {$_.Empty -and $_.LinkedGPOs} 62 | 63 | #Get the linked GPO Guids 64 | $emptyOUs[0].OU.LinkedGroupPolicyObjects 65 | 66 | #Convert it to a GPO 67 | $emptyOUs[0].OU.LinkedGroupPolicyObjects[0].Substring(4,36) 68 | #Or regex 69 | $emptyOUs[0].OU.LinkedGroupPolicyObjects[0] -match '^cn=\{(?[^\{\}]+)\}' 70 | $Matches.guid 71 | 72 | Get-GPO -Guid $emptyOUs[0].OU.LinkedGroupPolicyObjects[0].Substring(4,36) 73 | 74 | #Object to build output 75 | $GPOsLinkedToEmptyOUs = @() 76 | 77 | ForEach($OU in $emptyOUs.OU){ 78 | ForEach($GPOGuid in $OU.LinkedGroupPolicyObjects){ 79 | $GPO = Get-GPO -Guid $GPOGuid.Substring(4,36) 80 | Write-Host "GPO: '$($GPO.DisplayName)' is linked to empty OU: $($OU.Name)" 81 | If($GPOsLinkedToEmptyOUs.GPOId -contains $GPO.Id){ 82 | ForEach($LinkedGPO in ($GPOsLinkedToEmptyOUs | Where-Object {$_.GPOId -eq $GPO.Id})){ 83 | $LinkedGPO.EmptyOU = [string[]]$LinkedGPO.EmptyOU + "$($OU.DistinguishedName)" 84 | } 85 | }Else{ 86 | $GPOsLinkedToEmptyOUs += [PSCustomObject]@{ 87 | GPOName = $GPO.DisplayName 88 | GPOId = $GPO.Id 89 | EmptyOU = $OU.DistinguishedName 90 | NonEmptyOU = '' 91 | } 92 | } 93 | } 94 | } 95 | 96 | #result 97 | $GPOsLinkedToEmptyOUs | Format-List 98 | 99 | #Check if those GPOs are linked to any OUs with children 100 | $nonEmptyOUs = Get-ADOUStatus | Where-Object {-not $_.Empty} 101 | ForEach($OU in $nonEmptyOUs.OU){ 102 | ForEach($GPO in $GPOsLinkedToEmptyOUs){ 103 | ForEach($GPOGuid in $OU.LinkedGroupPolicyObjects){ 104 | If($GPOGuid.Substring(4,36) -eq $GPO.GPOId){ 105 | Write-Host "GPO: '$($GPO.GPOName)' also linked to non-empty OU: $($OU.Name)" 106 | If($GPO.NonEmptyOU){ 107 | $GPO.NonEmptyOU = [string[]]$GPO.NonEmptyOU + $OU.DistinguishedName 108 | }Else{ 109 | $GPO.NonEmptyOU = $OU.DistinguishedName 110 | } 111 | } 112 | } 113 | } 114 | } 115 | 116 | #Now 117 | $GPOsLinkedToEmptyOUs | Format-List 118 | 119 | #Bring it all together into a function with useful output 120 | Function Get-GPOStatus { 121 | [cmdletbinding()] 122 | Param() 123 | Function Get-ADOUStatus { 124 | param ( 125 | [string]$Filter = '*' 126 | ) 127 | ForEach($OU in Get-ADOrganizationalUnit -Filter $Filter){ 128 | $objects = $null 129 | $objects = Get-ADObject -Filter {ObjectClass -ne 'OrganizationalUnit'} -SearchBase $OU 130 | If($objects){ 131 | [pscustomobject]@{ 132 | OU = $OU 133 | Empty = $false 134 | LinkedGPOs = [bool]$OU.LinkedGroupPolicyObjects 135 | } 136 | }Else{ 137 | [pscustomobject]@{ 138 | OU = $OU 139 | Empty = $true 140 | LinkedGPOs = [bool]$OU.LinkedGroupPolicyObjects 141 | } 142 | } 143 | } 144 | } 145 | $OUs = Get-ADOUStatus | Where-Object {$_.LinkedGPOs} 146 | $GPOsLinkedToEmptyOUs = @() 147 | ForEach($OU in ($OUs | Where-Object {$_.empty}).OU){ 148 | ForEach($GPOGuid in $OU.LinkedGroupPolicyObjects){ 149 | $GPO = Get-GPO -Guid $GPOGuid.Substring(4,36) 150 | Write-Verbose "GPO: '$($GPO.DisplayName)' is linked to empty OU: $($OU.Name)" 151 | If($GPOsLinkedToEmptyOUs.GPOId -contains $GPO.Id){ 152 | ForEach($LinkedGPO in ($GPOsLinkedToEmptyOUs | Where-Object {$_.GPOId -eq $GPO.Id})){ 153 | $LinkedGPO.EmptyOU = [string[]]$LinkedGPO.EmptyOU + "$($OU.DistinguishedName)" 154 | } 155 | }Else{ 156 | $GPOsLinkedToEmptyOUs += [PSCustomObject]@{ 157 | GPOName = $GPO.DisplayName 158 | GPOId = $GPO.Id 159 | EmptyOU = $OU.DistinguishedName 160 | NonEmptyOU = '' 161 | } 162 | } 163 | } 164 | } 165 | ForEach($OU in ($OUs | Where-Object {-not $_.empty}).OU){ 166 | ForEach($GPO in $GPOsLinkedToEmptyOUs){ 167 | ForEach($GPOGuid in $OU.LinkedGroupPolicyObjects){ 168 | If($GPOGuid.Substring(4,36) -eq $GPO.GPOId){ 169 | Write-Verbose "GPO: '$($GPO.GPOName)' also linked to non-empty OU: $($OU.Name)" 170 | If($GPO.NonEmptyOU){ 171 | $GPO.NonEmptyOU = [string[]]$GPO.NonEmptyOU + $OU.DistinguishedName 172 | }Else{ 173 | $GPO.NonEmptyOU = $OU.DistinguishedName 174 | } 175 | } 176 | } 177 | } 178 | } 179 | $GPOsLinkedToEmptyOUs 180 | } 181 | 182 | #Usage 183 | Get-GPOStatus -Verbose | Format-List 184 | 185 | #Finding unused GPOs 186 | Get-GPOStatus | Where-Object {$_.EmptyOU -and -not $_.NonEmptyOU} -------------------------------------------------------------------------------- /automate/A03/03_01_Active_Directory_Replication.ps1: -------------------------------------------------------------------------------- 1 | # Active Directory Domain Controller Replication Status 2 | $domaincontroller = Read-Host 'What is your Domain Controller?' 3 | 4 | # Define Objects 5 | $report = New-Object PSObject -Property @{ 6 | ReplicationPartners = $null 7 | LastReplication = $null 8 | FailureCount = $null 9 | FailureType = $null 10 | FirstFailure = $null 11 | } 12 | 13 | # Replication Partners 14 | $report.ReplicationPartners = (Get-ADReplicationPartnerMetadata -Target $domaincontroller).Partner 15 | $report.LastReplication = (Get-ADReplicationPartnerMetadata -Target $domaincontroller).LastReplicationSuccess 16 | 17 | # Replication Failures 18 | $report.FailureCount = (Get-ADReplicationFailure -Target $domaincontroller).FailureCount 19 | $report.FailureType = (Get-ADReplicationFailure -Target $domaincontroller).FailureType 20 | $report.FirstFailure = (Get-ADReplicationFailure -Target $domaincontroller).FirstFailureTime 21 | 22 | # Format Output 23 | $report | Select-Object ReplicationPartners,LastReplication,FirstFailure,FailureCount,FailureType | Out-GridView -------------------------------------------------------------------------------- /automate/A03/03_02_Defender_protection.ps1: -------------------------------------------------------------------------------- 1 | #Status of Microsoft Defender 2 | Get-MpComputerStatus 3 | 4 | #Gets the history of threats detected on the computer 5 | Get-MpThreat 6 | 7 | #Gets known threats from the definitions catalog 8 | Get-MpThreatCatalog | more 9 | 10 | #Gets active and past malware threats that Windows Defender detected 11 | Get-MpThreatDetection 12 | 13 | #Settings on local machine 14 | Get-MpPreference 15 | 16 | #Settings on domain connected remote system 17 | Get-MpPreference -CimSession dc01 18 | 19 | #Adjust settings 20 | Set-MpPreference -DisableRemovableDriveScanning $false 21 | 22 | Set-MpPreference -ScanScheduleTime 17:00:00 23 | 24 | #Check for updates 25 | Update-MpSignature 26 | 27 | #Start Scan 28 | Start-MpScan -ScanType FullScan 29 | 30 | Start-MpScan -ScanType Quickscan 31 | 32 | #Multiple systems 33 | Invoke-Command -ComputerName dc02, dc01 -ScriptBlock {Start-MpScan -ScanType Quickscan} 34 | 35 | #Starts a Windows Defender offline scan 36 | Start-MpWDOScan -------------------------------------------------------------------------------- /automate/A03/03_03_Inactiveuser_Report.ps1: -------------------------------------------------------------------------------- 1 | #IMPORTANT: The following two accounts must be excluded (Gast krbtgt) 2 | 3 | #Imports active directory module to only current session 4 | Import-Module ActiveDirectory 5 | 6 | #Get-Date gives the present date in the server and is assigned to the variable presentdate 7 | $presentdate= Get-Date 8 | 9 | #User names whose lastlogondate is less than the presentdate-90days and those usernames are given to the variable output 10 | $output=Get-ADUser -Filter * -Properties lastlogondate | Where-Object {$_.lastlogondate -lt $presentdate.adddays(-90)} | Select-Object Name 11 | 12 | #This output is exported to a .csv file 13 | $output | Export-Csv C:\inactiveusers.csv -NoTypeInformation 14 | 15 | #This prints the users who are inactive by taking from the output 16 | Write-Host "The following users are inactive : " -ForegroundColor DarkYellow 17 | $output -------------------------------------------------------------------------------- /automate/A03/03_04_Move_FSMO.ps1: -------------------------------------------------------------------------------- 1 | #Provide the destination DC in which you want to transfer the fsmo role 2 | $destinationdc= Read-Host "Provide the Destination domain controller" 3 | 4 | #Choose the role you want to transfer 5 | $role=read-host "Choose the role" 6 | Switch($role) 7 | { 8 | 9 | 1 { $result = 'DomainNamingMaster'} 10 | 2 { $result = 'PDCEmulator'} 11 | 3 { $result = 'RIDMaster'} 12 | 4 { $result = 'SchemaMaster'} 13 | 5 { $result = 'InfrastructureMaster'} 14 | 6 {$result = 'All'} 15 | } 16 | 17 | if($role -gt 6) 18 | 19 | { 20 | Write-host "Choose correct option" -ForegroundColor Cyan 21 | 22 | } 23 | 24 | #This will transfer DomainNamingMaster role to destination server 25 | if ($role -eq 1) 26 | { 27 | 28 | Move-ADDirectoryServerOperationMasterRole -OperationMasterRole DomainNamingMaster -Identity $destinationDc -confirm:$false 29 | 30 | Write-host "$result is transferred successfully to $destinationDc" -ForegroundColor DarkGreen -BackgroundColor Cyan 31 | 32 | netdom query fsmo |Select-String "Domain Naming Master" 33 | } 34 | 35 | #This will transfer PDCEmulator role to destination server 36 | if ($role -eq 2) 37 | { 38 | 39 | Move-ADDirectoryServerOperationMasterRole -OperationMasterRole PDCEmulator -Identity $destinationDc -confirm:$false 40 | 41 | Write-host "$result is transferred successfully to $destinationDc" -ForegroundColor DarkGreen -BackgroundColor Cyan 42 | 43 | netdom query fsmo |Select-String "PDC" 44 | } 45 | 46 | #This will transfer RID pool manager role to destination server 47 | if ($role -eq 3) 48 | { 49 | 50 | Move-ADDirectoryServerOperationMasterRole -OperationMasterRole RIDMaster -Identity $destinationDc -confirm:$false 51 | 52 | Write-host "$result is transferred successfully to $destinationDc" -ForegroundColor DarkGreen -BackgroundColor Cyan 53 | 54 | netdom query fsmo |Select-String "RID pool manager" 55 | } 56 | 57 | #This will transfer Schema Master role to destination server 58 | if ($role -eq 4) 59 | { 60 | 61 | Move-ADDirectoryServerOperationMasterRole -OperationMasterRole SchemaMaster -Identity $destinationDc -confirm:$false 62 | 63 | Write-host "$result is transferred successfully to $destinationDc" -ForegroundColor DarkGreen -BackgroundColor Cyan 64 | 65 | netdom query fsmo |Select-String "Schema Master" 66 | } 67 | 68 | #This will transfer Infrastructure Master role to destination server 69 | if ($role -eq 5) 70 | { 71 | 72 | Move-ADDirectoryServerOperationMasterRole -OperationMasterRole InfrastructureMaster -Identity $destinationDc -Credential -confirm:$false 73 | 74 | Write-host "$result is transferred successfully to $destinationDc" -ForegroundColor DarkGreen -BackgroundColor Cyan 75 | 76 | netdom query fsmo |Select-String "Infrastructure Master" 77 | } 78 | 79 | #This will transfer All roles to destination server 80 | if ($role -eq 6) 81 | { 82 | 83 | Move-ADDirectoryServerOperationMasterRole -OperationMasterRole DomainNamingMaster,PDCEmulator,RIDMaster,SchemaMaster,InfrastructureMaster -Identity $destinationDc -confirm:$false 84 | 85 | Write-host "$result roles are transferred successfully to $destinationDc" -ForegroundColor DarkGreen -BackgroundColor Cyan 86 | 87 | netdom query fsmo 88 | } 89 | 90 | -------------------------------------------------------------------------------- /automate/A03/03_05_Creating_Printable_Contact_List.ps1: -------------------------------------------------------------------------------- 1 | #region Gathering the data 2 | # Define the properties to retrieve 3 | $properties = 'Name','Department','Title','EmailAddress','OfficePhone' 4 | 5 | # Get one user's info 6 | Get-ADUser 'Walter White' -Properties $properties | Format-Table $properties 7 | 8 | # For all applicable users 9 | $users = Get-ADUser -Filter {Department -like '*'} -Properties $properties 10 | 11 | # Export-Excel settings 12 | $exportExcelParams = @{ 13 | Autosize = $true 14 | TableName = 'Contacts' 15 | TableStyle = 'Light1' 16 | } 17 | 18 | # Output to .xlsx to make printable 19 | $users | Select-Object $properties | Export-Excel .\Contacts.xlsx -Title Contacts @exportExcelParams 20 | 21 | # Open the file 22 | Exit-PSSession 23 | Copy-Item C:\users\administrator\documents\Contacts.xlsx -Destination .\Contacts.xlsx -FromSession $Sessions[0] 24 | . .\Contacts.xlsx 25 | 26 | # Remote back to DC01 27 | Enter-PSSession $Sessions[0] 28 | 29 | #endregion 30 | 31 | #region Sort the data a bit better 32 | # Group by department, as an example 33 | $users | Group-Object Department 34 | 35 | # Format on different spreadsheets 36 | ForEach($group in ($users | Group-Object Department)){ 37 | $groupParams = @{ 38 | Path = ".\Contacts\$($Group.Name)_Contacts.xlsx" 39 | Title = "$($Group.Name) Contact List" 40 | } 41 | $group.Group | Select-Object $properties | Export-Excel @groupParams @exportExcelParams 42 | } 43 | 44 | # List the directory 45 | Get-ChildItem .\Contacts 46 | 47 | # Open one of the files 48 | Exit-PSSession 49 | Copy-Item C:\users\administrator\documents\Contacts\Accounting_Contacts.xlsx -Destination .\Accounting_Contacts.xlsx -FromSession $Sessions[0] 50 | . .\Accounting_contacts.xlsx 51 | 52 | # Remote back to DC01 53 | Enter-PSSession $Sessions[0] 54 | 55 | #endregion 56 | 57 | #region Of course we'll make that a function 58 | Function New-ADContactList { 59 | [cmdletbinding( 60 | DefaultParameterSetName = 'All' 61 | )] 62 | Param( 63 | [Parameter( 64 | ParameterSetName = 'GroupBy' 65 | )] 66 | [string]$GroupBy = 'Department', 67 | [Parameter( 68 | ParameterSetName = 'GroupBy' 69 | )] 70 | [string]$OutFolderPath, 71 | [Parameter( 72 | ParameterSetName = 'All' 73 | )] 74 | [string]$OutFilePath, 75 | [string]$Filter = "Department -like '*'", 76 | [string[]]$Properties = @('Name','Department','Title','EmailAddress','OfficePhone'), 77 | [hashtable]$ExportExcelParams = @{ 78 | Autosize = $true 79 | TableName = 'Contacts' 80 | TableStyle = 'Light1' 81 | } 82 | ) 83 | $users = Get-ADUser -Filter $Filter -Properties $Properties 84 | If($PSCmdlet.ParameterSetName -eq 'GroupBy'){ 85 | ForEach($group in ($users | Group-Object $GroupBy)){ 86 | $groupParams = @{ 87 | Path = "$OutFolderPath\$($Group.Name)_Contacts.xlsx" 88 | Title = "$($Group.Name) Contact List" 89 | } 90 | $group.Group | Select-Object $properties | Export-Excel @groupParams @ExportExcelParams 91 | } 92 | }ElseIf($PSCmdlet.ParameterSetName -eq 'All'){ 93 | $allParams = @{ 94 | Path = $OutFilePath 95 | Title = 'Contact List' 96 | } 97 | $users | Select-Object $properties | Export-Excel @allParams @ExportExcelParams 98 | } 99 | } 100 | 101 | # Usage 102 | New-ADContactList -GroupBy 'Department' -OutFolderPath .\Department 103 | 104 | # Verify 105 | Get-ChildItem .\Department 106 | Import-Excel .\Department\Accounting_Contacts.xlsx -StartRow 2 107 | 108 | # Usage 109 | New-ADContactList -OutFilePath .\AllContacts.xlsx 110 | Import-Excel .\AllContacts.xlsx -StartRow 2 111 | 112 | #endregion -------------------------------------------------------------------------------- /automate/A03/03_06_Generating_Group_Membership_Report.ps1: -------------------------------------------------------------------------------- 1 | #region Gather info 2 | # Single User's group membership: 3 | (Get-ADUser 'Walter White' -Properties MemberOf).MemberOf 4 | 5 | # Nicely formated 6 | (Get-ADUser 'Walter White' -Properties MemberOf).MemberOf | ForEach-Object {Get-ADGroup $_} 7 | 8 | # Multiple Users 9 | Get-ADUser -Filter {Title -like '*manager*'} -Properties MemberOf 10 | 11 | # Format 12 | $users = Get-ADUser -Filter {Title -like '*manager*'} -Properties MemberOf 13 | foreach($user in $users){ 14 | [pscustomobject]@{ 15 | Name = $user.Name 16 | User = $user.SamAccountName 17 | Memberships = ($user.MemberOf | ForEach-Object{Get-ADGroup $_}).Name 18 | } 19 | } 20 | 21 | # Make it presentable 22 | $userGroups = @() 23 | $users = Get-ADUser -Filter {Title -like '*manager*'} -Properties MemberOf 24 | foreach($user in $users){ 25 | $userGroups += [pscustomobject]@{ 26 | User = $user.SamAccountName 27 | Name = $user.Name 28 | Memberships = ($user.MemberOf | ForEach-Object{Get-ADGroup $_}).Name -join ', ' 29 | } 30 | } 31 | $userGroups | Export-Excel .\UserGroups.xlsx -Title 'Manager Group Memberships' 32 | 33 | # Validate 34 | Import-Excel .\UserGroups.xlsx -StartRow 2 35 | 36 | #endregion 37 | 38 | #region Functionize it! 39 | Function Get-ADUserGroupMembershipReport { 40 | [CmdletBinding()] 41 | Param( 42 | [Parameter( 43 | ValueFromPipeline = $true 44 | )] 45 | [Microsoft.ActiveDirectory.Management.ADUser]$Identity, 46 | [Parameter( 47 | Mandatory = $true 48 | )] 49 | [string]$FilePath, 50 | [string]$Title = 'AD User Membership Report', 51 | [string[]]$Properties 52 | ) 53 | begin{ 54 | $out = @() 55 | } 56 | process{ 57 | $propertiesToQuery = $Properties + 'MemberOf' 58 | $user = Get-ADUser $Identity -Properties $propertiesToQuery 59 | $tmp = [pscustomobject]@{ 60 | User = $user.SamAccountName 61 | Name = $user.Name 62 | Memberships = ($user.MemberOf | ForEach-Object{Get-ADGroup $_}).Name -join ', ' 63 | } 64 | ForEach($property in $Properties){ 65 | $tmp | Add-Member -MemberType NoteProperty -Name $property -Value $user."$property" 66 | } 67 | $out += $tmp 68 | } 69 | end{ 70 | $out | Export-Excel $FilePath -Title $Title 71 | } 72 | } 73 | 74 | # Usage 75 | Get-ADUserGroupMembershipReport -Identity 'Walter White' -FilePath .\Test.xlsx -Title "Walter's Memberships" 76 | 77 | # Verify 78 | Import-Excel .\Test.xlsx -StartRow 2 79 | Remove-Item .\Test.xlsx 80 | 81 | # All of a manager's reports 82 | Get-ADUser -Filter {Manager -eq 'Sona.May'} | ` 83 | Get-ADUserGroupMembershipReport -FilePath .\Test.xlsx -Properties Title -Title "Minion membership report for Marie-ann" 84 | 85 | #endregion -------------------------------------------------------------------------------- /automate/Links.txt: -------------------------------------------------------------------------------- 1 | https://docs.microsoft.com/en-us/powershell/module/activedirectory/ 2 | --------------------------------------------------------------------------------