ELM-ADTools.psm1

Function Calculate-IntakeYears {

    $Year = (get-date -UFormat %Y) -as [int]

    if ((get-date -UFormat %m) -ge "09") {
        
        $Year = ($Year + 1)

        }
        
    Write-Host "Reception:" ($Year - 1)
    Write-Host "Year 1:" ($Year - 2)
    Write-Host "Year 2:" ($Year - 3)
    Write-Host "Year 3:" ($Year - 4)
    Write-Host "Year 4:" ($Year - 5)
    Write-Host "Year 5:" ($Year - 6)
    Write-Host "Year 6:" ($Year - 7)

    }
Function Export-Users {

Param(
    [int]$Days
) # end param


# Get path friendly date (dd-mm-yy)
$Today = Get-Date -UFormat %d-%m-%y

# Get ALL users in domain
$AllUsers = Get-ADUser -filter * -Properties *

# Filter uses only if Days variable has been assigned
if ($Days) {

    # Filter to those logged in within last 90 days
    $AllUsers = $AllUsers | Where-Object  lastlogondate -gt ((Get-Date).AddDays(-$Days))
    }

# Output to a CSV file with firstname, lastname, username, and also OU they were in
$AllUsers |
select givenname, surname, samaccountname, distinguishedname |
ConvertTo-Csv -NoTypeInformation |
Out-File -FilePath "$Home\Desktop\User_Export-$Today.csv"

}
# Password Generator

