diff --git a/doc/samples/SqlDataSourceEnumeratorExample.cs b/doc/samples/SqlDataSourceEnumeratorExample.cs
new file mode 100644
index 0000000000..279881c672
--- /dev/null
+++ b/doc/samples/SqlDataSourceEnumeratorExample.cs
@@ -0,0 +1,33 @@
+using System;
+//<Snippet1>
+using Microsoft.Data.Sql;  
+  
+class Program  
+{  
+  static void Main()  
+  {  
+    // Retrieve the enumerator instance and then the data.  
+    SqlDataSourceEnumerator instance =  
+      SqlDataSourceEnumerator.Instance;  
+    System.Data.DataTable table = instance.GetDataSources();  
+  
+    // Display the contents of the table.  
+    DisplayData(table);  
+  
+    Console.WriteLine("Press any key to continue.");  
+    Console.ReadKey();  
+  }  
+  
+  private static void DisplayData(System.Data.DataTable table)  
+  {  
+    foreach (System.Data.DataRow row in table.Rows)  
+    {  
+      foreach (System.Data.DataColumn col in table.Columns)  
+      {  
+        Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);  
+      }  
+      Console.WriteLine("============================");  
+    }  
+  }  
+} 
+//</Snippet1>
diff --git a/doc/samples/SqlDataSourceEnumeratorVersionExample.cs b/doc/samples/SqlDataSourceEnumeratorVersionExample.cs
new file mode 100644
index 0000000000..73eefc1235
--- /dev/null
+++ b/doc/samples/SqlDataSourceEnumeratorVersionExample.cs
@@ -0,0 +1,25 @@
+using System;
+//<Snippet1>
+using Microsoft.Data.Sql;  
+  
+class Program  
+{  
+  static void Main()  
+  {  
+    // Retrieve the enumerator instance, and  
+    // then retrieve the data sources.  
+    SqlDataSourceEnumerator instance =  
+      SqlDataSourceEnumerator.Instance;  
+    System.Data.DataTable table = instance.GetDataSources();  
+  
+    // Filter the sources to just show SQL Server 2012 instances.  
+    System.Data.DataRow[] rows = table.Select("Version LIKE '11%'");  
+    foreach (System.Data.DataRow row in rows)  
+    {  
+      Console.WriteLine(row["ServerName"]);  
+    }  
+    Console.WriteLine("Press any key to continue.");  
+    Console.ReadKey();  
+  }  
+} 
+//</Snippet1>
diff --git a/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml b/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml
new file mode 100644
index 0000000000..55e1f2c057
--- /dev/null
+++ b/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<docs>
+    <members name="SqlDataSourceEnumerator">
+    <SqlDataSourceEnumerator>
+    <summary>Provides a mechanism for enumerating all available instances of SQL Server within the local network.</summary>
+    <remarks>
+      <format type="text/markdown"><![CDATA[  
+  
+## Remarks  
+SQL Server makes it possible for applications to determine the existence of its instances within the current network. The <xref:Microsoft.Data.Sql.SqlDataSourceEnumerator> class exposes this information to the application developer, providing a <xref:System.Data.DataTable> containing information about all the available servers. This returned table contains a list of server instances that matches the list provided when a user attempts to create a new connection, and on the `Connection Properties` dialog box, expands the drop-down list containing all the available servers.  
+
+ ]]></format>
+    </remarks>
+    <related type="Article" href="/dotnet/framework/data/adonet/sql/enumerating-instances-of-sql-server">Enumerating Instances of SQL Server</related>
+  </SqlDataSourceEnumerator>
+   <GetDataSources>
+        <summary>Retrieves a <see cref="T:System.Data.DataTable" /> containing information about all visible SQL Server instances.</summary>
+        <returns>A <see cref="T:System.Data.DataTable" /> containing information about the visible SQL Server instances.</returns>
+        <remarks>
+          <format type="text/markdown"><![CDATA[  
+  
+## Remarks  
+The table returned by this method contains the following columns, all of which contain strings:  
+
+|Column|Description|  
+|------------|-----------------|  
+|**ServerName**|Name of the server.|  
+|**InstanceName**|Name of the server instance. Blank if the server is running as the default instance.|  
+|**IsClustered**|Indicates whether the server is part of a cluster.|  
+|**Version**|Version of the server:<br /><br />10.0.xx for SQL Server 2008<br />10.50.x for SQL Server 2008 R2<br />11.0.xx for SQL Server 2012<br />12.0.xx for SQL Server 2014<br />13.0.xx for SQL Server 2016<br />14.0.xx for SQL Server 2017|  
+  
+> [!NOTE]
+> Due to the nature of the mechanism used by <xref:Microsoft.Data.Sql.SqlDataSourceEnumerator> to locate data sources on a network, the method will not always return a complete list of the available servers, and the list might not be the same on every call. If you plan to use this function to let users select a server from a list, make sure that you always also supply an option to type in a name that is not in the list, in case the server enumeration does not return all the available servers. In addition, this method may take a significant amount of time to execute, so be careful about calling it when performance is critical.  
+
+## Examples  
+ The following console application retrieves information about all the visible SQL Server instances and displays the information in the console window.  
+  
+[!code-csharp[SqlDataSourceEnumerator.Example#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorExample.cs#1)]
+  
+ ]]></format>
+        </remarks>
+        <related type="Article" href="/dotnet/framework/data/adonet/sql/enumerating-instances-of-sql-server">Enumerating Instances of SQL Server</related>
+      </GetDataSources>
+    <Instance>
+        <summary>Gets an instance of the <see cref="T:Microsoft.Data.Sql.SqlDataSourceEnumerator"/>, which can be used to retrieve information about available SQL Server instances.</summary>
+        <value>An instance of the <see cref="T:Microsoft.Data.Sql.SqlDataSourceEnumerator"/> used to retrieve information about available SQL Server instances.</value>
+        <remarks>
+          <format type="text/markdown"><![CDATA[  
+  
+## Remarks  
+The <xref:Microsoft.Data.Sql.SqlDataSourceEnumerator> class does not provide a constructor. Use the <xref:Microsoft.Data.Sql.SqlDataSourceEnumerator.Instance%2A> property to retrieve an instance of the class instead.  
+
+[!code-csharp[SqlDataSourceEnumeratorExample#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorExample.cs#1)]
+
+## Examples  
+The following console application displays a list of all the available SQL Server 2005 instances within the local network. This code uses the <xref:System.Data.DataTable.Select%2A> method to filter the rows in the table returned by the <xref:Microsoft.Data.Sql.SqlDataSourceEnumerator.GetDataSources%2A> method.  
+ [!code-csharp[SqlDataSourceEnumeratorVersionExample#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorVersionExample.cs#1)]
+
+ ]]></format>
+        </remarks>
+        <related type="Article" href="/dotnet/framework/data/adonet/sql/enumerating-instances-of-sql-server">Enumerating Instances of SQL Server</related>
+    
+    </Instance>
+    </members>
+</docs>
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
index 3d63a3f9db..12e8094ff0 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
@@ -29,6 +29,15 @@ public SqlNotificationRequest(string userData, string options, int timeout) { }
         /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlNotificationRequest.xml' path='docs/members[@name="SqlNotificationRequest"]/UserData/*' />
         public string UserData { get { throw null; } set { } }
     }
+
+    /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/SqlDataSourceEnumerator/*' />
+    public sealed class SqlDataSourceEnumerator : System.Data.Common.DbDataSourceEnumerator
+    {
+        /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/Instance/*' />  
+        public static SqlDataSourceEnumerator Instance { get; }
+        /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/GetDataSources/*' />      
+        public override System.Data.DataTable GetDataSources() { throw null; }
+    }
 }
 namespace Microsoft.Data.SqlTypes
 {
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs
index ed33b6897a..0b09ea3341 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs
@@ -3,11 +3,15 @@
 // See the LICENSE file in the project root for more information.
 
 using Microsoft.Data.SqlClient.SNI;
+using System;
+using System.Runtime.InteropServices;
 
 namespace Microsoft.Data.SqlClient
 {
     internal static partial class SNINativeMethodWrapper
     {
+        private const string SNI = "Microsoft.Data.SqlClient.SNI.dll";
+
         internal enum SniSpecialErrors : uint
         {
             LocalDBErrorCode = SNICommon.LocalDBErrorCode,
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs
index 7f1b3e17ea..4e84fdc406 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs
@@ -12,8 +12,6 @@ namespace Microsoft.Data.SqlClient
 {
     internal static partial class SNINativeMethodWrapper
     {
-        private const string SNI = "Microsoft.Data.SqlClient.SNI.dll";
-
         private static int s_sniMaxComposedSpnLength = -1;
 
         private const int SniOpenTimeOut = -1; // infinite
@@ -200,6 +198,7 @@ internal struct SNI_Error
         #endregion
 
         #region DLL Imports
+
         [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")]
         internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo);
 
@@ -306,7 +305,19 @@ private static extern unsafe uint SNISecGenClientContextWrapper(
 
         [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)]
         private static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket);
-	    #endregion
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")]
+        internal static extern IntPtr SNIServerEnumOpen();
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")]
+        internal static extern void SNIServerEnumClose([In] IntPtr packet);
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)]
+        internal static extern int SNIServerEnumRead([In] IntPtr packet,
+                                                     [In][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer,
+                                                     [In] int bufferLength,
+                                                     [MarshalAs(UnmanagedType.Bool)] out bool more);
+        #endregion
 
         internal static uint SniGetConnectionId(SNIHandle pConn, ref Guid connId)
         {
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index e1483a26a8..ec72b3a856 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -45,6 +45,15 @@
     </Compile>
     <Compile Include="..\..\src\Microsoft\Data\Common\ActivityCorrelator.cs">
       <Link>Microsoft\Data\Common\ActivityCorrelator.cs</Link>
+    </Compile>
+     <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumerator.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumerator.cs</Link>
+    </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs</Link>
     </Compile>
     <Compile Include="..\..\src\Microsoft\Data\Common\DbConnectionStringCommon.cs">
       <Link>Microsoft\Data\Common\DbConnectionStringCommon.cs</Link>
@@ -633,6 +642,12 @@
   </ItemGroup>
   <!-- Windows only -->
   <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs</Link>
+    </Compile>
     <Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionCertificateStoreProvider.Windows.cs" />
     <Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionCngProvider.Windows.cs" />
     <Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionCspProvider.Windows.cs" />
@@ -861,6 +876,7 @@
     </Compile>
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsWindows)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
+    <Compile Include="Microsoft\Data\Sql\SqlDataSourceEnumerator.Unix.cs" />
     <Compile Include="Microsoft\Data\ProviderBase\DbConnectionPoolIdentity.Unix.cs" />
     <Compile Include="Interop\SNINativeMethodWrapper.Unix.cs" />
     <Compile Include="$(CommonPath)\System\Net\Security\NegotiateStreamPal.Unix.cs">
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs
new file mode 100644
index 0000000000..6ee3fe3329
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System.Data;
+using System.Data.Common;
+using Microsoft.Data.SqlClient.Server;
+
+namespace Microsoft.Data.Sql
+{
+    /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/SqlDataSourceEnumerator/*' />
+    public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator
+    {
+        private partial DataTable GetDataSourcesInternal() => SqlDataSourceEnumeratorManagedHelper.GetDataSources();
+    }
+}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs
index 0147b29f17..d182a8d31f 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs
@@ -11,10 +11,16 @@
 
 namespace Microsoft.Data.SqlClient.SNI
 {
-    internal class SSRP
+    internal sealed class SSRP
     {
         private const char SemicolonSeparator = ';';
-        private const int SqlServerBrowserPort = 1434;
+        private const int SqlServerBrowserPort = 1434; //port SQL Server Browser
+        private const int RecieveMAXTimeoutsForCLNT_BCAST_EX = 15000; //Default max time for response wait
+        private const int RecieveTimeoutsForCLNT_BCAST_EX = 1000; //subsequent wait time for response after intial wait 
+        private const int ServerResponseHeaderSizeForCLNT_BCAST_EX = 3;//(SVR_RESP + RESP_SIZE) https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/2e1560c9-5097-4023-9f5e-72b9ff1ec3b1
+        private const int ValidResponseSizeForCLNT_BCAST_EX = 4096; //valid reponse size should be less than 4096
+        private const int FirstTimeoutForCLNT_BCAST_EX = 5000;//wait for first response for 5 seconds
+        private const int CLNT_BCAST_EX = 2;//request packet
 
         /// <summary>
         /// Finds instance port number for given instance name.
@@ -149,8 +155,7 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re
                 const int sendTimeOutMs = 1000;
                 const int receiveTimeOutMs = 1000;
 
-                IPAddress address = null;
-                bool isIpAddress = IPAddress.TryParse(browserHostname, out address);
+                bool isIpAddress = IPAddress.TryParse(browserHostname, out IPAddress address);
 
                 byte[] responsePacket = null;
                 using (UdpClient client = new UdpClient(!isIpAddress ? AddressFamily.InterNetwork : address.AddressFamily))
@@ -165,9 +170,52 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re
                         responsePacket = receiveTask.Result.Buffer;
                     }
                 }
-
                 return responsePacket;
             }
         }
+
+        /// <summary>
+        /// Sends request to server, and recieves response from server (SQLBrowser) on port 1434 by UDP
+        /// Request (https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/a3035afa-c268-4699-b8fd-4f351e5c8e9e)
+        /// Response (https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/2e1560c9-5097-4023-9f5e-72b9ff1ec3b1) 
+        /// </summary>
+        /// <returns>string constaning list of SVR_RESP(just RESP_DATA)</returns>
+        internal static string SendBroadcastUDPRequest()
+        {
+            StringBuilder response = new StringBuilder();
+            byte[] CLNT_BCAST_EX_Request = new byte[1] { CLNT_BCAST_EX }; //0x02
+            // Waits 5 seconds for the first response and every 1 second up to 15 seconds
+            // https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/f2640a2d-3beb-464b-a443-f635842ebc3e#Appendix_A_3
+            int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; 
+
+            using (TrySNIEventScope.Create(nameof(SSRP)))
+            {
+                using (UdpClient clientListener = new UdpClient())
+                {
+                    Task<int> sendTask = clientListener.SendAsync(CLNT_BCAST_EX_Request, CLNT_BCAST_EX_Request.Length, new IPEndPoint(IPAddress.Broadcast, SqlServerBrowserPort));
+                    Task<UdpReceiveResult> receiveTask = null;
+                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Waiting for UDP Client to fetch list of instances.");
+                    Stopwatch sw = new Stopwatch(); //for waiting until 15 sec elapsed
+                    sw.Start();
+                    try
+                    { 
+                        while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && sw.ElapsedMilliseconds <= RecieveMAXTimeoutsForCLNT_BCAST_EX && receiveTask != null)
+                        {
+                            currentTimeOut = RecieveTimeoutsForCLNT_BCAST_EX;
+                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client.");
+                            if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response
+                            {
+                                response.Append(Encoding.UTF7.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); //RESP_DATA(VARIABLE) - 3 (RESP_SIZE + SVR_RESP)
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        sw.Stop();
+                    }
+                }
+            }
+            return response.ToString();
+        }
     }
 }
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs
index e17a65be95..6f67764f9a 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs
@@ -180,5 +180,6 @@ internal static int GetRemainingTimeout(int timeout, long start)
                 return checked((int)remaining);
             }
         }
+        internal static long GetTimeoutSeconds(int timeout) => GetTimeout((long)timeout * 1000L);
     }
 }
diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs
index 6a6ae668e7..d5ac6b0611 100644
--- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs
@@ -34,6 +34,15 @@ public SqlNotificationRequest(string userData, string options, int timeout) { }
         /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlNotificationRequest.xml' path='docs/members[@name="SqlNotificationRequest"]/UserData/*' />
         public string UserData { get { throw null; } set { } }
     }
+
+    /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/SqlDataSourceEnumerator/*' />
+    public sealed class SqlDataSourceEnumerator : System.Data.Common.DbDataSourceEnumerator
+    {
+        /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/Instance/*' />  
+        public static SqlDataSourceEnumerator Instance {get;}
+        /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/GetDataSources/*' />      
+        public override System.Data.DataTable GetDataSources(){ throw null; }
+    }
 }
 
 namespace Microsoft.Data.SqlClient
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
index a4ecd51c67..fe4e7b13da 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -119,6 +119,18 @@
     <Compile Include="..\..\src\Microsoft\Data\Sql\SqlNotificationRequest.cs">
       <Link>Microsoft\Data\Sql\SqlNotificationRequest.cs</Link>
     </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumerator.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumerator.cs</Link>
+    </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs</Link>
+    </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\..\src\Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs">
+      <Link>Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs</Link>
+    </Compile>
     <Compile Include="..\..\src\Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs">
       <Link>Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs</Link>
     </Compile>
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs
index abbfda7ede..13e35363a8 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs
@@ -134,5 +134,17 @@ internal static extern unsafe uint SNISecGenClientContextWrapper(
 
         [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)]
         internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext);
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")]
+        internal static extern IntPtr SNIServerEnumOpen();
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")]
+        internal static extern void SNIServerEnumClose([In] IntPtr packet);
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)]
+        internal static extern int SNIServerEnumRead([In] IntPtr packet,
+                                                     [In, Out][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer,
+                                                     [In] int bufferLength,
+                                                     [MarshalAs(UnmanagedType.Bool)] out bool more);
     }
 }
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs
index b700e4b108..5517ba8c0e 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs
@@ -134,5 +134,17 @@ internal static extern unsafe uint SNISecGenClientContextWrapper(
 
         [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)]
         internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext);
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")]
+        internal static extern IntPtr SNIServerEnumOpen();
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")]
+        internal static extern void SNIServerEnumClose([In] IntPtr packet);
+
+        [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)]
+        internal static extern int SNIServerEnumRead([In] IntPtr packet,
+                                                     [In, Out][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer,
+                                                     [In] int bufferLength,
+                                                     [MarshalAs(UnmanagedType.Bool)] out bool more);
     }
 }
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs
index d1fb0ad3e5..39ba5c5259 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs
@@ -760,6 +760,26 @@ internal static uint SNIInitialize()
             return SNIInitialize(LocalAppContextSwitches.UseSystemDefaultSecureProtocols, IntPtr.Zero);
         }
 
+        internal static IntPtr SNIServerEnumOpen() => s_is64bitProcess ?
+                SNINativeManagedWrapperX64.SNIServerEnumOpen() :
+                SNINativeManagedWrapperX86.SNIServerEnumOpen();
+
+        internal static int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readbuffer, int bufferLength, out bool more) => s_is64bitProcess ?
+              SNINativeManagedWrapperX64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more) :
+              SNINativeManagedWrapperX86.SNIServerEnumRead(packet, readbuffer, bufferLength, out more);
+
+        internal static void SNIServerEnumClose([In] IntPtr packet)
+        {
+            if (s_is64bitProcess)
+            {
+                SNINativeManagedWrapperX64.SNIServerEnumClose(packet);
+            }
+            else
+            {
+                SNINativeManagedWrapperX86.SNIServerEnumClose(packet);
+            }
+        }
+
         internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo)
         {
             // initialize consumer info for MARS
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs
index 025ea7d020..7be7f61bb4 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs
@@ -221,6 +221,8 @@ internal static long GetTimeout(long timeoutMilliseconds)
             return result;
         }
 
+        internal static long GetTimeoutSeconds(int timeout) => GetTimeout((long)timeout * 1000L);
+
         internal static bool TimeoutHasExpired(long timeoutTime)
         {
             bool result = false;
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs
index 7d86c2d7ff..8db89b51b7 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs
@@ -1227,6 +1227,8 @@ static internal Exception InvalidMixedUsageOfCredentialAndAccessToken()
             => InvalidOperation(StringsHelper.GetString(Strings.ADP_InvalidMixedUsageOfCredentialAndAccessToken));
 #endregion
 
+        internal static bool IsEmpty(string str) => string.IsNullOrEmpty(str);
+        internal static readonly IntPtr s_ptrZero = IntPtr.Zero;
 #if NETFRAMEWORK
 #region netfx project only
         internal static Task<T> CreatedTaskWithException<T>(Exception ex)
@@ -1381,7 +1383,6 @@ internal static InvalidOperationException ComputerNameEx(int lastError)
         internal const float FailoverTimeoutStepForTnir = 0.125F; // Fraction of timeout to use in case of Transparent Network IP resolution.
         internal const int MinimumTimeoutForTnirMs = 500; // The first login attempt in  Transparent network IP Resolution 
 
-        internal static readonly IntPtr s_ptrZero = IntPtr.Zero; // IntPtr.Zero
         internal static readonly int s_ptrSize = IntPtr.Size;
         internal static readonly IntPtr s_invalidPtr = new(-1); // use for INVALID_HANDLE
 
@@ -1472,7 +1473,6 @@ internal static IntPtr IntPtrOffset(IntPtr pbase, int offset)
             return (IntPtr)checked(pbase.ToInt64() + offset);
         }
 
-        internal static bool IsEmpty(string str) => string.IsNullOrEmpty(str);
 #endregion
 #else
 #region netcore project only
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs
new file mode 100644
index 0000000000..83ce5085e7
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System.Data;
+using System.Data.Common;
+using Microsoft.Data.SqlClient.Server;
+
+namespace Microsoft.Data.Sql
+{
+    /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/SqlDataSourceEnumerator/*' />
+    public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator
+    {
+        private partial DataTable GetDataSourcesInternal()
+        {
+#if NETFRAMEWORK
+            return SqlDataSourceEnumeratorNativeHelper.GetDataSources();
+#else
+            return SqlClient.TdsParserStateObjectFactory.UseManagedSNI ? SqlDataSourceEnumeratorManagedHelper.GetDataSources() : SqlDataSourceEnumeratorNativeHelper.GetDataSources();
+#endif
+        }
+    }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs
new file mode 100644
index 0000000000..e8f7aac29c
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System;
+using System.Data;
+using System.Data.Common;
+
+namespace Microsoft.Data.Sql
+{
+    /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/SqlDataSourceEnumerator/*' />
+    public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator
+    {
+        private static readonly Lazy<SqlDataSourceEnumerator> s_singletonInstance = new(() => new SqlDataSourceEnumerator());
+
+        private SqlDataSourceEnumerator() : base(){}
+
+        /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/Instance/*' />  
+        public static SqlDataSourceEnumerator Instance => s_singletonInstance.Value;
+
+        /// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml' path='docs/members[@name="SqlDataSourceEnumerator"]/GetDataSources/*' />      
+        override public DataTable GetDataSources() => GetDataSourcesInternal();
+
+        private partial DataTable GetDataSourcesInternal();
+    }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs
new file mode 100644
index 0000000000..43be666e0d
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Data;
+using Microsoft.Data.Sql;
+
+namespace Microsoft.Data.SqlClient.Server
+{
+    /// <summary>
+    /// Provides a mechanism for enumerating all available instances of SQL Server within the local network
+    /// </summary>
+    internal static class SqlDataSourceEnumeratorManagedHelper
+    {
+        /// <summary>
+        /// Provides a mechanism for enumerating all available instances of SQL Server within the local network.
+        /// </summary>
+        /// <returns>DataTable with ServerName,InstanceName,IsClustered and Version</returns>
+        internal static DataTable GetDataSources()
+        {
+            // TODO: Implement multicast request besides the implemented broadcast request.
+            throw new System.NotImplementedException(StringsHelper.net_MethodNotImplementedException);
+        }
+
+        private static DataTable ParseServerEnumString(string serverInstances)
+        {
+            DataTable dataTable = SqlDataSourceEnumeratorUtil.PrepareDataTable();
+            DataRow dataRow;
+
+            if (serverInstances.Length == 0)
+            {
+                return dataTable;
+            }
+
+            string[] numOfServerInstances = serverInstances.Split(SqlDataSourceEnumeratorUtil.s_endOfServerInstanceDelimiter_Managed, System.StringSplitOptions.None);
+            SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO> Number of recieved server instances are {2}",
+                                                   nameof(SqlDataSourceEnumeratorManagedHelper), nameof(ParseServerEnumString), numOfServerInstances.Length);
+
+            foreach (string currentServerInstance in numOfServerInstances)
+            {
+                Dictionary<string, string> InstanceDetails = new();
+                string[] delimitedKeyValues = currentServerInstance.Split(SqlDataSourceEnumeratorUtil.InstanceKeysDelimiter);
+                string currentKey = string.Empty;
+
+                for (int keyvalue = 0; keyvalue < delimitedKeyValues.Length; keyvalue++)
+                {
+                    if (keyvalue % 2 == 0)
+                    {
+                        currentKey = delimitedKeyValues[keyvalue];
+                    }
+                    else if (currentKey != string.Empty)
+                    {
+                        InstanceDetails.Add(currentKey, delimitedKeyValues[keyvalue]);
+                    }
+                }
+
+                if (InstanceDetails.Count > 0)
+                {
+                    dataRow = dataTable.NewRow();
+                    dataRow[0] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.ServerNameCol) == true ?
+                                 InstanceDetails[SqlDataSourceEnumeratorUtil.ServerNameCol] : string.Empty;
+                    dataRow[1] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.InstanceNameCol) == true ?
+                                 InstanceDetails[SqlDataSourceEnumeratorUtil.InstanceNameCol] : string.Empty;
+                    dataRow[2] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.IsClusteredCol) == true ?
+                                 InstanceDetails[SqlDataSourceEnumeratorUtil.IsClusteredCol] : string.Empty;
+                    dataRow[3] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.VersionNameCol) == true ?
+                                 InstanceDetails[SqlDataSourceEnumeratorUtil.VersionNameCol] : string.Empty;
+
+                    dataTable.Rows.Add(dataRow);
+                }
+            }
+            return dataTable.SetColumnsReadOnly();
+        }
+    }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs
new file mode 100644
index 0000000000..db40a6439e
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs
@@ -0,0 +1,179 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Data;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Security;
+using System.Text;
+using Microsoft.Data.Common;
+using Microsoft.Data.SqlClient;
+using static Microsoft.Data.Sql.SqlDataSourceEnumeratorUtil;
+
+namespace Microsoft.Data.Sql
+{
+    /// <summary>
+    /// Provides a mechanism for enumerating all available instances of SQL Server within the local network
+    /// </summary>
+    internal static class SqlDataSourceEnumeratorNativeHelper
+    {
+        /// <summary>
+        /// Retrieves a DataTable containing information about all visible SQL Server instances
+        /// </summary>
+        /// <returns></returns>
+        internal static DataTable GetDataSources()
+        {
+            (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304
+            char[] buffer = null;
+            StringBuilder strbldr = new();
+
+            int bufferSize = 1024;
+            int readLength = 0;
+            buffer = new char[bufferSize];
+            bool more = true;
+            bool failure = false;
+            IntPtr handle = ADP.s_ptrZero;
+
+            RuntimeHelpers.PrepareConstrainedRegions();
+            try
+            {
+                long s_timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(ADP.DefaultCommandTimeout);
+                RuntimeHelpers.PrepareConstrainedRegions();
+                try
+                { }
+                finally
+                {
+                    handle = SNINativeMethodWrapper.SNIServerEnumOpen();
+                    SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO> {3} returned handle = {4}.",
+                                                           nameof(SqlDataSourceEnumeratorNativeHelper),
+                                                           nameof(GetDataSources),
+                                                           nameof(SNINativeMethodWrapper.SNIServerEnumOpen), handle);
+                }
+
+                if (handle != ADP.s_ptrZero)
+                {
+                    while (more && !TdsParserStaticMethods.TimeoutHasExpired(s_timeoutTime))
+                    {
+                        readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more);
+
+                        SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO> {2} returned 'readlength':{3}, and 'more':{4} with 'bufferSize' of {5}",
+                                                               nameof(SqlDataSourceEnumeratorNativeHelper),
+                                                               nameof(GetDataSources),
+                                                               nameof(SNINativeMethodWrapper.SNIServerEnumRead),
+                                                               readLength, more, bufferSize);
+                        if (readLength > bufferSize)
+                        {
+                            failure = true;
+                            more = false;
+                        }
+                        else if (readLength > 0)
+                        {
+                            strbldr.Append(buffer, 0, readLength);
+                        }
+                    }
+                }
+            }
+            finally
+            {
+                if (handle != ADP.s_ptrZero)
+                {
+                    SNINativeMethodWrapper.SNIServerEnumClose(handle);
+                    SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO> {3} called.",
+                                                           nameof(SqlDataSourceEnumeratorNativeHelper),
+                                                           nameof(GetDataSources),
+                                                           nameof(SNINativeMethodWrapper.SNIServerEnumClose));
+                }
+            }
+
+            if (failure)
+            {
+                Debug.Assert(false, $"{nameof(GetDataSources)}:{nameof(SNINativeMethodWrapper.SNIServerEnumRead)} returned bad length");
+                SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|ERR> {2} returned bad length, requested buffer {3}, received {4}",
+                                                       nameof(SqlDataSourceEnumeratorNativeHelper),
+                                                       nameof(GetDataSources),
+                                                       nameof(SNINativeMethodWrapper.SNIServerEnumRead),
+                                                       bufferSize, readLength);
+
+                throw ADP.ArgumentOutOfRange(StringsHelper.GetString(Strings.ADP_ParameterValueOutOfRange, readLength), nameof(readLength));
+            }
+            return ParseServerEnumString(strbldr.ToString());
+        }
+
+        private static DataTable ParseServerEnumString(string serverInstances)
+        {
+            DataTable dataTable = PrepareDataTable();
+            string serverName = null;
+            string instanceName = null;
+            string isClustered = null;
+            string version = null;
+            string[] serverinstanceslist = serverInstances.Split(EndOfServerInstanceDelimiter_Native);
+            SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.{1}|INFO> Number of recieved server instances are {2}",
+                                                   nameof(SqlDataSourceEnumeratorNativeHelper), nameof(ParseServerEnumString), serverinstanceslist.Length);
+
+            // Every row comes in the format "serverName\instanceName;Clustered:[Yes|No];Version:.." 
+            // Every row is terminated by a null character.
+            // Process one row at a time
+            foreach (string instance in serverinstanceslist)
+            {
+                string value = instance.Trim(EndOfServerInstanceDelimiter_Native); // MDAC 91934
+                if (value.Length == 0)
+                {
+                    continue;
+                }
+                foreach (string instance2 in value.Split(InstanceKeysDelimiter))
+                {
+                    if (serverName == null)
+                    {
+                        foreach (string instance3 in instance2.Split(ServerNamesAndInstanceDelimiter))
+                        {
+                            if (serverName == null)
+                            {
+                                serverName = instance3;
+                                continue;
+                            }
+                            Debug.Assert(instanceName == null, $"{nameof(instanceName)}({instanceName}) is not null.");
+                            instanceName = instance3;
+                        }
+                        continue;
+                    }
+                    if (isClustered == null)
+                    {
+                        Debug.Assert(string.Compare(Clustered, 0, instance2, 0, s_clusteredLength, StringComparison.OrdinalIgnoreCase) == 0,
+                                     $"{nameof(Clustered)} ({Clustered}) doesn't equal {nameof(instance2)} ({instance2})");
+                        isClustered = instance2.Substring(s_clusteredLength);
+                        continue;
+                    }
+                    Debug.Assert(version == null, $"{nameof(version)}({version}) is not null.");
+                    Debug.Assert(string.Compare(SqlDataSourceEnumeratorUtil.Version, 0, instance2, 0, s_versionLength, StringComparison.OrdinalIgnoreCase) == 0,
+                                 $"{nameof(SqlDataSourceEnumeratorUtil.Version)} ({SqlDataSourceEnumeratorUtil.Version}) doesn't equal {nameof(instance2)} ({instance2})");
+                    version = instance2.Substring(s_versionLength);
+                }
+
+                string query = "ServerName='" + serverName + "'";
+
+                if (!ADP.IsEmpty(instanceName))
+                { // SQL BU DT 20006584: only append instanceName if present.
+                    query += " AND InstanceName='" + instanceName + "'";
+                }
+
+                // SNI returns dupes - do not add them.  SQL BU DT 290323
+                if (dataTable.Select(query).Length == 0)
+                {
+                    DataRow dataRow = dataTable.NewRow();
+                    dataRow[0] = serverName;
+                    dataRow[1] = instanceName;
+                    dataRow[2] = isClustered;
+                    dataRow[3] = version;
+                    dataTable.Rows.Add(dataRow);
+                }
+                serverName = null;
+                instanceName = null;
+                isClustered = null;
+                version = null;
+            }
+            return dataTable.SetColumnsReadOnly();
+        }
+    }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs
new file mode 100644
index 0000000000..fb6972d8cf
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Data;
+using System.Globalization;
+
+namespace Microsoft.Data.Sql
+{
+    /// <summary>
+    /// const values for SqlDataSourceEnumerator
+    /// </summary>
+    internal static class SqlDataSourceEnumeratorUtil
+    {
+        internal const string ServerNameCol = "ServerName";
+        internal const string InstanceNameCol = "InstanceName";
+        internal const string IsClusteredCol = "IsClustered";
+        internal const string VersionNameCol = "Version";
+
+        internal const string Version = "Version:";
+        internal const string Clustered = "Clustered:";
+        internal static readonly int s_versionLength = Version.Length;
+        internal static readonly int s_clusteredLength = Clustered.Length;
+
+        internal static readonly string[] s_endOfServerInstanceDelimiter_Managed = new[] { ";;" };
+        internal const char EndOfServerInstanceDelimiter_Native = '\0';
+        internal const char InstanceKeysDelimiter = ';';
+        internal const char ServerNamesAndInstanceDelimiter = '\\';
+
+        internal static DataTable PrepareDataTable()
+        {
+            DataTable dataTable = new("SqlDataSources");
+            dataTable.Locale = CultureInfo.InvariantCulture;
+            dataTable.Columns.Add(ServerNameCol, typeof(string));
+            dataTable.Columns.Add(InstanceNameCol, typeof(string));
+            dataTable.Columns.Add(IsClusteredCol, typeof(string));
+            dataTable.Columns.Add(VersionNameCol, typeof(string));
+
+            return dataTable;
+        }
+
+        /// <summary>
+        /// Sets all columns read-only.
+        /// </summary>
+        internal static DataTable SetColumnsReadOnly(this DataTable dataTable)
+        {
+            foreach (DataColumn column in dataTable.Columns)
+            {
+                column.ReadOnly = true;
+            }
+            return dataTable;
+        }
+    }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
index ab9ad736bf..44ff1f1ce7 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
@@ -29,7 +29,7 @@
       <Link>TCECryptoNativeBaselineRsa.txt</Link>
     </Content>
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND !$(ReferenceType.Contains('NetStandard')) AND ('$(TestSet)' == '' OR '$(TestSet)' == 'AE')" >
+  <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND !$(ReferenceType.Contains('NetStandard')) AND ('$(TestSet)' == '' OR '$(TestSet)' == 'AE')">
     <Compile Include="AlwaysEncrypted\CspProviderExt.cs" />
     <Compile Include="AlwaysEncrypted\TestFixtures\Setup\CertificateUtilityWin.cs" />
     <Compile Include="AlwaysEncrypted\TestFixtures\Setup\CspProviderColumnMasterKey.cs" />
@@ -159,6 +159,9 @@
     <Compile Include="SQL\SqlBulkCopyTest\DataConversionErrorMessageTest.cs" />
     <Compile Include="SQL\SqlBulkCopyTest\CopyWidenNullInexactNumerics.cs" />
   </ItemGroup>
+  <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND ('$(TestSet)' == '' OR '$(TestSet)' == '2')">
+    <Compile Include="SQL\SqlDSEnumeratorTest\SqlDataSourceEnumeratorTest.cs" />
+  </ItemGroup>
   <ItemGroup Condition="'$(TestSet)' == '' OR '$(TestSet)' == '3'">
     <Compile Include="DDBasics\DDAsyncTest\DDAsyncTest.cs" />
     <Compile Include="DDBasics\DDDataTypesTest\DDDataTypesTest.cs" />
@@ -239,7 +242,7 @@
     <None Include="SQL\ParameterTest\SqlParameterTest_ReleaseMode.bsl" />
     <None Include="SQL\ParameterTest\SqlParameterTest_ReleaseMode_Azure.bsl" />
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetGroup)'=='netcoreapp' AND ('$(TestSet)' == '' OR '$(TestSet)' == '3')" >
+  <ItemGroup Condition="'$(TargetGroup)'=='netcoreapp' AND ('$(TestSet)' == '' OR '$(TestSet)' == '3')">
     <Compile Include="TracingTests\EventCounterTest.cs" />
     <Compile Include="TracingTests\DiagnosticTest.cs" />
     <Compile Include="TracingTests\FakeDiagnosticListenerObserver.cs" />
@@ -319,6 +322,7 @@
     <PackageReference Condition="'$(TargetGroup)'=='netcoreapp' AND $(OS)=='Unix'" Include="Microsoft.Windows.Compatibility" Version="$(MicrosoftWindowsCompatibilityVersion)" />
     <PackageReference Condition="'$(TargetGroup)'=='netfx'" Include="Microsoft.SqlServer.Types" Version="$(MicrosoftSqlServerTypesVersion)" />
     <PackageReference Condition="'$(TargetGroup)'=='netcoreapp'" Include="Microsoft.DotNet.RemoteExecutor" Version="$(MicrosoftDotnetRemoteExecutorVersion)" /> 
+    <PackageReference Condition="'$(TargetGroup)'!='netfx'" Include="System.ServiceProcess.ServiceController" Version="$(SystemServiceProcessServiceControllerVersion)" />
   </ItemGroup>
   <ItemGroup>
     <None Condition="'$(TargetGroup)'=='netfx' AND $(ReferenceType)=='Project'" Include="$(BinFolder)$(Configuration).AnyCPU\Microsoft.Data.SqlClient\netfx\**\*SNI*.dll" CopyToOutputDirectory="PreserveNewest" />
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs
new file mode 100644
index 0000000000..118a2412c3
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ServiceProcess;
+using Microsoft.Data.Sql;
+using Xunit;
+
+namespace Microsoft.Data.SqlClient.ManualTesting.Tests
+{
+#if NET50_OR_LATER
+        [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+#endif
+    public class SqlDataSourceEnumeratorTest
+    {
+        [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsNotUsingManagedSNIOnWindows))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public void SqlDataSourceEnumerator_NativeSNI()
+        {
+            // The returned rows depends on the running services which could be zero or more.
+            int count = GetDSEnumerator().GetDataSources().Rows.Count;
+            Assert.InRange(count, 0, 65536);
+        }
+
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+        [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsUsingManagedSNI))]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        public void SqlDataSourceEnumerator_ManagedSNI()
+        {
+            // After adding the managed SNI support, this test should have the same result as SqlDataSourceEnumerator_NativeSNI
+            Assert.Throws<NotImplementedException>(() => GetDSEnumerator().GetDataSources());
+        }
+
+        private SqlDataSourceEnumerator GetDSEnumerator()
+        {
+            // SQL Server Browser runs as a Windows service.
+            // TODO: This assessment can be done on CI.
+            ServiceController sc = new("SQLBrowser");
+            Assert.Equal(ServiceControllerStatus.Running, sc.Status);
+
+            return SqlDataSourceEnumerator.Instance;
+        }
+    }
+}
diff --git a/tools/props/Versions.props b/tools/props/Versions.props
index eb18b2115d..ac93368fa7 100644
--- a/tools/props/Versions.props
+++ b/tools/props/Versions.props
@@ -78,6 +78,7 @@
     <MicrosoftSqlServerSqlManagementObjectsVersion>161.41011.9</MicrosoftSqlServerSqlManagementObjectsVersion>
     <MicrosoftSqlServerTypesVersion>10.50.1600.1</MicrosoftSqlServerTypesVersion>
     <BenchmarkDotNetVersion>0.12.1</BenchmarkDotNetVersion>
+    <SystemServiceProcessServiceControllerVersion>6.0.0</SystemServiceProcessServiceControllerVersion>
   </PropertyGroup>
   <PropertyGroup>
     <TestAKVProviderVersion>$(NugetPackageVersion)</TestAKVProviderVersion>