If you are in process of upgrading from Exchange 2003 to Exchange 2010, you must have read “Upgrade from Exchange 2003 Transport” article on Technet which spells out the details of a requirement – “minor link state updates must be suppressed to make sure that message looping doesn’t occur when a route is recalculated”.
I will not go into details of the requirement, however, if you read the details in the “Suppress Link State Updates” article, you know that the task can be daunting, especially if you have multiple Exchange 2003 servers, possibly in geographically dispersed locations.
Well, sweat no more. I have written a script that will help you get it done easily. Here’s the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | ############################################################################# # Suppress-Linkstate.ps1 # Using static text file or Get-ExchangeServer, this script will configure # selected Exchange 2003 servers to suppress Link State to aid in upgrade to # Exchange Server 2010 environment. # # Use this script in accordance to the following Technet article # http://technet.microsoft.com/en-us/library/aa996728.aspx # # Created by # Bhargav Shukla # https://www.bhargavs.com # # DISCLAIMER # ========== # THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE # RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER. ############################################################################# function Suppress-Linkstate { # Create empty results file or overwrite existing file "Server Name,SuppressStateChanges,ServiceStopState,ServiceStartState" | Out-File .\results.csv -Encoding ASCII foreach ($Server in $Servers) { # Do Nothing if $_ is null if ($Server -ne $null) { # Set server to connect to #$Server = "$_" # Read SuppressStateChanges from servers # Set Registry Key variables $REG_KEY = "System\\CurrentControlSet\\Services\\RESvc\\Parameters" $VALUE = "SuppressStateChanges" # Open remote registry $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Server) # Open the targeted remote registry key/subkey as read/write $regKey = $reg.OpenSubKey($REG_KEY,$true) # Set SuppressStateChanges to 1 if key exists if ($regKey -ne $null) { $regKey.Setvalue('SuppressStateChanges', '1', 'Dword') # Write changes to registry without closing it $regKey.Flush() # Read and Store SuppressStateChanges value in variable $SuppressStateChanges = $regkey.getvalue($VALUE) # Close the Reg Key $regKey.Close() } # Restart SMTP service, the Microsoft Exchange Routing Engine service, and the Microsoft Exchange MTA Stacks service #### You must specify a timeout (in seconds) or the script could potentially never end $TimeOut = 30 #### This will stop a single service on all servers in sequence $ServiceFilters = "(name = 'smtpsvc')","(name = 'resvc')","(name = 'msexchangemta')" $Locator = new-object -com "WbemScripting.SWbemLocator" $WMI = $Locator.ConnectServer($Server, "root\cimv2") # Stop Service and check for timeout or sucessful stop $ServiceFilters | %{ $ThisFilter = $_ (Get-WmiObject -Class Win32_Service -ComputerName $Server -filter "$ThisFilter AND state='running'") | %{ $Service = $_ $Refresher = new-object -comobject "WbemScripting.SWbemRefresher" $FreshObject = $Refresher.Add($WMI,$Service.__RELPATH) $Refresher.Refresh() $Then = Get-Date :Checking Do { $Service.StopService() | out-null $Refresher.Refresh() if (($FreshObject.Object.properties_ | ?{$_.name -eq "state"}).value -eq "Stopped") { $ServiceStopState = "Service $($Service.Name) stopped"; # Store result string in a variable $result = "$Server,$SuppressStateChanges,$ServiceStopState,$ServiceStartState" # Write results to file $result | Out-File .\results.csv -Encoding ASCII -Append $ServiceStopState = $null break :Checking; } Else { If (((Get-Date) - $Then).seconds -ge $TimeOut){ $ServiceStopState = "Service $($Service.Name) stop TIMEOUT"; # Store result string in a variable $result = "$Server,$SuppressStateChanges,$ServiceStopState,$ServiceStartState" # Write results to file $result | Out-File .\results.csv -Encoding ASCII -Append $ServiceStopState = $null break :Checking; } } } While ($True) } } # Start Service and check for timeout or sucessful start $ServiceFilters | %{ $ThisFilter = $_ (Get-WmiObject -Class Win32_Service -ComputerName $Server -filter "$ThisFilter AND state='Stopped'") | %{ $Service = $_ $Refresher = new-object -comobject "WbemScripting.SWbemRefresher" $FreshObject = $Refresher.Add($WMI,$Service.__RELPATH) $Refresher.Refresh() $Then = Get-Date :Checking Do { $Service.StartService() | out-null $Refresher.Refresh() if (($FreshObject.Object.properties_ | ?{$_.name -eq "state"}).value -eq "running") { $ServiceStartState = "Service $($Service.Name) started"; # Store result string in a variable $result = "$Server,$SuppressStateChanges,$ServiceStopState,$ServiceStartState" # Write results to file $result | Out-File .\results.csv -Encoding ASCII -Append $ServiceStartState = $null break :Checking; } Else { If (((Get-Date) - $Then).seconds -ge $TimeOut){ $ServiceStartState = "Service $($Service.Name) start TIMEOUT"; # Store result string in a variable $result = "$Server,$SuppressStateChanges,$ServiceStopState,$ServiceStartState" # Write results to file $result | Out-File .\results.csv -Encoding ASCII -Append $ServiceStartState = $null break :Checking; } } } While ($True) } } } } } #Add Exchange 2010 snapin if not loaded # Uncomment following four (4) lines if using dynamic list mentioned below If ((Get-PSSnapin | where {$_.Name -match "E2010"}) -eq $null) { Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 } # Uncomment next line if you want to dynamically get Exchange 2003 servers using Exchange 2010 Management Shell $Servers = (get-exchangeserver | Where-Object {$_.AdminDisplayVersion -like '*6.5*'} | ForEach-Object {$_.Name}) # Comment line above and Uncomment next line if you want to provide list of servers in a text file (one server per line) # You can't have both of the abovementioned lines uncommented. Please use one of your choice. # $Servers = Get-Content .\servers.txt $Servers | Suppress-Linkstate |
Few important pointers:
- The script can use one of the two methods, please comment and uncomment necessary lines as documented in script
– Dynamically retrieve list of Exchange 2003 servers in your environment using Get-ExchangeServer cmdlet from an Exchange 2010 server
– Use list of Exchange 2003 servers provided in servers.txt file (one server per line)
- If you choose to use dynamic method, you must have Exchange server 2010 admin tools installed on the machine where the script is run from
- The output will be store in results.csv file
- Timeout value in line 62 works fine in my lab tests, it may not work for you. Please adjust the value as necessary
You can download the script from here: Suppress-Linkstate.ps1
I am sure there are ways to optimize and improve this script. I would love to know how I can make the script better and more useful. Please feel free to drop me a line using contact form. I will be happy to hear your feedback and improve script. You can also use comments option on this post to leave your feedback.