function Generate-Passwords {

    [CmdletBinding()]
    param (
        [Parameter()]
        [int]
        $PasswordQty
    )
    
    $PasswordFile = "$env:USERPROFILE\Passwords.txt"
    Write-Host "Password text file is here $PasswordFile" -ForegroundColor Green

    if (test-path $PasswordFile) {
        Remove-Item $PasswordFile
        }

    $counter = 0

    1..$PasswordQty | ForEach-Object {

        $counter++
        Write-Progress -Activity 'Generating Passwords' -CurrentOperation "Password $_" -PercentComplete (($counter / $PasswordQty) * 100)
        Invoke-WebRequest http://www.dinopass.com/password/simple | Select-Object Content -ExpandProperty Content

        } | Out-File $PasswordFile -Append

}
function Get-InactiveAccounts {
    
    [cmdletbinding(SupportsShouldProcess=$True)]

    Param(
        [int] $DaysInactive = 30,
        [Parameter(Mandatory)]  
        [ValidateSet('Users','Computers')]
        $Object,
        [switch]
        $Disable
        )

    $domain = (Get-ADDomain).DistinguishedName
    $oucheckname = "_DISABLED"
    $oucheck = [adsi]::Exists("LDAP://OU=$oucheckname,$domain")

    if ($oucheck -eq $false) {
        New-ADOrganizationalUnit -Name _DISABLED
    }

    $DisabledOU = (Get-ADOrganizationalUnit -Filter 'Name -Like "*_DISABLED*"').DistinguishedName

    if ($Object -eq 'Users') {
        
        $InactiveObjects = Search-ADAccount -UsersOnly -AccountInactive -TimeSpan "30.00:00:00" |
        Where-Object { ($_.Enabled -eq $true) -and ($_.lastlogondate -ne $null) -and ($_.name -notlike "*admin*")}
        $InactiveObjects | Sort-Object LastLogonDate | Select-Object Name,LastLogonDate

        if ($Disable) {

            foreach ($Item in $InactiveObjects) {
            
                Set-ADUser -Identity $Item.DistinguishedName -Description "Account Disabled on $(get-date -UFormat %d/%m/%y)" -Enabled $false
                Move-ADObject -Identity $Item.DistinguishedName -TargetPath $DisabledOU
                Write-Verbose "Successfully disabled $($Item.Name)"

            }

        }

    }


    if ($Object -eq 'Computers') {
        
        $InactiveObjects = Search-ADAccount -ComputersOnly -AccountInactive -TimeSpan "$DaysInactive.00:00:00"  |
        Where-Object {$_.Enabled -eq $true}
        $InactiveObjects | Sort-Object LastLogonDate | Select-Object Name,LastLogonDate

        if ($Disable) {

            foreach ($Item in $InactiveObjects) {
            
                Set-ADComputer -Identity $Item.DistinguishedName -Description "Computer Disabled on $(get-date -UFormat %d/%m/%y)" -Enabled $false
                Move-ADObject -Identity $Item.DistinguishedName -TargetPath $DisabledOU
                Write-Verbose "Successfully disabled $($Item.Name)"
                

            }

        }

    }


}
function Get-OrphanedFolders {


    [cmdletbinding()]    
    param(
        [Parameter(Mandatory=$true)]
        [string]$ProfileDir,
        [Parameter(Mandatory=$true)]
        [string]$HomeDir
    )


$Date = Get-Date -UFormat %Y-%m-%d
Install-WindowsFeature RSAT-AD-PowerShell

###########################
##### Home FOLDERS #####
###########################

# create an array to put all folders in
$AllHomeFolders = @()

# scan through subfolders and add them to the array
$AllHomeFolders += (Get-ChildItem $HomeDir -Exclude Archive | Get-ChildItem)

# create an array to put orphaned folders in
$OrphanedHomeFolders = @()

# test each folder name against active directory samaccountnames and if they dont exist place them in the orphaned folders array
Foreach ($HomeFolder in $AllHomeFolders) {

    try {
        Write-Verbose "Looking for $($HomeFolder.Name)..."
        Get-ADUser -Identity $HomeFolder.Name | out-null
        }
    catch {
        Write-Verbose "*** Could not find $($HomeFolder.Name) ***"
        $OrphanedHomeFolders += $HomeFolder
        }

}

# display the orphaned folders that were found
Write-Host "here are the current oprhaned Home folders"

$OrphanedHomeFolders | sort lastaccesstime | ft name,fullname,lastaccesstime

# prompt user if they want to archive them
$confirm = Read-Host "Would you like to move these to an archive folder (y/n)"

# test for archive folder and create it if it does not exist
if ($confirm -eq "y") {

    $HomeArchiveDir = "$HomeDir\Archive\$Date"

    if (!(Test-Path $HomeArchiveDir)) {

        New-Item $HomeArchiveDir -ItemType Directory

        }

# move all orphaned folders to the archive folder
    $OrphanedHomeFolders | Move-Item -Destination $HomeArchiveDir -Force
    Write-Host "The folders have been successfully moved to $HomeArchiveDir" -ForegroundColor Green

}

###########################
##### Profile FOLDERS #####
###########################

# create an array to put all folders in
$AllProfileFolders = @()

# scan through subfolders and add them to the array
$AllProfileFolders += (Get-ChildItem $ProfileDir -Exclude Archive | Get-ChildItem)

# create an array to put orphaned folders in
$OrphanedProfileFolders = @()

# test each folder name against active directory samaccountnames and if they dont exist place them in the orphaned folders array
Foreach ($ProfileFolder in $AllProfileFolders) {

    try {
        Write-Verbose "Looking for $($ProfileFolder.Name)..."
        Get-ADUser -Identity $ProfileFolder.Name.Replace(".V6","") | Out-Null
        }
    catch {
        Write-Verbose "*** Could not find $($ProfileFolder.Name) ***"
        $OrphanedProfileFolders += $ProfileFolder
        }

}

# display the orphaned folders that were found
Write-Host "here are the current oprhaned Profile folders"

$OrphanedProfileFolders | sort lastaccesstime | ft name,fullname,lastaccesstime

# prompt user if they want to archive them
$confirm = Read-Host "Would you like to move these to an archive folder (y/n)"

# test for archive folder and create it if it does not exist
if ($confirm -eq "y") {

    $ProfileArchiveDir = "$ProfileDir\Archive\$Date"

    if (!(Test-Path $ProfileArchiveDir)) {

        New-Item $ProfileArchiveDir -ItemType Directory

        }

# move all orphaned folders to the archive folder
    $OrphanedProfileFolders | Move-Item -Destination $ProfileArchiveDir -Force
    Write-Host "The folders have been successfully moved to $ProfileArchiveDir" -ForegroundColor Green

}


}



