Author Archives: Andreas Lindahl

Exchange Online: How to create a dirsynced Resource Mailbox

The idea with DirSync is to keep your user administration on-prem. A problem arise when you decomission the on-premises Exchange server and want to create a Shared Mailbox or a Resource Mailbox. There is no simple way to create such mailbox without assigning a license. It is possible to create a new regular user, assign a license, and then convert it to a Shared Mailbox or a Resource Mailbox, but the drawback with this method is that it requires a license during the process. On the other hand your user account will be fully managed in your on-prem environment, and the goal is achieved.

Another possibility is to create a Resource Mailbox with a Cloud Identity, and then connect it to an account synced from your Active Directory. This is what I will show you now. Lets start with disabling DirSync. This step is not necessary, but we might get some problems if our accounts are synced before they are ready.

Stop-Service MSOnlineSyncScheduler

Then we create a user account in Active Directory that we will later sync to Office 365:

Import-Module ActiveDirectory
$ADUserProperties = @{
    Name =               'Meeting Room 1'
    Path =               'CN=Users,DC=365lab,DC=net'
    SamAccountName =     'room1'
    UserPrincipalName =  ''
    DisplayName =        'Meeting Room 1'
    EmailAddress =       ''
    OtherAttributes = @{
        ProxyAddresses = ''
$ADUser = New-ADUser @ADUserProperties -PassThru

The next step is to create a new Resource Mailbox in Office 365. This can be done either with GUI or PowerShell, I prefer PowerShell.

$O365cred = Get-Credential
$O365sess = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $O365cred -Authentication Basic -AllowRedirection
$importcmd = Import-PSSession $O365sess

$O365UserProperties = @{
    DisplayName =        'Meeting Room 1'
    Name =               'room1'

$RoomMailbox = New-Mailbox @O365UserProperties -Room

Now we have two separate accounts, one in Active Directory with the managed attributes, and one in the cloud that we want to connect to our on-prem identity. The connection is done by populating the ImmutableID attribute with the corresponding ObjectGuid from Active Directory. Also, we change the UserPrincipalName in Office 365 to match our domain account.

$ObjectGuid = $ADUser.objectGuid
$ImmutableId = [System.Convert]::ToBase64String($ObjectGuid.ToByteArray())

Import-Module MSOnline

Set-MsolUserPrincipalName -UserPrincipalName $RoomMailbox.UserPrincipalName -NewUserPrincipalName $ADUser.UserPrincipalName -ImmutableId $ImmutableId

Now our UserPrincipalNames are the same in both our Active Directory and in Office 365, and we have linked then together using the ObjectGuid/ImmutableId. Time to start our DirSync service again and force a synchronization to run.

Start-Service MSOnlineSyncScheduler

Import-Module DirSync
Start-OnlineCoexistenceSync -FullSync

Now the Cloud Identity is converted to a DirSynced Identity, and the attributes in Active Directory are syned to our new Resource Mailbox. From now on all user administration tasks for this account can be managed in our on-prem Active Directory.

/ Andreas


Automating the creation of Lync Online DNS Records

Recently I implemented Lync Online with a customer that had a lot of custom domain names. Adding the required DNS records manually would literary take hours, but luckily the customer used Windows DNS both internally and externally, so it was easy for me to write a script to add these DNS records.

In my case both DNS servers (internal and external) are running Windows Server 2008 R2. That gives me the option to use dnscmd.exe to add the records. Here is the script I used to add the records. Please note that you may need to modify the script if you are using subdomains.

#Get all domains registered in Office 365
Import-Module MSOnline
$domains = Get-MsolDomain | Where-Object { $_.Name -notlike '*' }
$dnsserver = 'srv-dns01'

#Loop through all domains and add the required DNS records for all domains
foreach ($domain in $domains) {
    Write-Verbose "Adding records for domain $($domain.Name)"
    &"dnscmd.exe $dnsserver /RecordAdd $($domain.Name) sip CNAME"
    &"dnscmd.exe $dnsserver /RecordAdd $($domain.Name) lyncdiscover CNAME"
    &"dnscmd.exe $dnsserver /RecordAdd $($domain.Name) _sipfederationtls._tcp SRV 100 1 5061"
    &"dnscmd.exe $dnsserver /RecordAdd $($domain.Name) _sip._tls SRV 100 1 443"

Now I reduced this time-consuming (and boring) task to just a few minutes!

/ Andreas

How to handle SMTP Relay after migrating to Exchange Online

When decomissioning your on-premises Exchange server after moving to Office 365 you need a new solution for SMTP relay to use with for example multi-functional printers. In some cases your internet provider can offer this service, but if you want control over your mail flow I recommend using Office 365 also for outgoing e-mail.

Normally you need a licensed user to be able to send e-mails using SMTP with Office 365. Your applications also need support for TLS encryption. If your application doesn’t support TLS, or if you need to send e-mails from another address than the licensed user’s address you need another solution. Luckily Office 365 can help you. The solution is to set up an inbound connector in Exchange Online Protection.

Setting up an Inbound Connector

An Inbound Connector is easily set up with just a few lines of PowerShell code. First we have to connect to Exchange Online.

$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange `
    -ConnectionUri '' `
    -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session -CommandName 'New-InboundConnector'

Now we can create the Inbound Connector. All we have to specify is a Name for our connector, SenderIPAddresses which is the IP addresses to allow relaying from (your external IP address), and SenderDomains which is the domains to accept messages from.

You can also get your external IP address with PowerShell, here I will use a free IP detection tool from Dyn.

$ip = (Invoke-WebRequest -Uri `
    -replace '[^\d\.]'
New-InboundConnector `
    -Name 'SMTP Relay' `
    -SenderIPAddresses $ip `
    -SenderDomains ''

The settings for Mail Flow are also found in Exchange admin center, navigate to mail flow, and then go to the connectors section. Of course you can also use the GUI to create your connector.


When configuring your application to connect to this SMTP server, use your MX server name as SMTP server and connect using port 25. The server name can be found in Office 365 admin center, and looks something like

Increasing security

With this method all computers on your network sharing the same external IP address can use your Inbound Connector. To strengthen the security I recommend only opening port 25 in the firewall from your devices that actually sends email. An even better alternative would be to set up an internal SMTP server that only accept connections from approved devices, and then uses your Inbound Connector as smart host. This can be achieved with the SMTP Service provided with Internet Information Services (IIS) in Windows Server.

Configuring IIS SMTP Service

First we have to install the SMTP Service in Windows. This can be done with PowerShell.

Note that the Add-WindowsFeature cmdlet in Windows Server 2012 is called Install-WindowsFeature, but Add-WindowsFeature still exists as alias for backward compatibility.

Import-Module ServerManager
Add-WindowsFeature SMTP-Server

This will also install the required dependencies for example the IIS 6 Management Console. When the installation is done we are ready to start configuring the service. Let’s set the service to start automatically when Windows starts:

Set-Service SMTPSVC -StartupType Automatic

The next step is to set Office 365 as Smart Host. Replace the Smart Host name with your own MX server.

$smtpsvc = [ADSI]'IIS://localhost/smtpsvc/1'
$smtpsvc.SmartHost = ''

We also have to set a Fully Qualified Domain Name to identify our SMTP Server.

$hostname = (Resolve-DnsName $ip).NameHost
$smtpsvc.FullyQualifiedDomainName = $hostname

Finally we have to add our internal IP addresses that are allowed to use the SMTP Service. I prefer using the GUI for this. You will find these settings in the Internet Information Services (IIS) 6.0 Manager. Expand the local computer node, and right click on “SMTP Virtual Server #1” and choose Properties. On the Access tab click on Relay restrictions, and then add your local IP addresses that are allowed to use the SMTP Server. While in the GUI settings I also suggest having a look at the message size limits and logging settings.

Now we are all set. Don’t forget to configure your perimeter firewall to block outgoing SMTP traffic from all your computers except the SMTP Server.

/ Andreas

PowerShell GUI application to set thumbnailPhoto

A while ago I started experimenting with writing GUI applications in PowerShell. This script that updates the thumbnailPhoto attribute of a user was my first attempt, and since it works quite well I thought that I might share it with you.

The thumbnailPhoto attribute is used more and more, and it is now supported by Outlook, SharePoint and Lync. It is also supported by Office 365, and when using DirSync the data is synced to Windows Azure Active Directory.

This script uses Windows Presentation Foundation (WPF) which is part of .Net 3.0. The window form is easily built with Microsoft Visual Studio Express 2013 for Windows Desktop and can be saved as a XAML document, which we can import in our PowerShell script.

Data are saved and retrieved from Active Directory using ADSI, which means no additional PowerShell modules must be installed. The only requirements are PowerShell 2.0 or newer with .Net Framework 3.0. If running PowerShell version 2.0 you also need the -STA parameter to powershell.exe.

The application itself is very simple, just type the username in the search box, and browse for a photo. When clicking Apply the image data is saved to Active Directory. By default all users has permission to change their own thumbnailPhoto. To change other users, permissions needs to be delegated.

There is a limit in picture size, maximum size is 100 kB, but since Office 365 cannot handle that large image I have set the limit in the script to 10 kB. Also recommended resolution is 96×96 pixels.


Here’s the full script, please note that you need a valid path to the .xaml document.


<Window x:Class="MainWindow"
    Title="Thumbnail photo changer app" Height="350" Width="525" ResizeMode="NoResize">
    <Grid x:Name="list1" Margin="0,0,0,2">
        <Label Content="Username:" HorizontalAlignment="Left" Width="105" Margin="20,23,0,250" />
        <TextBox x:Name="txtSearch" Margin="138,27,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="122"/>
        <Button x:Name="btnSearch" Content="Search" HorizontalAlignment="Left" VerticalAlignment="Top" Width="50" Margin="271,27,0,0"/>
        <Label Content="Surname:" HorizontalAlignment="Left" Height="30" Margin="20,92,0,0" VerticalAlignment="Top" Width="92"/>
        <Label x:Name="lblSn" Content="" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left" Width="315" Margin="134,92,0,0"/>
        <Label Content="UserPrincipalName:" HorizontalAlignment="Left" Height="30" Margin="20,123,0,0" VerticalAlignment="Top" Width="115"/>
        <Label x:Name="lblUPN" Content="" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left" Width="346" Margin="134,123,0,0"/>
        <Label Content="Givenname:" HorizontalAlignment="Left" Height="30" Margin="20,61,0,0" VerticalAlignment="Top" Width="92"/>
        <Label x:Name="lblGivenName" Content="" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left" Width="315" Margin="134,61,0,0"/>
        <Image x:Name="imgThumb" HorizontalAlignment="Left" Height="96" Margin="29,203,0,0" VerticalAlignment="Top" Width="96"/>
        <Button Name="btnImg" Content="Change photo..." HorizontalAlignment="Left" Height="28" Margin="149,267,0,0" VerticalAlignment="Top" Width="111" IsEnabled="False"/>
        <Label Content="DistinguishedName:" HorizontalAlignment="Left" Height="30" Margin="20,156,0,0" VerticalAlignment="Top" Width="126"/>
        <Label x:Name="lblDN" Content="" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left" Width="373" Margin="134,156,0,0"/>
        <Button x:Name="btnApply" Content="Apply" HorizontalAlignment="Left" Height="28" Margin="278,267,0,0" VerticalAlignment="Top" Width="111" IsEnabled="False"/>


if ([threading.thread]::CurrentThread.ApartmentState.ToString() -eq 'MTA') {
    Write-Error "This script requires PowerShell to run in Single-Threaded Apartment. Please run powershell.exe with parameter -STA"

Add-Type -AssemblyName PresentationFramework 
[xml]$XAML = Get-Content "Set-ThumbnailPhotoGUI-mainform.xaml"
$global:userinfo = @{
    dn = $null
    photo = [byte[]]$null
function Invoke-FileBrowser {
    param([string]$Title,[string]$Directory,[string]$Filter="jpeg (*.jpg)|*.jpg")
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
    $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
    $FileBrowser.InitialDirectory = $Directory
    $FileBrowser.Filter = $Filter
    $FileBrowser.Title = $Title
    $Show = $FileBrowser.ShowDialog()
    If ($Show -eq "OK") { Return $FileBrowser.FileName }
function Get-LDAPUsers($sam) {
    $activeDomain = New-Object DirectoryServices.DirectoryEntry
    $domain = $activeDomain.distinguishedName
    $searcher = [System.DirectoryServices.DirectorySearcher]"[ADSI]LDAP://$domain"
    $searcher.filter = "(&(samaccountname=$sam)(objectClass=user)(objectClass=person))"
    $result = $searcher.findall()
    if ($result.count -gt 1) {
        Write-Warning "More than one user found. Please refine your search."
    } elseif ($result.count -eq 1) {
        $result = $searcher.findone().getDirectoryEntry()
            UserPrincipalName = $result.userprincipalname[0]
            DistinguishedName = $result.distinguishedname[0]
            samAccountName = $result.samaccountname[0]
            Givenname = $result.givenname[0]
            Surname = $[0]
            ThumbnailPhoto = $result.thumbnailphoto
function Update-WPFForm($sam) {
   $selecteduser = Get-LDAPUsers $sam
   if ($selecteduser) {
        $global:userinfo.dn = $selecteduser.DistinguishedName
        $ = [byte[]]$($selecteduser.thumbnailphoto)
        $lblGivenName.Content = $selecteduser.GivenName
        $lblSN.Content = $selecteduser.SurName
        $lblUPN.Content = $selecteduser.UserPrincipalName
        $lblDN.Content = $global:userinfo.dn
        $txtSearch.Text = $selecteduser.SamAccountName
        $imgThumb.Source = $
        $btnImg.IsEnabled = $true
#region GUI
    $reader=(New-Object System.Xml.XmlNodeReader $xaml)
    $btnSearch = $window.FindName("btnSearch")
    $btnImg = $window.FindName("btnImg")
    $btnApply = $window.FindName("btnApply")
    $txtSearch = $window.FindName("txtSearch")
    $lblGivenName = $window.FindName("lblGivenName")
    $lblSn = $window.FindName("lblSn")
    $lblUPN = $window.FindName("lblUPN")
    $lblDN = $window.FindName("lblDN")
    $imgThumb = $window.FindName("imgThumb")
#endregion GUI
#region Events
    #region btnSearchClick
        $btnSearch_click = $btnSearch.add_Click
    #endregion btnSearchClick
    #region btnImgClick
        $btnImg_click = $btnImg.add_Click
            $file = Invoke-FileBrowser -Title "Choose a thumbnail photo" -Filter "Jpeg pictures (*.jpg)|*.jpg"
            if ($file) {
                if ((Get-Item $file).length -gt 10kB) {
                    Write-Warning "Picture too large. Maximum size is 10 kB."
                } else {
                    $ = [byte[]](Get-Content $file -encoding byte)
                    $imgThumb.Source = $
                    $btnApply.IsEnabled = $true
    #endregion btnImgClick
    #region btnApplyClick
        $btnApply_click = $btnApply.add_Click
            $user = New-Object DirectoryServices.DirectoryEntry "LDAP://$($global:userinfo.dn)"
            $user.put("thumbnailPhoto", $
            $btnApply.IsEnabled = $false
            Write-Verbose "User $($global:userinfo.dn) updated."
    #endregion btnApplyClick
    #region textChange
        $txtSearch_Change = $txtSearch.add_KeyDown
            if ($_.Key -ieq 'Return') {
    #endregion textChange
#endregion Events
$window.ShowDialog() | Out-Null

This is just an example how a useful script with GUI can be written with quite simple means. Now let’s get the camera and take some photos!

/ Andreas

Using Exchange Online as mail gateway for decentralized email domains

In some scenarios it is useful to have a central email server that forwards messages to different email servers. You might for example have a company with different business units, each having an email server of their own. In this post I will show you how to get started with the mail flow using one domain, but with several different email servers in Exchange Online.

Consider the following scenario. Several email servers exists within a company:

  • In USA an on-premises Exchange environment is using addresses
  • In Spain an external hosting provider is delivering an email service based on pop3 using addresses
  • In Poland Exchange Online is used, but with addresses

A new corporate policy states that all users must have an email address of the form Also, a central antispam system must be used. At this point no consolidation of email servers will be done. Exchange Online Protection licenses has been bought by the company.

To take care of the mail flow in Exchange Online we have to create our Office 365 tenant and add the domain to it. We also have to change our DNS and let the MX records for point to Exchange Online. This will give us the following mail flow for a user in for example Poland:

Mail flow

I have a csv file with all users in each location:


For each user we will create a mail enabled user that holds the alias and target email addresses. I will use PowerShell to create these users:

#Import all users
$users = Import-Csv users.csv

#Create a password for all users
$Password = ConvertTo-SecureString 'Pa$$w0rd' -asPlainText -Force

#Create mail-enabled user
ForEach ($user in $users) {
	$Name = $user.Name
	$Email = $user.Alias
	$Target = $user.Email
	New-MailUser -Name $Name -MicrosoftOnlineServicesID $Email -ExternalEmailAddress $Target -Password $Password

Now all emails sent to the addresses will be delivered to the current regional email server. The next step would be to configure each email server to use as from address, and only accept incoming emails from Exchange Online.

/ Andreas

How to manually configure an Outlook profile for Office 365

Manually configuring Outlook for Office 365 can be tricky. That’s what Autodiscover is for. But in some situations you have to be able to do a manual configuration in for example a pilot deployment. Here are the steps required.

The nice thing with this method is that we will be able configure Outlook without changing our Autodiscover DNS records. That means we can do a full Office 365 test deployment without affecting users in an on-premises Exchange environment.

The first step is to establish a remote PowerShell session to Exchange Online. Here we need the ExchangeGuid attribute from our mailbox. Copy this value and save it for later.


The next step is to launch the New Profile Wizard in Outlook. We will go for the option to do a Manual setup.


In the next screen we select that we have a Microsoft Exchange Server.


Now it’s time to enter the exchange server name. Here we need the ExchangeGuid from the first step. Write the Guid followed by @ and the email domain. The user name is our Office 365 user name.
Now click More Settings.


On the Security tab we select Anonymous Authentication.


On the Connection tab check the box to connect using HTTP and click Exchange Proxy Settings


Fill in all values as below


Click OK to close all windows. You will be asked for credentials, fill in your Office 365 username and password.


Now our Outlook Profile is ready to use and Outlook is configured for Exchange Online, without using Autodiscover.

/ Andreas

Exchange Online: Migrating shared mailboxes and resources

In Exchange 2003 Resource Mailboxes and Shared Mailboxes are often set up as a regular user mailbox. These mailboxes are still possible to migrate using Staged Migration or Cutover Migration, by migrating them as a regular user mailbox. The downside is that they will require an Exchange Online license.

If you are migrating from an Exchange version that supports Hybrid Migration you will be able to migrate resources directly without assigning licenses, but there is a workaround for Cutover and Staged migrations as well.

The process of migrating a Shared Mailbox or Resource Mailbox is as follows:

  1. Migrate mailbox as regular user mailbox
  2. Assign license
  3. Convert mailbox to shared/resource
  4. Remove license

To convert a user mailbox to a shared mailbox we just need one line of PowerShell. Except from changing the type, we also have to modify the mailbox quotas.

Set-Mailbox -Identity "" `
	-Type Shared `
	-IssueWarningQuota 9.5GB `
	-ProhibitSendQuota 9.75GB `
	-ProhibitSendReceiveQuota 10GB

The same thing applies to Resource Mailboxes (Rooms and Equipment). The difference here is that we also want to configure AutoAccept policies and set default access rights to the calendar:

Set-Mailbox -Identity "" `
	-Type Room `
	-IssueWarningQuota 9.5GB `
	-ProhibitSendQuota 9.75GB `
	-ProhibitSendReceiveQuota 10GB

Set-CalendarProcessing -Identity "" `
	-AutomateProcessing AutoAccept 

Add-MailboxFolderPermission "\Calendar" `
	-User Default `
	-AccessRights LimitedDetails

After this is done the license can be removed. You will get a warning that your data will be lost, but it is safe to click Yes on this one.


/ Andreas

Quick Tip: Forcing Office 365 Directory Synchronization to run

This blog post was written for an older version of the Azure AD Connect Synchronization Service. For information regarding the current version please look at the documentation from Microsoft.

Sometimes you need changes in your on-premises Active Directory to sync to Office 365 as soon as possible. You might, for example, have a new employee at your doorstep one morning, and you quickly have to create an account for him. Normally a sync is only done every three hours. With these commands your data is synced immediately.

Depending on your version of DirSync/AADSync the commands are a bit different:

DirSync prior to version 6862.0000

To start a manual sync you launch the DirSyncConfigShell Console File, located at C:\Program Files\Windows Azure Active Directory Sync.

A sync is triggered by the command


You can also trigger a full sync by using the -FullSync parameter.

If you are using DirSync with Password Sync you can also run a full password sync with the following lines of PowerShell code:

Restart-Service FIMSynchronizationService -Force

The DirSync result can be viewed in the FIM Client, but to see the result of Password Sync you need to look at the Event Viewer in Windows.

DirSync version 6862.0000 and later

Starting with DirSync version 6862.0000 released on June 5 2014 there is no longer a DirSyncConfigShell Console file in the Program Files folder. Instead you just start a normal PowerShell window and run Import-Module DirSync. After that the Start-OnlineCoexistenceSync cmdlet is available.

Forcing a Password Sync uses the same lines of PowerShell code as the previous versions:

Restart-Service FIMSynchronizationService -Force

Azure Active Directory Synchronization Services (AAD Sync)

A Directory Synchronization is triggered by running an exe file:

C:\Program Files\Microsoft Azure AD Sync\Bin\DirectorySyncClientCmd.exe


DirectorySyncClientCmd.exe accept two parameters, initial and delta. Running DirectorySyncClientCmd.exe initial initiates to a FullSync, and running DirectorySyncClientCmd.exe delta (or without any parameters) initiates an incremental sync.

The delta synchronization is triggered every 3 hours, and it can also be started manually by running the Scheduled Task “Azure AD Sync Scheduler” in the Task Scheduler.

To force a Password Sync the following lines of PowerShell code is needed. Modify the first two lines to match your environment.

$adConnector  = ''
$aadConnector = ' - AAD'

Import-Module ADSync

$c = Get-ADSyncConnector -Name $adConnector
$p = New-Object Microsoft.IdentityManagement.PowerShell.ObjectModel.ConfigurationParameter 'Microsoft.Synchronize.ForceFullPasswordSync', String, ConnectorGlobal, $null, $null, $null
$p.Value = 1
$c = Add-ADSyncConnector -Connector $c
Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $false
Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $true 

/ Andreas

Exchange Online: Pre-populate language and time zone on new mailboxes

When a new Exchange Online mailbox is created the user is prompted to set language and time zone at first logon. This information is possible to pre-populate to make the experience smoother for the end users. This is particularly useful in a migration scenario.

2014-02-08 21-18-09

These settings are set with the cmdlet Set-MailboxRegionalConfiguration.


Set-MailboxRegionalConfiguration -identity "" `
    -TimeZone "W. Europe Standard Time" -Language "sv-SE" -confirm:$false

Some useful links:

/ Andreas

Fix broken shortcuts during file server migrations

During a file server migration several problems arise. Most of them are eliminated by using DFS Namespaces. With DFS all paths are kept the same even though the file server itself is changed. Having that in mind, I really hope that everyone is using DFS for file servers.

In scenarios where UNC paths that points directly to the file server are used we have to find a way to minimize problems for the end users when the paths are changed.

It is very common that end users have shortcuts on their desktops that point to folders and documents on the server. I will give you a simple script that will replace the path for you.

This script is written in VBScript. The first two lines defines the old path, and what to replace it with.

'Define paths
strFind = "\\oldserver\share1\"
strReplace = "\\newserver\share2\"

Set objWsh = CreateObject("WScript.Shell")
Set objWshSysEnv = objWsh.Environment("PROCESS")
strProfilePath = objWshSysEnv("USERPROFILE")

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strProfilePath & "\Desktop")

'Loop through all files on the desktop
For Each file In objFolder.Files
	if right(file.Name,3)="lnk" then
		'If a shortcut is found
		Set objLink = objWsh.CreateShortcut(file.Path)

		objLink.Arguments = Replace(objLink.Arguments,strFind,strReplace,1,-1,1)
		objLink.TargetPath = Replace(objLink.TargetPath,strFind,strReplace,1,-1,1)
		objLink.WorkingDirectory = Replace(objLink.WorkingDirectory,strFind,strReplace,1,-1,1)

	end if

Run this script as a login script on your clients and you will have one problem less the day after your file server migration.

/ Andreas