Jump to content

Recommended Posts

Posted
I'd like to change all users UPNs within AD to [email protected] and then apply this said UPN as their proxyAddress.

 

Does anyone have any sample scripts that I could modify?

 

Why not do the heavy lifting for proxy address with an exchange email address policy?

Posted
Why not do the heavy lifting for proxy address with an exchange email address policy?

 

Many don't have exchange anymore. I am assuming the OP uses Office 365.

Posted
Many don't have exchange anymore. I am assuming the OP uses Office 365.

 

I get the impression they have a hybrid config, and that’s only supported with an on premise exchange server, precisely for jobs like this.

Posted
Many don't have exchange anymore. I am assuming the OP uses Office 365.

 

Spot on. Probably should have specified that in my original post.

 

It's a new tenancy we are migrating too. All UPNs are currently [email protected] I need to set them to their email address to make things simpler for logging into O365.

Posted (edited)

Hello,

 

Here is a quick script I just slapped together for you that would change all the users UPNs - to [email protected] - there is two variables at the top to change. It need ran as an administrator and on a device wither with RSAT installed or from a domain controller. I have done some very basic testing on my development domain and it worked but I recommend doing a few little tests of your own first. If you want any help or would like it to do more just fire me a message.

 

Thank you,

CaptainQwerty.

 

# Script: UPN change
# Author: CaptainQwerty 
# Date Created: 28/07/2019

#requires -module ActiveDirectory
#requires -RunAsAdministrator
# Change there two variables, the top one is your domain and the second one is the OU that contains the users
$domain = "Example.co.uk"
$ou = "OU=Staff,DC=Example,DC=co,DC=uk"
write-host "Importing Acive Directory module"
Import-Module ActiveDirectory

# Getting all users from the OU
$users = Get-ADUser -filter * -SearchBase $ou

# For each user in the OU change their UPN

foreach($user in $users){    
# Generating the UPN    
$firstname = $user.GivenName    
$firstInitial = $firstname.substring(0,1)    
$upn = "$firstInitial.$($user.surname)@$domain"    

# Setting the users UPN    
set-aduser $user -UserPrincipalName $upn
}

 

edit: Fixed formatting

Edited by QwertyMash
  • Thanks 1
Posted

I would put a try catch on the set is my only thought on a quick pass on the script above.

 

And some logging, by that i dont mean write-host... :-P

Posted
I would put a try catch on the set is my only thought on a quick pass on the script above.

 

And some logging, by that i dont mean write-host... :-P

 

Oh don't get me wrong I literally said I threw it together. I figured they could maybe add what they needed check wise and I totally agree with you haha

 

For instance it doesn't check for other people already having that UPN, when you sat writing Powershell on the mobile website it gets a little tedious haha

 

Original poster, if you'd like help finishing off the script to be more robust as suggested by the above just message me and while I'm at the PC I'd happily help.

  • Thanks 1
Posted
Hay @QwertyMash I was not calling you there was just adding my suggestions based on your saying it had been thrown together.

 

Spot on :) Yeah it needs more like haha it's just literally the core of what he asked for haha

Posted (edited)

Script: UPN change
# Author: CaptainQwerty 
# Date Created: 28/07/2019

#Script updated by: Hplum78
#Date updated: 29/07/2019
#Added functions for Script logging and error handling, Script will now create a log file in the following location C:\PowerShell\Logs\ Folder
#Depending on how this is run (in the ISE/ as a PS script) the log will take the form of  or will be 
#Added -whatif to the SET-ADUser command (Remove this after you have tested the script)

#requires -module ActiveDirectory
#requires -RunAsAdministrator
# Change the two variables, the top one is your domain and the second one is the OU that contains the users - removed the requirement for changing the domain var if this script is running on the domain that you are working in (HPlum78.

<#
.DESCRIPTION
   This function returns the filename with no extension of the current script
.PARAMETER StackDepth
   the stackdepth the retrieve
#>
function Get-ScriptFilenameNoExtension
{

  [CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$false)] [string]$StackDepth = 1
   )

   return [io.path]::GetFileNameWithoutExtension( $((Get-PSCallStack)[$StackDepth].ScriptName))
}

<#
.DESCRIPTION
   Setup global variable with full file path and filename of log file 
