This may save you a fair bit of trouble in the future. I was working on a client with an Exchange 2007 server that was overrun with contacts. That’s not necessarily a problem in and of itself, but these contacts had served their purpose and now needed to be turned into mail enabled users. They already had a number of duplicates between AD users and contacts and it was causing a lot of trouble in their SharePoint hierarchy. Fortunately PowerShell can step in and save the day! Or would you really enjoy manually copying over all of the contact’s profile data to an AD user? Not my idea of fun.
Here’s the code. You’ll want to tweak it to your purposes of course. I wanted some clear on the screen results as it progressed and also have an HTML report that I can reference afterwards. This marked my first venture in LINQ with moderate success. I will have to revisit things later to get it working exactly how I want.
<# .SYNOPSIS Reads in a CSV of contacts or mail enabled users and moves the contacts to mail enabled users or updates the current mail enabled users .DESCRIPTION Convert-CSVContactsToUsers reads in the CSV specified in the command line. This CSV contains a list of users that either currently have a contact which needs to be converted to a mail enabled user, have both a contact and a user that is not mail enabled which needs the info from the contact copied over to the user which is then mail enabled, or have neither a contact or a user and need to have a mail enabled user created for them. .PARAMETER FilePath The path and filename to the CSV containing the required users. .PARAMETER DomainController The NetBIOS or FQDN for the target DC to use. .PARAMETER ResultsFile The filename to save the HTML formatted results to. .EXAMPLE Convert-CSVContactstoUsers -FilePath .\UserList.csv -DomainController dc01 -ResultsFile .\Results.html .NOTES Require Server 2008 R2 and should be run from the EMS. .NET 3.5 and above required for HTML output. Appropriate domain and Exchange rights are required. Revision History v1.0 - Initial release v1.1 - Added X500 address, moved status report #> [CmdletBinding()] param( [Parameter(Mandatory=$True)][string]$FilePath, [Parameter(Mandatory=$True)][string]$DomainController, [Parameter(Mandatory=$False)][string]$ResultsFile ) Import-Module ActiveDirectory #$ErrorActionPreference= 'silentlycontinue' $CSVList = Import-CSV -Path "$($FilePath)" $Password = ConvertTo-SecureString -String "expPassword!!" -AsPlainText -Force # Create a custom table for storing the results $ResultsTable = New-Object System.Data.DataTable "Conversion Results" $column01 = New-Object System.Data.DataColumn User $column02 = New-Object System.Data.DataColumn Result $ResultsTable.columns.add($column01) $ResultsTable.columns.add($column02) # Loop through each CSV entry, check for object existence # then process the object based on existence and type foreach($TargetUser in $CSVList) { # Check for existence of any objects $ADContact = Get-ADObject -LdapFilter "(&(CN=$($TargetUser.Name))(ObjectClass=contact))" -SearchScope Subtree -Properties * -Server $DomainController $ADUser = Get-ADObject -LdapFilter "(&(CN=$($TargetUser.Name))(ObjectClass=user))" -SearchScope Subtree -Properties * -Server $DomainController $ResultsRow = $ResultsTable.NewRow() $ResultsRow.User = $TargetUser.Name [string]$Status = $null # If both contact and user exist, copy the info from the contact # into the user's properties, remove the contact, then mail enable the user if($ADContact -and $ADUser) { # First copy over any of the current profile details if($ADContact.directReports) { $ADUser.directReports = $ADContact.directReports } if($ADContact.homePhone) { $ADUser.homePhone = $ADContact.homePhone } if($ADContact.facsimileTelephoneNumber) { $ADUser.facsimileTelephoneNumber = $ADContact.facsimileTelephoneNumber } if($ADContact.l) { $ADUser.l = $ADContact.l } if($ADContact.manager) { $ADUser.manager = $ADContact.manager } if($ADContact.mobile) { $ADUser.mobile = $ADContact.mobile } if($ADContact.physicalDeliveryOfficeName) { $ADUser.physicalDeliveryOfficeName = $ADContact.physicalDeliveryOfficeName } if($ADContact.postalCode) { $ADUser.postalCode = $ADContact.postalCode } if($ADContact.sn) { $ADUser.sn = $ADContact.sn } if($ADContact.st) { $ADUser.st = $ADContact.st } if($ADContact.streetAddress) { $ADUser.streetAddress = $ADContact.streetAddress } if($ADContact.telephoneNumber) { $ADUser.telephoneNumber = $ADContact.telephoneNumber } if($ADContact.title) { $ADUser.title = $ADContact.title } if($ADContact.department) { $ADUser.department = $ADContact.department } if($ADContact.Description) { $ADUser.Description = $ADContact.Description } if($ADContact.c) { $ADUser.c = $ADContact.c } if($ADContact.co) { $ADUser.co = $ADContact.co } if($ADContact.countryCode) { $ADUser.countryCode = $ADContact.countryCode } if($ADContact.info) { $ADUser.info = $ADContact.info } if($ADContact.initials) { $ADUser.initials = $ADContact.initials } if($ADContact.ipPhone) { $ADUser.ipPhone = $ADContact.ipPhone } if($ADContact.pager) { $ADUser.pager = $ADContact.pager } if($ADContact.wWWHomePage) { $ADUser.wWWHomePage = $ADContact.wWWHomePage } if($ADContact.postOfficeBox) { $ADUser.postOfficeBox = $ADContact.postOfficeBox } if($ADContact.company) { $ADUser.company = $ADContact.company } # Update the user with the current info Set-ADObject -Instance $ADUser -Server $DomainController # Loop through the groups and add the user to them foreach($ADGroup in $ADContact.memberOf) { Add-ADGroupMember -Identity "$($ADGroup)" -Members $ADUser -Server $DomainController } # Next, remove the contact Remove-MailContact -Identity $ADContact.DistinguishedName -Confirm:$false -DomainController $DomainController # Enable the current user, then copy over the remaining attributes Enable-MailUser -Identity $ADUser.DistinguishedName -ExternalEmailAddress $ADContact.mail -Alias $ADContact.mailNickname -DomainController $DomainController | Out-Null # Add the X500 address if the contact was stamped with a legacyExchangeDN if($ADContact.legacyExchangeDN) { $X500User = Get-MailUser -Identity $ADUser.DistinguishedName -DomainController $DomainController $X500User.EmailAddresses += [Microsoft.Exchange.Data.CustomProxyAddress]("X500:$($ADContact.legacyExchangeDN)") Set-MailUser -Identity $X500User -EmailAddresses $X500User.EmailAddresses -DomainController $DomainController } Write-Host "$($TargetUser.Name) converted." $Status = "Success" } elseif($ADContact) { # First remove the contact Remove-MailContact -Identity $ADContact.DistinguishedName -Confirm:$false -DomainController $DomainController # Create the mail enabled user New-MailUser -Name "$($TargetUser.Name)" -ExternalEmailAddress $ADContact.mail -Alias $ADContact.mailNickname -UserPrincipalName "$($ADContact.mailNickname)@domain.local" -Password $Password -ResetPasswordOnNextLogon:$true -DomainController $DomainController | Out-Null # Then copy in the attributes $ADUser = Get-ADObject -LdapFilter "(&(CN=$($TargetUser.Name))(ObjectClass=user))" -SearchScope Subtree -Properties * -Server $DomainController $ADUser.directReports = $ADContact.directReports $ADUser.homePhone = $ADContact.homePhone $ADUser.facsimileTelephoneNumber = $ADContact.facsimileTelephoneNumber $ADUser.l = $ADContact.l $ADUser.manager = $ADContact.manager $ADUser.mobile = $ADContact.mobile $ADUser.physicalDeliveryOfficeName = $ADContact.physicalDeliveryOfficeName $ADUser.postalCode = $ADContact.postalCode $ADUser.sn = $ADContact.sn $ADUser.st = $ADContact.st $ADUser.streetAddress = $ADContact.streetAddress $ADUser.telephoneNumber = $ADContact.telephoneNumber $ADUser.title = $ADContact.title $ADUser.department = $ADContact.department $ADUser.Description = $ADContact.Description $ADUser.c = $ADContact.c $ADUser.co = $ADContact.co $ADUser.countryCode = $ADContact.countryCode $ADUser.info = $ADContact.info $ADUser.initials = $ADContact.initials $ADUser.ipPhone = $ADContact.ipPhone $ADUser.pager = $ADContact.pager $ADUser.wWWHomePage = $ADContact.wWWHomePage $ADUser.postOfficeBox = $ADContact.postOfficeBox $ADUser.company = $ADContact.company # Copying over the X500 address if it exists if($ADContact.legacyExchangeDN) { $X500User = Get-MailUser -Identity $ADUser.DistinguishedName -DomainController $DomainController $X500User.EmailAddresses += [Microsoft.Exchange.Data.CustomProxyAddress]("X500:$($ADContact.legacyExchangeDN)") Set-MailUser -Identity $X500User -EmailAddresses $X500User.EmailAddresses -DomainController $DomainController } Set-ADObject -Instance $ADUser -Server $DomainController # Loop through the groups and add the user to them foreach($ADGroup in $ADContact.memberOf) { Add-ADGroupMember -Identity "$($ADGroup)" -Members $ADUser -Server $DomainController } Write-Host -ForegroundColor Yellow "$($TargetUser.Name) created." $Status = "Success" } elseif($ADUser) { # Only a user is found Write-Host -ForegroundColor Cyan "$($TargetUser.Name) already exists." $Status = "Exists" } else { Write-Host -ForegroundColor Magenta "$($TargetUser.Name) not found!" $Status = "Failed" } # Update the results $ResultsRow.Result = $Status # Clear the variables to prevent false positives on the next loop $ADContact = $null $ADUser = $null $Status = $null # Update the results table $ResultsTable.Rows.Add($ResultsRow) } # Check if HTML results should be written out if($ResultsFile) { # Build the style sheet for the page $Style = "<style>" $Style = $Style + "body{font-family: `"Century Gothic`"; font-size: 10pt;}" $Style = $Style + "table{border-width: 1px; border-style: solid; border-color black; border-collapse: collapse; }" $Style = $Style + "th{border-width: 1px; border-style: solid; border-color: black; background-color: #CBFEFF; }" $Style = $Style + "td{border-width: 1px; border-style: solid; border-color: black; text-align: center}" $Style = $Style + "</style>" # LINQ will be used for easier custom formatting Add-Type -AssemblyName System.Xml.Linq # Convert the desired columns into HTML and convert it to XML $xml = [System.Xml.Linq.XDocument]::Parse("$($ResultsTable | Select User,Result | ConvertTo-Html -Head $Style)") # Define the namespace if($Namespace = $xml.Root.Attribute("xmlns").Value) { $Namespace = "{{{0}}}" -f $Namespace } # # $xml.Descendants().Value is not returning the values for some reason here # Have to resort to alternate index discovery # #$wsIndex = [Array]::IndexOf($xml.Descendants("${Namespace}th").Value, "Result") [Array]$xmlArray = $xml.Descendants("${Namespace}th") for($i=0;$i -le $xmlArray.length-1;$i++) { #We're color coding the Results column if($xmlArray[$i] -match "Result") { $wsIndex = $i } } # Loop through each row and assign a text color and background color to the result foreach($row in $xml.Descendants("${Namespace}tr")) { switch(@($row.Descendants("${Namespace}td"))[$wsIndex]) { {"Success" -eq $_.Value} {$_.SetAttributeValue("style", "color: #006600; background-color: #F1FEFE;"); continue} {"Failed" -eq $_.Value} {$_.SetAttributeValue("style", "color: #660000; background-color: #F1FEFE;"); continue } {"Exists" -eq $_.Value} {$_.SetAttributevalue("style", "color: #4D6600; background-color: #F1FEFE;"); continue } } } # Save to the desired file $xml.Save("$pwd/$($ResultsFile)") }
Use safely!