STtools.psm1
Import-Module NTFSSecurity function Get-STGroupsFromCSV { <# .SYNOPSIS Gets/outputs group names and associated/unassociated users. Good for adding/removing year level or class groups for staff/students. .DESCRIPTION Gets user and group information from a CSV file that has at least two columns; one with usernames, the other with group names. The command will output to the pipeline: A generated group name made up of the group field and your prefix/postfix/both A list of Active Directory User objects (like you would get from Get-ADUser) who should be in the group based on their username A list of Active Directory User objects (like you would get from Get-ADUser) who should NOT be in the group (all OTHER users from AD) .PARAMETER csvfile The source CSV file that contains a field for usernames and a field for groups .PARAMETER username_header The header of the field that contains usernames (Defaults to "Student Code") .PARAMETER group_header The header of the field that contains group (Defaults to "Roll Class Code") .PARAMETER group_name The group name to assign ALL users that result from this list. Use if there is no group_header that makes sense, but a filter does. .PARAMETER prefix A Prefix to prepend to the group name to generate the desired group name (Eg. "Year" to generate "Year7"). Can also be used with postfix. .PARAMETER postfix A Postfix to append to the group name to generate the desired group name (Eg. "Students" to generate "7Students"). Can also be used with prefix. .PARAMETER onlynumbers Only the numbers are kept in the group field. Useful when you're trying to create year groups from fields that have letters (Eg. "7B" -> "7") .PARAMETER stripzeros Strips leading zeros on for example a group year (Eg. "07" -> "7") .EXAMPLE Get-STGroupsFromCSV -csvfile \\path\to\csv\file.csv -prefix "Year" |ForEach-Object { Remove-ADGroupMember -Identity $_.Identity -Members $_.NonMembers -Confirm:$false Add-ADGroupMember -Identity $_.Identity -Members $_.Members -Confirm:$false } Get year groups and associated users from file.csv, for each "YearX" group, remove the users who don't appear in the CSV file, and add users who do .EXAMPLE Get-STGroupsFromCSV -csvfile \\path\to\csv\file.csv -postfix "Teachers" -username_header "Teacher Code" |ForEach-Object { Remove-ADGroupMember -Identity $_.Identity -Members $_.NonMembers -Confirm:$false Add-ADGroupMember -Identity $_.Identity -Members $_.Members -Confirm:$false } Get year groups and associated users from file.csv, for each "XTeachers" group, remove the users who aren't in the CSV file, add users who are in the CSV file .EXAMPLE Get-STGroupsFromCSV -csvfile \\CASES\share\ST_XXXX.csv #> Param( [Parameter(Mandatory=$true)] [string] $csvfile, [Parameter(Mandatory=$false,HelpMessage="The CSV table header for student code (default is 'Student Code' for TTv7)")] [string] $username_header = "Student Code", [Parameter(Mandatory=$false,HelpMessage="The CSV table header for year level (default is 'Roll Class Code' for TTv7)")] [string] $group_header, [Parameter(Mandatory=$false,HelpMessage="Prepends this to the beggining of each year level (eg. Year -> Year7)")] [string] $group_name, [Parameter(Mandatory=$false,HelpMessage="Prepends this to the beggining of each year level (eg. Year -> Year7)")] [string] $prefix = "", [Parameter(Mandatory=$false,HelpMessage="Appends this to the beggining of each year level (eg. students -> 7students)")] [string] $postfix = "", [Parameter(Mandatory=$false,HelpMessage="Strips leading zeros on group year")] [switch] $stripzeros, [Parameter(Mandatory=$false,HelpMessage="Selects only numbers from the group field (eg. '7B' -> '7')")] [switch] $onlynumbers, [Parameter(Mandatory=$false,HelpMessage='Filters records in CSV according to this filter (eg. -filter {$_.STATUS -eq "ACTV"')] [scriptblock] $filter ) Begin{ if ($group_name -and $($group_header -or $prefix -or $postfix -or $stripzeros -or $onlynumbers)) { Throw "Group Name must be used on its own!" } elseif ($group_name) { $groups = @{} if ($filter) { Import-Csv $csvfile |Where-Object $filter |ForEach-Object {$groups.$($group_name) += @($($_.$username_header))} } else { Import-Csv $csvfile |ForEach-Object {$groups.$($group_name) += @($($_.$username_header))} } } else { $groups = @{} if ($filter) { if ($onlynumbers) { if ($stripzeros) { Import-Csv $csvfile |Where-Object $filter |ForEach-Object {$groups.$($($_.$group_header -replace '\D+').trimstart('0')) += @($($_.$username_header))} } else { Import-Csv $csvfile |Where-Object $filter |ForEach-Object {$groups.$($_.$group_header -replace '\D+') += @($($_.$username_header))} } } else { if ($stripzeros) { Import-Csv $csvfile |Where-Object $filter |ForEach-Object {$groups.$($($_.$group_header).trimstart('0')) += @($($_.$username_header))} } else { Import-Csv $csvfile |Where-Object $filter |ForEach-Object {$groups.$($_.$group_header) += @($($_.$username_header))} } } } else { if ($onlynumbers) { if ($stripzeros) { Import-Csv $csvfile |ForEach-Object {$groups.$($($_.$group_header -replace '\D+').trimstart('0')) += @($($_.$username_header))} } else { Import-Csv $csvfile |ForEach-Object {$groups.$($_.$group_header -replace '\D+') += @($($_.$username_header))} } } else { if ($stripzeros) { Import-Csv $csvfile |ForEach-Object {$groups.$($($_.$group_header).trimstart('0')) += @($($_.$username_header))} } else { Import-Csv $csvfile |ForEach-Object {$groups.$($_.$group_header) += @($($_.$username_header))} } } } } } Process{ foreach ($group in $groups.Keys) { $unique_users = @() $adusers = @() $unique_users += $groups.$group |Select-Object -Unique foreach ($user in $unique_users) { try { $adusers += $(Get-ADUser -Identity $user) } catch { Write-Warning "Couldn't find AD User account for $user" } } $non_members = Get-ADUser -Filter * |Where-Object {$_.samaccountname -notin $unique_users} Write-Debug "Group: $group" Write-Debug "Members: $adusers" Write-Debug "Non-members: $non_members" $props = @{ 'Identity' = "$prefix$group$postfix"; 'Members' = $adusers; 'NonMembers' = $non_members } $obj = New-Object -TypeName PSObject -Property $props $obj.PSObject.TypeNames.Insert(0,"ST.GroupUsers") Write-Output $obj } } } function ConvertFrom-STEduHubSF { [CmdletBinding()] param ( # list of users [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [System.Object[]] $UserList, # Directory (share) where user home dirs are created [Parameter(Mandatory=$true)] [string] $HomeDirBase, # Domain name (to generate email address) [Parameter(Mandatory=$true)] [string] $Domain, # Home drive letter (not including colon) [Parameter(Mandatory=$true)] [string] $HomeDrive, # Wether the account should be enabled or not [Parameter(Mandatory=$false)] [bool] $Enabled=$true ) process { foreach ($user in $UserList) { $converteduser = $user | Select-Object -Property ` @{Name="DisplayName"; Expression={"$($_.FIRST_NAME) $($_.SURNAME)"}}, @{Name="EmailAddress"; Expression={"$($_.SFKEY)@$Domain"}}, @{Name="Enabled"; Expression={$Enabled}}, @{Name="GivenName"; Expression={"$($_.FIRST_NAME)"}}, @{Name="HomeDirectory"; Expression={"$(Join-Path $HomeDirBase $_.SFKEY)"}}, @{Name="HomeDrive"; Expression={"$HomeDrive"}}, @{Name="Name"; Expression={"$($_.SFKEY)"}}, @{Name="PasswordNotRequired"; Expression={$false}}, @{Name="SamAccountName"; Expression={$_.SFKEY}}, @{Name="Surname"; Expression={$_.SURNAME}}, @{Name="UserPrincipalName"; Expression={"$($_.SFKEY)@$Domain"}} Write-Output $converteduser } } } function ConvertFrom-STEduHubST { [CmdletBinding()] param ( # list of users [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [System.Object[]] $UserList, # Directory (share) where user home dirs are created [Parameter(Mandatory=$true)] [string] $HomeDirBase, # Domain name (to generate email address) [Parameter(Mandatory=$true)] [string] $Domain, # Home drive letter (not including colon) [Parameter(Mandatory=$true)] [string] $HomeDrive, # Wether the account should be enabled or not [Parameter(Mandatory=$false)] [bool] $Enabled=$true ) process { foreach ($user in $UserList) { $converteduser = $user | Select-Object -Property ` @{Name="DisplayName"; Expression={"$($_.FIRST_NAME) $($_.SURNAME)"}}, @{Name="EmailAddress"; Expression={"$($_.STKEY)@$Domain"}}, @{Name="Enabled"; Expression={$Enabled}}, @{Name="GivenName"; Expression={"$($_.FIRST_NAME)"}}, @{Name="HomeDirectory"; Expression={"$(Join-Path $HomeDirBase $_.STKEY)"}}, @{Name="HomeDrive"; Expression={"$HomeDrive"}}, @{Name="Name"; Expression={"$($_.STKEY)"}}, @{Name="DOB"; Expression={"$(NormaliseBirthDate -date $($_.BIRTHDATE))"}}, @{Name="SamAccountName"; Expression={$_.STKEY}}, @{Name="Surname"; Expression={$_.SURNAME}}, @{Name="UserPrincipalName"; Expression={"$($_.STKEY)@$Domain"}} Write-Output $converteduser } } } function Update-Properties { [CmdletBinding()] param ( # Source object [Parameter(Mandatory=$true)] [System.Object] $sourceObject, # Destination object [Parameter(Mandatory=$true)] [System.Object] $destinationObject ) process { $updated = $false $properties = $sourceObject |Get-Member |Where-Object {$_.membertype -eq "NoteProperty"} $properties |ForEach-Object { if ($_.Name -ne "DOB" -and $_.Name -ne "Name") { # This is very bad... VERY bad. This ties our data to our code giving us tight coupling and making this script less robust and less portable. if ($sourceObject.$($_.Name) -ne $destinationObject.$($_.Name)) { write-host "$($_.Name): $($sourceObject.$($_.Name)) and $($destinationObject.$($_.Name)) are different" $destinationObject.Item("$($_.Name)").Value = $sourceObject.$($_.Name) $updated = $true } } } if ($updated -eq $true) { Write-Output $destinationObject } } } function Get-STRandomCharacter($range, $count) { return $([string](-join ($range |Get-Random -count $count | ForEach-Object {[char]$_}))) } function Get-STNewCompliantPassword () { $randomChars = $($(Get-STRandomCharacter -range (48..57) -count 3) + $(Get-STRandomCharacter -range (33..47) + (58..64) -count 2) + $(Get-STRandomCharacter -range (65..90) -count 3) + $(Get-STRandomCharacter -range(97..122) -count 4)) -split "" |Sort-Object {Get-Random} return -join $randomChars } function Set-STUser ($users, $homeDirBase="", $allUsers) { $users |ForEach-Object { foreach ($account in $allUsers) { if ($_.samaccountname -eq $account.samaccountname) { Write-Host "Checking: $($account.samaccountname)" Update-Properties -sourceObject $_ -destinationObject $account } } } |ForEach-Object {set-aduser -Instance $_} $users |ForEach-Object { if ($($homeDirBase -ne "") -and -not $(Test-Path -PathType Container $(Join-Path -Path $homeDirBase -ChildPath $_.samaccountname))) { New-Item -ItemType Directory -Path $(Join-Path -Path $homeDirBase -ChildPath $_.samaccountname) Add-NTFSAccess -Path $(Join-Path -Path $homeDirBase -ChildPath $_.samaccountname) -Account $_.samaccountname -AccessRights FullControl } } } function New-STUser ($sourceUsers, $currentUsers, $ouLookup, $homeDirBase="", $smtp_server="", $support_address="", $to_addresses=@()){ $sourceUsers |ForEach-Object { if ($_.samaccountname -notin $currentUsers.samaccountname) { Write-Host "$($_.samaccountname) doesn't have an account yet... creating..." $_.PSObject.Properties.Remove('DOB') $plainpassword = Get-STNewCompliantPassword if ($smtp_server -and $support_address -and $to_addresses) { Send-MailMessage -SmtpServer $smtp_server -To $to_addresses -From $support_address -Subject "New User report" -Body "New user: $($_.samaccountname)`nPassword: $plainpassword" } $_ |add-member -MemberType NoteProperty -name "AccountPassword" -value $(convertto-securestring $plainpassword -AsPlainText -Force) -Force Write-Output $_ } } | New-ADUser $sourceUsers |ForEach-Object { if (-not $(Test-Path -PathType Container $(Join-Path -Path $homeDirBase -ChildPath $_.samaccountname)) -and $($homeDirBase -ne "")) { New-Item -ItemType Directory -Path $(Join-Path -Path $homeDirBase -ChildPath $_.samaccountname) -ErrorAction Continue Add-NTFSAccess -Path $(Join-Path -Path $homeDirBase -ChildPath $_.samaccountname) -Account $_.samaccountname -AccessRights FullControl } } } function NormaliseBirthDate ($date) { if ($date -eq "") { $date = "0/00/0000" } if ($date.Length -lt 22) { $date = "0" + $date } $date -match "(?<day>[0-9]+)/(?<month>[0-9]+)/(?<year>[0-9]+)" |Out-Null $date = $Matches["day"] + $Matches["month"] + $Matches["year"].Substring(2, 2) return $date } function Set-STOrganizationalUnit ($userOUs) { foreach ($OU in $userOUs.Keys) { $targetOU = "" try { $targetOU = Get-ADOrganizationalUnit $OU -ErrorAction Stop } catch { Write-Debug "$OU OU doesn't exist" } if ($targetOU -ne "") { $currentOUUsers = get-aduser -SearchBase $targetOU -SearchScope 1 -Filter * foreach ($user in $userOUs.$OU) { if ($user -notin $currentOUUsers.samaccountname) { $usertomove = Get-ADUser $user write-host "Moving $user to $targetOU" Move-ADObject -Identity $usertomove -TargetPath $targetOU } } } } } |