Function Import-Users {

<#
 
.Synopsis
Use this function to import users from a CSV file in to Active Directory
 
.Description
Users are imported in to an imported users OU, from there you can move them as you wish
 
 
.Parameter CSV
The path to a CSV file containing user data, CSV MUST have 3 columns, firstname, lastname & description
 
.Parameter UsernameFormat
Select the format you want for the usernames generated, currently johnd, john.d, jdoe, j.doe, john.doe are supported.
 
.Parameter Usertype
Select the type of user account, the function uses this to find the home directory (eg Home$\Staff) and also adds them to the corresponding security group
 
.Parameter Homeshare
Path to the Home$ share (eg \\DC01\Home$)
 
.Parameter Profileshare
Path to the Profile$ share (eg \\DC01\Profile$)
 
.Parameter Password
What password you want for the account, MUST comply with domain policy OR fine grained password policy.
 
.Parameter RandomPassword
Tells the function to use www.dinopass.com to generate random passwords for each account
 
.Parameter Logpath
What path to generate the log files, by default is current users desktop
 
 
#>



#Requires -RunAsAdministrator
    
    [cmdletbinding(SupportsShouldProcess=$True)]
    [CmdletBinding(DefaultParameterSetName='password')]
    Param(
        
        [string]
        [Parameter(Mandatory=$true)]
        $csv,
        
        [string]
        [Parameter(Mandatory=$true)]
        [ValidateSet('johnd','john.d','jdoe','j.doe','john.doe')]
        $UsernameFormat,
        
        [string]
        [Parameter(Mandatory=$true)]
        [ValidateSet('Staff','Office','Students')]
        $UserType,
        
        [string]
        [Parameter(Mandatory=$true)]
        $HomeShare,
        
        [string]
        [Parameter(Mandatory=$true)]
        $ProfileShare,
        
        [Parameter(ParameterSetName='password', Position=0)]
        $Password,
        
        [Switch]
        [Parameter(ParameterSetName='random', Position=0)]
        $RandomPassword,
        
        [string]
        $LogPath = "$env:USERPROFILE\Desktop\User Import Logs"
    )


# Setup logging
$Log = "$LogPath\$(Get-Date -UFormat %Y-%m-%d) Import Log.csv"
$FailLog = "$LogPath\$(Get-Date -UFormat %Y-%m-%d) FAILED Import Log.csv"

if (!(Test-Path $Log)) {

    New-Item $Log, $FailLog -Force
    Set-Content -Path $Log -Value '"Full Name","UserName","Description","Password"'
    Set-Content -Path $FailLog -Value '"Full Name","UserName"'
    
    }

# Store the data from the CSV in the $Users variable
$Users = Import-csv $csv

# Defines what the CSV headers should be
$CorrectHeaders = @(
    'firstname'
    'lastname'
    'description'
    )

# Assigns the actual headers to a variable
$ImportHeaders = (($Users[0].psobject.properties.name))

# Counts the differencnes
$HeaderDiffs = (Compare-Object $CorrectHeaders $ImportHeaders).count

# Throws an error if the differences are not 0
if ($HeaderDiffs -ne '0') {

    Throw "Check your CSV Headers! Should be 'firstname,lastname,description'"

}

# Set some Variables
$Domain = (Get-ADDomain).name
$FullDomain = (Get-ADDomain).dnsroot
$DomainRoot = (Get-ADDomain).DistinguishedName
$HomePath = "$HomeShare\$UserType"
$ProfilePath = "$ProfileShare\$UserType"
$bar = "*" * 125

# Tests for an "Imported Users" OU at root of domain and if it does not exist then it creates it
$ImportOU = "OU=Imported Users,$DomainRoot"

try {
    Get-ADOrganizationalUnit -Identity $ImportOU | Out-Null
    } catch {
    New-ADOrganizationalUnit -Name "Imported Users" -Path $DomainRoot
    }

# Check Home & Profile paths exist
if (!(Test-Path $HomePath)) {
    Throw "Could not find $HomePath!"
}
    
if (!(Test-Path $ProfilePath)) {
    Throw "Could not find $ProfilePath!"
}

# Loop through each row containing user details in the CSV file

foreach ($User in $Users) {

    # Read user data from each field in each row and assign the data to a variable as below
        
    $Firstname      = $User.firstname 
    $Lastname      = $User.lastname
    $FullName    = "$Firstname $Lastname"
    $Description = $User.description

    # Select username format

    if ($UsernameFormat -eq "johnd") {
        $Username = $Firstname + $Lastname.substring(0,1)
        
    }

    if ($UsernameFormat -eq "john.d") {
        $Username = $Firstname + "." + $Lastname.substring(0,1)
    }

    if ($UsernameFormat -eq "jdoe") {
        $Username = $Firstname.substring(0,1) + $Lastname
    }

    if ($UsernameFormat -eq "j.doe") {
        $Username = $Firstname.substring(0,1) + "." + $Lastname
    }

    if ($UsernameFormat -eq "john.doe") {
        $Username = $Firstname + "." + $Lastname
    }
    
    # change to lower case and remove - and ' and spaces

    $Username    = $Username.ToLower()
    $Username    = $Username.Replace('-','').replace("'",'').replace(" ",'')

    # Generate a random password and make the first letter a capital

    if ($RandomPassword) {
        
        Write-Verbose "Generating random password..."
        $Password = (Get-Culture).TextInfo.ToTitleCase((Invoke-WebRequest "http://www.dinopass.com/password/simple" -Verbose:$False | Select-Object Content -ExpandProperty Content))

        }

    $PasswordSecure = $Password | ConvertTo-SecureString -AsPlainText -Force


    # Create splat of user params
        
    $UserParams = @{
        SamAccountName = $Username
        UserPrincipalName  = "$Username@$FullDomain"
        Name = $FullName
        GivenName = $Firstname
        Surname = $Lastname
        Enabled = $True
        DisplayName = $FullName
        Path = $ImportOU
        ProfilePath = "$ProfilePath\$Username"
        HomeDrive = "H:"
        HomeDirectory = "$HomePath\$Username"
        Description = $Description
        AccountPassword = $PasswordSecure
        ChangePasswordAtLogon = $true
        }

    # Create an object to make reporting later easier
       
    $UserObject = [PSCustomObject]@{

        Name            = $Fullname
        UserName        = $Username
        Description     = $Description
        Password        = $Password

        }

    try {
        
        New-ADUser @UserParams
        Write-Verbose "Successfully created $FullName with username $Username and Password $Password"
        $UserObject | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1 | Out-File -FilePath $Log -Append -encoding ASCII

        } catch {

        $_ | Out-File -FilePath $FailLog -Append -encoding ASCII
        $UserObject | Select Name,Username | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1 | Out-File -FilePath $FailLog -Append -encoding ASCII
        $bar | Out-File -FilePath $FailLog -Append -encoding ASCII
        Write-Verbose "Unable to create $FullName, moving on to next user..."
        continue
        
        }

    Write-Verbose "Creating home directory: $HomePath\$Username"
    # Create users home folder and give them full rights
    New-Item -Name $Username -Path $HomePath -ItemType Directory | Out-Null
        
    Write-Verbose "Setting access rights..."
    $Acl = Get-Acl "$HomePath\$Username"
    $Ar = New-Object  System.Security.AccessControl.FileSystemAccessRule("$Domain\$Username","FullControl","ContainerInherit,ObjectInherit","None","Allow")
    $Acl.SetAccessRule($Ar)
    Set-Acl "$HomePath\$Username" $Acl

    Write-Verbose "Assigning to groups..."
    # Add them to AD groups
    Add-ADGroupMember -Identity $UserType -Members $Username

    # Set password and enable account after group membership (fine grained password policy)
    Write-Verbose "Setting password..."
    
    Set-ADAccountPassword -Identity $Username -Reset -NewPassword $PasswordSecure
    Set-ADUser -Identity $Username -Enabled $true
    
    if ($UserType -eq "Students") {

        Set-ADUser -Identity $Username -CannotChangePassword $true -ChangePasswordAtLogon $false -PasswordNeverExpires $true
        
        } else {

        Set-ADUser -Identity $Username -CannotChangePassword $false -ChangePasswordAtLogon $true

        }

    Write-Verbose $bar

    }

}
function List-Users {

    param (
        [Parameter(Mandatory=$true)]
        [string]$Group
        )


# Put all members of group in to a variable
$GroupMembers = Get-ADGroupMember -Identity $Group

# Prepare a blank array
$UsersToList = @()

# As Get-ADGroupMember does not return the "description" field we will need to loop through and Get-ADUser on each group member to get all their properties
Foreach ($User in $GroupMembers) {
    
    # Set the current value in the pipe line to $User
    $_ = $User

    # Get the ADUser using their account name
    $User = Get-ADUser -Filter {samaccountname -eq $_.SamAccountName -and enabled -eq $true} -Properties *

    # Add them to the emtpy array created earlier
    $UsersToList += $User

    }


# Do some super magic formatting!
       # Sort by description and then by name
       # Put in a table and group by description
            # If they are a student then change the group heading to "Year Group" from "Description"
            # Else assume they are staff and change the group heading to "Role" from "Description"
       # Change property name (SamAccountName to Username)
# Output to a text file on the desktop
If ($Group -like "Student*") {
    
    $UsersToList |
    Sort-Object @{expression=�Description�;Ascending=$true},
                @{expression=�Name�;Ascending=$true} |
    Format-Table -AutoSize -GroupBy @{Name="Year Group";Expression='Description'} -Property `
    @{Label="Name";Expression={$_.Name}},
    @{Label="Username";Expression={$_.SamAccountName}} |
    Out-File "$HOME\Desktop\$Group User List.txt"

    } else {

    $UsersToList |
    Sort-Object @{expression=�Description�;Ascending=$true},
                @{expression=�Name�;Ascending=$true} |
    Format-Table -AutoSize -GroupBy @{Name="Role";Expression='Description'} -Property `
    @{Label="Name";Expression={$_.Name}},
    @{Label="Username";Expression={$_.SamAccountName}} |
    Out-File "$HOME\Desktop\$Group User List.txt"

    }


}
# This script will find any disabled users located in a _DISABLED OU
# and remove the profile, home folder and also remove their AD Account