.PARAMETER None
#>
function Get-DefaultLogLocation 
{
$LogRootPath = 'C:\PowerShell\Logs\'
   
   $scriptname = Get-ScriptFilenameNoExtension -stackdepth 3
   return "$($LogRootPath)$scriptname\" + "$scriptname`_$(get-date -Format "yyyyMMdd_HHmmss").log"

}

<#
.DESCRIPTION
   This function check to see if the object passed in is either null, empty or whitespace
.PARAMETER o 
   The object for the test to be carried out on
#>
Function Get-IsNotNullEmptyOrSpace
{
   [CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$false)]$o
   )

   $return = $false
   try
   {
       IF([string]::IsNullOrWhiteSpace($o)) 
       {            
           Write-verbose "Given object is NULL/empty/whitespace"            
       } 
       else 
       {            
           Write-verbose "Given object has a value"
           $return = $true            
       }    
   }
   catch
   {
       Write-verbose "Error: Given object is NULL/empty/whitespace"            
   }
   return $return

}

<#
.DESCRIPTION
   This function pads a string with chars
.PARAMETER Str
   The string to be padded
.PARAMETER PadChar 
   The padding char
.PARAMETER MaxLength 
   The length of the string for the padding to add to
.PARAMETER PadLeft 
   If true, the padding will appear at the begining of the string otherwise by default it will appear at the end of the string
#>
function Set-PaddingToString
{
   Param (
       [Parameter(Position=0,Mandatory=$true)] [string]$Str, 
       [Parameter(Position=1,Mandatory=$false)] [char]$PadChar = " ",
       [Parameter(Position=2,Mandatory=$false)] [int]$MaxLength = 7,
       [Parameter(Position=3,Mandatory=$false)] [bool]$PadLeft = $false
   )

   try
   {
       if (!($PadLeft))
       {
           $return = $Str.PadRight($MaxLength,$PadChar)        
       }
       else
       {
           $return = $Str.PadLeft($MaxLength,$PadChar)        
       }
   }
   catch
   {
       $return = $Str
   }
   return $return
   
}


<#
.DESCRIPTION
   Enabled file based logging output from script
.PARAMETER None
#>
function Set-FileLogging 
{
$LogRootPath = 'C:\PowerShell\Logs\'
   
   if (Test-Path $LogRootPath){
       
           $logfullpath = split-path (Get-DefaultLogLocation)
           Log-WriteDebug "Log root path exists need to check subfolder: $logfullpath exists" 

            if (!(Test-Path ($logfullpath)))
            {
               
               Write-LogDebug "Need to create logging folder: $logfullpath"
               mkdir $logfullpath
            }
           
           $global:logfile = Get-DefaultLogLocation
           Log-WriteDebug "Setup global variable for logging path toer: $logfile exists" 

       }
   else
   {
   
       Log-WriteWarn "Default root log folder does not exist"
   }  

}

<#
.DESCRIPTION
   Breakdown and output attributes of the error
.PARAMETER ErrorRecord
   Error object to resolve
#>
function Resolve-Error
{
   [CmdletBinding()] 
   param(
       $ErrorRecord = ($error[0])
   )
   
   Write-verbose "Error Occurred. formatting..."
   
   $spacer = "-"*80
   
   Set-StrictMode -Off
   
   #$output = "`n`r" | out-string

   $output += "Error details:" | out-string
   $output += $errorRecord | Format-List * -Force | out-string


   $output += $spacer | out-string
   $output += "InvocationInfo :" | out-string
   $output += $errorRecord.InvocationInfo | Format-List * | out-string

   $output += $spacer | out-string
   $output += "TargetObject :" | out-string
   $output += $errorRecord.TargetObject | Format-List * | out-string


   $output += $spacer | out-string
   $output += "Exception :" | out-string
   $output += $exception = $errorRecord.Exception | out-string

   for ($i = 0; $exception; $i++, ($exception = $exception.InnerException))
   {
       $output += "Inner Exception $i :" | out-string
       $output += $exception | Format-List * -Force | out-string
   }
   return $output
}


<#
.DESCRIPTION
   This function outputs message to console and/or output file (if set)
.PARAMETER Message
   The message to write in the log file
.PARAMETER ForColour
   name of a Colour to be used for in the forColour attribute
.PARAMETER LogType
   the log type "INFO"
#>
Function Log-Write
{
   [CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$false)] [string]$Message, 
       [Parameter(Position=1,Mandatory=$false)] [string]$ForColour = "",
       [Parameter(Position=2,Mandatory=$false)] [string]$LogType = "INFO"
    )

   if (Get-IsNotNullEmptyOrSpace $logFile)
   {
       $timeStamp = (get-date).ToString() #get the date and time on the system now
       $logentry = (Set-PaddingToString $LogType) + " | " + $timeStamp + " | " + $Message 
       $logentry | out-file -filepath $logFile -Append

   }
   
   if( $ForColour -eq "")
   {
       Write-Host "$LogType | $Message"
   }
   else
   {
       Write-Host "$LogType | $Message" -foregroundcolor $ForColour
   }
}

<#
.DESCRIPTION
   Display and/or log to file of error message in appropriate Colour
.PARAMETER Message 
   message to be displayed/logged
.PARAMETER ErrorRecord
   Describes a terminating or nonterminating error that occurred during the processing of a command
#>
function Log-WriteError
{
[CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$false)] [string]$Message,
       [Parameter(Position=1,Mandatory=$false)] [system.Management.Automation.ErrorRecord]$ErrorRecord=$null
   )

   if ($Message -ne $null -and $ErrorRecord -eq $null)
   {
       Log-Write -forColour "red" -logtype "ERROR" -message $Message
   }

   if ($ErrorRecord -ne $null)
   {
       Log-WriteError -forColour "red"  -logtype "ERROR" -message ("$Message | Error Details:`n`r$(Resolve-Error($ErrorRecord))" )
   }

}

<#
.DESCRIPTION
   Display and/or log to file a warning message in appropriate Colour
.PARAMETER Message 
   Message to be displayed/logged
#>
function Log-WriteWarn
{
   [CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$true)] [string]$Message
   )

   Log-Write -forColour "darkyellow" -logtype "WARN" -message "$Message"
}

<#
.DESCRIPTION
   Display and/or log to file of info message in appropriate Colour
.PARAMETER Message 
   Message to be displayed/logged
#>
function Log-WriteInfo
{
   [CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$true)][string]$Message
   )

   Log-Write -message $Message -logtype "INFO"
}

<#
.DESCRIPTION
   Display and/or log to file of debug message in appropriate Colour
.PARAMETER Message 
   debug message to be displayed/logged
#>
function Log-WriteDebug
{
   [CmdletBinding()] 
   Param (
       [Parameter(Position=0,Mandatory=$true)] [string]$Message
   )

   if ($debug -eq 1)
   {
       Log-Write -message $Message -logtype "DEBUG"
   }
}

Set-FileLogging

$domain = $env:USERDNSDOMAIN
Log-WriteInfo "Working Doamin is $($Domain)" 

#$ou = "OU=Staff,DC=Example,DC=co,DC=uk"
Log-WriteInfo "Working OU is $($ou)"

Log-WriteInfo "Importing ActiveDirectory"

Try{
   Import-Module ActiveDirectory
   Log-WriteInfo "ActiveDirectory Module imported sucessfuly"
   }
   Catch{
       Log-WriteError "Failed to Import ActiveDirectory Module - Terminating Script"
}

# Getting all users from the OU

Try{
   Log-WriteInfo "Getting Users info from $($ou)"
   $users = Get-ADUser -filter * -SearchBase $ou
   }
   Catch{
       Log-WriteError "Failed to get Users from $($ou)"
}

# For each user in the OU change their UPN

foreach($user in $users){    
    
    Try{   
       # Generating the UPN    
       Log-WriteInfo "Gernerating UPN for User $(($user).name)"
       $firstname = $user.GivenName    
       $firstInitial = $firstname.substring(0,1)    
       $upn = "$firstInitial.$($user.surname)@$domain"
       Log-WriteInfo "New UPN for $(($user).name) is $($upn)"    

       # Setting the users UPN    
       Log-WriteInfo "Setting UPN for User $(($user).name)"
       set-aduser $user -UserPrincipalName $upn -whatif #Remove -whatif to arm this script
       }
       Catch{
           Log-WriteError "Failed to set UPN for $(($user).name)"
   }
}

 

The Error logging can been seen in the attached file.

 

Feel free to grab the error handling functions from the above to use in your own scripts.

 

Harry

_20190729_085817.txt

Edited by HPlum78
  • Thanks 1
Posted

Just noticed that i have mangled the log file in my attempts to anonymise the data but its there to show the format of the logging rather than anything else. If anyone needs more info on what those functions do that i have added feel free to ask but they are essentially the framework to enable logging of what you are doing in a PS script one of the functions sets out the formatting with the pipes and the likes in the log file.

 

Hope they help.

H.

Posted

Yeah I bet.... Thought that someone would say that I had over done it! Question I am asking myself is have I? (do the functions make sense, or have I scared everyone off it because of all the code)

 

What I do is have those functions in a separate module and then call them from my other scripts. What is not there is another few functions that I use for searching the log location on the script sever. As already noted the functions set out a framework for logging means that all my scripts log in the same format accross the board.

  • Thanks 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...