Friday, 1 February 2019

Update Job Title and Department in Active Directory with Powershell

 

 

Here is a short powershell script to update job title and department in Active Directory, though this could be used to update any of the AD fields.  Obviously you will need to create a CSV file beforehand which is populated with the required information.  When the CSV is imported, no headers are specified in the script so ensure these are in the first row file already.  As a minimum here I needed SAMAccountName, Title and Department.

 

The script will first check to see if the user in the file actually exists (I am working in an environment with multiple domains and forests and I didn’t want the script to produce lots of ugly errors if the user weren’t found).  This is done with try and catch.  If you are adapting this script for a different use you will need to make sure you catch the correct error.  The way I got the correct error text was to run the command that produces the error and then run:

 

$Error[0].Exception.GetType().FullName

 

 

I then used ‘catch’ to pick up the accounts that didn’t exist (ie that errored) and set a variable to skip the next command, which is done by the ‘if’ statement.  At the end of that particular row in the ‘foreach’ loop, I set $Nextaction back to $null ready for the next check and so on…

 

 

 

$LogFilePath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\update_job_titles_" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $LogFilePath -NoClobber

$NewPass = cat C:\cloudwyse\secureinfo.txt | convertto-securestring

$NewCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "contoso\username",$NewPass

$NewEnvDC = "server01.contoso.com"

$JobStart = Get-Date

$Totalprocessed = $null

$Totalupdated = $null

$Userlistpath = "C:\cloudwyse\jobtitles.csv"

$Userlist = Import-csv $Userlistpath

$NewSession = New-PSSession -ComputerName $NewEnvDC -Credential $NewCred

Invoke-Command $NewSession -Scriptblock {Import-Module ActiveDirectory}

Import-PSSession $NewSession -Module ActiveDirectory

 

foreach ($User in $Userlist) {

       Try    {

             Get-ADuser $User.SAMAccountName -ErrorAction Stop | out-null

             }

       Catch [System.Management.Automation.RemoteException]        {

             Write-Host -ForegroundColor Cyan "The user" $User.SAMAccountName "was not found... skipping to next record..."

             $NextAction = "skip"

             }

       Finally {

             if ($NextAction -ne "skip") {

             Set-ADUser $User.SAMAccountName -Department $User.Department -Title $User.Title

             Write-Host -ForegroundColor Magenta "The title for" $User.SAMAccountName "was set to" $User.Title "and the department was set to" $User.Department

             $totalupdated = $totalupdated +1

             $NextAction = $null

             } else {

             $NextAction = $null

             }

             }

       $totalprocessed = $totalprocessed +1

       }                                                                 

$JobEnd = Get-Date

$JobSecondsTaken = ($JobEnd - $JobStart)

Write-Host -ForegroundColor Yellow "Processed $totalprocessed record(s) in" $JobSecondsTaken.Minutes "minute(s) and" $JobSecondsTaken.Seconds "second(s)."

Write-Host -ForegroundColor Yellow "Updated $totalupdated record(s)"

Remove-PSSession $NewSession

Stop-Transcript

 

 

Thanks and feel free to recycle/reuse.

 

 

 

Thursday, 31 January 2019

Powershell Script to Create Random Complex Passwords suitable for O365

 

 

This script enables you to generate a set of random complex passwords for a list of users which is imported as a CSV file.  The password will contain upper and lowercase letters, symbols, numbers and will always be between 8-16 characters in length (meeting the O365 requirements).  Obviously the functions can be tweaked to make the passords more or less secure and the script could be altered to add more sections to the password.  Remember each time a function is called within the foreach, the variable name will need to be different in order to stop the same part of the password repeating.  That’s why there are multiple random symbol and random numbers.

 

 

 

$JobStart = Get-Date

$userlistpath = "C:\cloudwyse\users_requiring_passwords.csv"

$wordlistpath = "C:\cloudwyse\dictionary.csv"

$DateTime = (Get-Date -Format "ddMMyyyy-HHmmss")

$exportpath = "C:\Cloudwyse\users_with_passwords$DateTime.csv"

Write-Host  -ForegroundColor Magenta "Importing lists from $userlistpath and $wordlistpath..."

$userlist = import-csv $userlistpath

$wordlist = import-csv $wordlistpath

$JobEnd = Get-Date

$JobSecondsTaken = ($JobEnd - $JobStart)

Write-Host -ForegroundColor Yellow "Lists imported taking" $JobSecondsTaken.Minutes "minute(s) and" $JobSecondsTaken.Seconds "second(s)."

$symbollist = @("`^","`!","`%","`&")