# first we will check for the _DISABLED OU

function Remove-DisabledUsers {

$domain = (Get-ADDomain).DistinguishedName
$oucheckname = "_DISABLED"
$oucheck = [adsi]::Exists("LDAP://OU=$oucheckname,$domain")

if ($oucheck -eq $false) {
    Write-Warning "Cannot find a _DISABLED OU, exiting now..."
    exit
    } else {
    $disabledou = (Get-ADOrganizationalUnit -Filter 'Name -Like "*_DISABLED*"').DistinguishedName
    Write-host "I have found a _DISABLED OU at $disabledou" -ForegroundColor Cyan
    }

# Now we will get all disabled users in that OU

$userstodelete = Get-ADUser -Filter {Enabled -eq $false} -Properties * -SearchBase $disabledou

Write-Host "I have found the following users to delete..."

$userstodelete | ft Name,samaccountname,enabled,memberof

# Here is a confirmation that exits unless y is entered

$confirm = Read-Host "Would you like to proceed with the removal? (type yes to continue)"
if ($confirm -ne 'yes') {exit}



foreach ($user in $userstodelete) {
    $homedir = $user.homedirectory
    $profiledir = $user.profilepath
    $name = $user.name

    Write-Host "Removing $name's Home Folder" -ForegroundColor Green
    Remove-Item $homedir -Recurse -Force
    
    Write-Host "Removing $name's Profile" -ForegroundColor Green
    Remove-Item "$profiledir*" -Recurse -Force
    
    Write-Host "Removing $name's Account" -ForegroundColor Green
    Remove-ADUser $user -Confirm:$false -Verbose

    }

}
function Rename-Users {

    param (
    [string]$OU
    )

    # get users in a certain OU
    $allusers = Get-ADUser -Filter * -SearchBase $OU

    # loop through all users found
    foreach($user in $allusers){

    # assign variables
    $firstname = $user.givenname
    $surname = $user.surname
    $olddisplayname =$user.name

    # reassign variables with correct capitalization
    $firstname = $firstname.substring(0,1).ToUpper()+$firstname.substring(1).ToLower()

    $surname = $surname.substring(0,1).ToUpper()+$surname.substring(1).ToLower()

    # create the correct displayname
    $newdisplayname = $firstname + " $surname"

    # perform the rename action
    Set-ADUser -Identity $user -DisplayName $newdisplayname
    Rename-ADObject -Identity $user -NewName $newdisplayname

    Write-Host "Renamed $olddisplayname to $newdisplayname" -ForegroundColor Green

    }
}
Function Reset-Passwords {

 param (

    [Parameter(Mandatory=$true,Position=0)]
    [string]$OU,

    [Parameter(Mandatory=$true,Position=0)]
    [string]$NewPwd,

    [switch]$RequireChange = $true


 )


# Get all the users in the OU
$Users = Get-ADUser -Filter * -Properties * -SearchBase $OU

foreach ($User in $Users) {
    
    # Set the users password
    Set-ADAccountPassword -Identity $User.SamAccountName -NewPassword (ConvertTo-SecureString $NewPwd -AsPlainText -Force) -Reset -Verbose    
    # If require change is true then do so
    if ($RequireChange -eq $true)
        {
        Set-ADUser -Identity $User.SamAccountName -ChangePasswordAtLogon $true
        }
    
    Write-Host "$($User.name)'s password has been updated" -ForegroundColor Green
        
        }
    }