function RandomWord {$wordlist[(get-random -maximum 716)] | select-object -ExpandProperty Word}

function RandomNumber {get-random -minimum 10 -maximum 99}

function RandomSymbol {$symbollist[(get-random -maximum 4)]}

$total = $null

$Job2Start = Get-Date

$pwList = @()

foreach ($user in $userlist)     {

       $pwPart1 = RandomSymbol

       $pwPart2a = RandomWord

       $pwPart2 = (Get-Culture).TextInfo.ToTitleCase($pwPart2a.ToLower())

       $pwPart3 = RandomSymbol

       $pwPart4 = RandomNumber

       $pwPart5 = RandomNumber

       $longpass = "$pwPart1$pwPart2$pwPart3$pwPart4"

       if ($longpass.length -lt 8) {   

              do {

             $longpass += $pwPart5

             }

             until ($longpass.length -ge 8)

             }

       $password = $longpass.substring(0, [System.Math]::Min(16, $longpass.Length))

       $username = $user | Select-Object -ExpandProperty User

       $pw = New-Object PSObject

       $pw | Add-Member -type NoteProperty -Name 'User' -Value $username

       $pw | Add-Member -type NoteProperty -Name 'Password' -Value $password

       Write-Host  -ForegroundColor Magenta "Processed password for user" $username

       $pwlist += $pw

       $total = $total +1

       }

$Job2End = Get-Date

$Job2SecondsTaken = ($Job2End - $Job2Start)

Write-Host -ForegroundColor Yellow "Processed $total passwords in" $Job2SecondsTaken.Minutes "minute(s) and" $Job2SecondsTaken.Seconds "second(s)."

Write-Host  -ForegroundColor Magenta "Exporting list..."

$pwList | Export-csv -Path $exportpath

Write-Host -ForegroundColor Yellow "Finished exporting list to $exportpath"

 

 

The CSV file I used for the dictionary can be downloaded here.

 

 

 

Monday, 21 January 2019

Powershell Script to export a list of all proxyaddresses for all users in the O365 tenant

 

 

This script allows you to export a list of all users in the tenant and all associated proxy addresses.  It’s helpful to be able to get this as a csv filer for future reference so that you can quickly filter on whichever user you like.  It’s also been helpful for me on a recent migration where I was able to make sure that each user’s email addresses were properly migrated.

 

 

 

$LogFilePath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\user_proxy_addresses_" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $LogFilePath -NoClobber

$365Pass = cat C:\cloudwyse\securestring365.txt | convertto-securestring

$365Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "admin@contoso.com",$365Pass

$DateTime = (Get-Date -Format "ddMMyyyy-HHmmss")

 

$365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $365cred -Authentication Basic -AllowRedirection

Import-PSSession $365Session

Connect-Msolservice -Credential $365Cred

 

 

Write-Host  -ForegroundColor Magenta "Pulling mailbox information for all users, please be patient..."

$JobStart = Get-Date

$getmailbox = get-Mailbox

$JobEnd = Get-Date

$JobSecondsTaken =($JobEnd - $JobStart)

Write-Host  -ForegroundColor Yellow "Extract complete.  The Job took" $JobSecondsTaken.Seconds "seconds."

$total = $null

$Job2Start = Get-Date

$userList = @()

foreach ($user in $getmailbox)   {

$lookup = get-msoluser -userprincipalname $user.userprincipalname

       Write-Host  -ForegroundColor Magenta "Current user is" $user.userprincipalname

       $addresses = $lookup.proxyaddresses

       foreach ($address in $addresses) {

       $us = New-Object PSObject

             $us | Add-Member -type NoteProperty -Name 'UPN' -Value $lookup.userprincipalname

             $us | Add-Member -type NoteProperty -Name 'ProxyAddresses' -Value $address

             Write-Host  -ForegroundColor Cyan "Address is" $address

             $userList += $us

                                                                                              }

       $total = $total +1

                                                     

       }

$Job2End = Get-Date

$Job2SecondsTaken =($Job2End - $Job2Start)

Write-Host -ForegroundColor Yellow "$total users processed in" $Job2SecondsTaken.Minutes "minute(s) and" $Job2SecondsTaken.Seconds "second(s)."

Remove-PSSession $365Session

$userlist | export-csv C:\Cloudwyse\user_proxy_addresses$datetime.csv

Write-Host -ForegroundColor Yellow "Report exported to C:\Cloudwyse\user_proxy_addresses$datetime.csv"

 

Stop-Transcript

 

I’ve shared this before, but if you are unsure how to securely store credentials in a script without using plain text then follow the instructions here to create the securestring.txt.