diff --git a/cmd/modern/main.go b/cmd/modern/main.go
index 4b358b48..81536a32 100644
--- a/cmd/modern/main.go
+++ b/cmd/modern/main.go
@@ -131,6 +131,7 @@ func initializeCallback() {
 			TraceHandler: outputter.Tracef,
 			HintHandler:  displayHints,
 			LineBreak:    sqlcmd.SqlcmdEol,
+			LoggingLevel: verbosity.Level(rootCmd.loggingLevel),
 		})
 	config.SetFileName(rootCmd.configFilename)
 	config.Load()
diff --git a/cmd/modern/root/config/delete-context.go b/cmd/modern/root/config/delete-context.go
index 75f3df5c..898df0fb 100644
--- a/cmd/modern/root/config/delete-context.go
+++ b/cmd/modern/root/config/delete-context.go
@@ -74,6 +74,10 @@ func (c *DeleteContext) run() {
 			if config.UserExists(context) {
 				config.DeleteUser(*context.ContextDetails.User)
 			}
+
+			for _, c := range context.AddOns {
+				config.DeleteEndpoint(c.Endpoint)
+			}
 		}
 
 		config.DeleteContext(c.name)
diff --git a/cmd/modern/root/install/edge_test.go b/cmd/modern/root/install/edge_test.go
index c01d7dc0..18c04f2f 100644
--- a/cmd/modern/root/install/edge_test.go
+++ b/cmd/modern/root/install/edge_test.go
@@ -25,7 +25,7 @@ func TestInstallEdge(t *testing.T) {
 	cmdparser.TestCmd[*edge.GetTags]()
 	cmdparser.TestCmd[*Edge](
 		fmt.Sprintf(
-			`--accept-eula --user-database foo --errorlog-wait-line "Hello from Docker!" --registry %v --repo %v`,
+			`--accept-eula --database foo --errorlog-wait-line "Hello from Docker!" --registry %v --repo %v`,
 			registry,
 			repo))
 
diff --git a/cmd/modern/root/install/mssql-base.go b/cmd/modern/root/install/mssql-base.go
index 924123ae..d21e21d1 100644
--- a/cmd/modern/root/install/mssql-base.go
+++ b/cmd/modern/root/install/mssql-base.go
@@ -56,6 +56,9 @@ type MssqlBase struct {
 	port int
 
 	usingDatabaseUrl string
+	network          string
+	addOn            string
+	addOnUse         string
 
 	unitTesting bool
 
@@ -99,8 +102,8 @@ func (c *MssqlBase) AddFlags(
 
 	addFlag(cmdparser.FlagOptions{
 		String:    &c.defaultDatabase,
-		Name:      "user-database",
-		Shorthand: "u",
+		Name:      "database",
+		Shorthand: "d",
 		Usage:     localizer.Sprintf("Create a user database and set it as the default for login"),
 	})
 
@@ -215,9 +218,31 @@ func (c *MssqlBase) AddFlags(
 	addFlag(cmdparser.FlagOptions{
 		String:        &c.usingDatabaseUrl,
 		DefaultString: "",
-		Name:          "using",
+		Name:          "use",
 		Usage:         localizer.Sprintf("Download (into container) and attach database (.bak) from URL"),
 	})
+
+	addFlag(cmdparser.FlagOptions{
+		String:        &c.network,
+		DefaultString: "",
+		Name:          "network",
+		Usage:         localizer.Sprintf("Container network name (defaults to 'container-network' if --add-on specified)"),
+	})
+
+	addFlag(cmdparser.FlagOptions{
+		String:        &c.addOn,
+		DefaultString: "",
+		Name:          "add-on",
+		Usage:         localizer.Sprintf("Create add-on container"),
+	})
+
+	addFlag(cmdparser.FlagOptions{
+		String:        &c.addOnUse,
+		DefaultString: "",
+		Name:          "add-on-use",
+		Usage:         localizer.Sprintf("File to use for add-on container"),
+	})
+
 }
 
 // Run checks that the end-user license agreement has been accepted,
@@ -261,7 +286,12 @@ func (c *MssqlBase) Run() {
 // command-line and the program will exit.
 func (c *MssqlBase) createContainer(imageName string, contextName string) {
 	output := c.Cmd.Output()
+
 	saPassword := c.generatePassword()
+	userName := pal.UserName()
+	password := c.generatePassword()
+
+	contextName = config.FindUniqueContextName(contextName, userName)
 
 	env := []string{
 		"ACCEPT_EULA=Y",
@@ -270,7 +300,7 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
 	}
 
 	if c.port == 0 {
-		c.port = config.FindFreePortForTds()
+		c.port = config.FindFreePort(1433)
 	}
 
 	// Do an early exit if url doesn't exist
@@ -280,43 +310,65 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
 
 	if c.defaultDatabase != "" {
 		if !c.validateDbName(c.defaultDatabase) {
-			output.Fatalf(localizer.Sprintf("--user-database %q contains non-ASCII chars and/or quotes", c.defaultDatabase))
+			output.Fatalf(localizer.Sprintf("--database %q contains non-ASCII chars and/or quotes", c.defaultDatabase))
 		}
 	}
 
 	controller := container.NewController()
 
+	// If an add-on is specified, and no network name, then set a default network name
+	if c.addOn != "" && c.network == "" {
+		c.network = "sqlcmd-" + contextName + "-network"
+	}
+
+	if c.network != "" {
+		// Create a docker network
+		if !controller.NetworkExists(c.network) {
+			output.Info(localizer.Sprintf("Creating %q, to enable cross container communication for add-ons", c.network))
+			controller.NetworkCreate(c.network)
+		}
+	}
+
+	// Very strange issue that we need to work here.  If we are using add-on containers
+	// we have to specify the name of the mssql container!
+	// Details in this bug/DCR here:
+	//		https://github.com/moby/moby/issues/45183
+	if c.name == "" {
+		c.name = contextName + "-container"
+	}
+
 	if !c.useCached {
 		c.downloadImage(imageName, output, controller)
 	}
 
-	output.Info(localizer.Sprintf("Starting %v", imageName))
+	output.Info(localizer.Sprintf("Starting %q", imageName))
 	containerId := controller.ContainerRun(
 		imageName,
 		env,
+		nil,
+		1433,
 		c.port,
 		c.name,
 		c.hostname,
 		c.architecture,
 		c.os,
+		c.network,
 		[]string{},
 		false,
 	)
 	previousContextName := config.CurrentContextName()
 
-	userName := pal.UserName()
-	password := c.generatePassword()
-
 	// Save the config now, so user can uninstall/delete, even if mssql in the container
 	// fails to start
 	config.AddContextWithContainer(
-		contextName,
 		imageName,
+		contextName,
 		c.port,
 		containerId,
 		userName,
 		password,
 		c.passwordEncryption,
+		c.network,
 	)
 
 	output.Info(
@@ -353,7 +405,11 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
 			Password:           secret.Encode(saPassword, c.passwordEncryption)},
 		Name: "sa"}
 
-	c.sql.Connect(endpoint, saUser, sql.ConnectOptions{Database: "master", Interactive: false})
+	c.sql.Connect(
+		endpoint,
+		saUser,
+		sql.ConnectOptions{Database: "master", Interactive: false},
+	)
 
 	c.createNonSaUser(userName, password)
 
@@ -366,9 +422,65 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
 		)
 	}
 
+	dabPort := 0
+	if c.addOn == "dab" {
+		dabImageName := "mcr.microsoft.com/azure-databases/data-api-builder"
+
+		if !c.useCached {
+			c.downloadImage(dabImageName, output, controller)
+		}
+
+		dabEnv := []string{
+			fmt.Sprintf("CONN_STRING=Server=%s;Database=%s;User ID=%s;Password=%s;TrustServerCertificate=true",
+				c.name,
+				c.defaultDatabase,
+				userName,
+				password),
+		}
+
+		dabPort = config.FindFreePort(5001)
+
+		addOnContainerId := controller.ContainerRun(
+			dabImageName,
+			dabEnv,
+			nil,
+			5000,
+			dabPort,
+			"",
+			"",
+			c.architecture,
+			c.os,
+			c.network,
+			[]string{},
+			false,
+		)
+
+		contextName := config.CurrentContextName()
+
+		// Save add-on details to config file now, so it can be deleted even
+		// if something below fails
+		config.AddAddOn(
+			contextName,
+			"dab",
+			addOnContainerId,
+			dabImageName,
+			"127.0.0.1",
+			dabPort)
+
+		controller.DownloadFile(
+			addOnContainerId,
+			c.addOnUse,
+			"/App",
+		)
+
+		// Restart the container, now that the dab-config file is there
+		controller.ContainerStop(addOnContainerId)
+		controller.ContainerStart(addOnContainerId)
+	}
+
 	hints := [][]string{}
 
-	// TODO: sqlcmd open ads only support on Windows right now, add Mac support
+	// TODO: sqlcmd open ads only supported on Windows and Mac right now, add Linux support
 	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
 		hints = append(hints, []string{localizer.Sprintf("Open in Azure Data Studio"), "sqlcmd open ads"})
 	}
@@ -390,8 +502,20 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
 	hints = append(hints, []string{localizer.Sprintf("See connection strings"), "sqlcmd config connection-strings"})
 	hints = append(hints, []string{localizer.Sprintf("Remove"), "sqlcmd delete"})
 
+	if c.addOn == "dab" {
+		hints = append(hints, []string{
+			localizer.Sprintf("Data API Builder (DAB) Health Status"),
+			fmt.Sprintf("curl -s http://localhost:%d", dabPort),
+		})
+	}
+
+	if c.addOn == "dab" {
+		output.Info(localizer.Sprintf("Now ready for DAB connections on port %d",
+			dabPort),
+		)
+	}
 	output.InfoWithHintExamples(hints,
-		localizer.Sprintf("Now ready for client connections on port %d",
+		localizer.Sprintf("Now ready for SQL connections on port %d",
 			c.port),
 	)
 }
@@ -420,7 +544,7 @@ func (c *MssqlBase) validateUsingUrlExists() {
 
 	// At the moment we only support attaching .bak files, but we should
 	// support .bacpacs and .mdfs in the future
-	if _, file := filepath.Split(u.Path); filepath.Ext(file) != ".bak" {
+	if _, file := filepath.Split(u.Path); filepath.Ext(file) != ".bak" && filepath.Ext(file) != ".sql" {
 		output.FatalWithHints(
 			[]string{
 				localizer.Sprintf("--using file URL must be a .bak file"),
@@ -452,7 +576,7 @@ func (c *MssqlBase) createNonSaUser(
 		defaultDatabase = c.defaultDatabase
 
 		// Create the default database, if it isn't a downloaded database
-		output.Info(localizer.Sprintf("Creating default database [%s]", defaultDatabase))
+		output.Info(localizer.Sprintf("Creating default database %q", defaultDatabase))
 		c.query(fmt.Sprintf("CREATE DATABASE [%s]", defaultDatabase))
 	}
 
@@ -532,7 +656,7 @@ func (c *MssqlBase) downloadAndRestoreDb(
 	_, file := filepath.Split(databaseUrl)
 
 	// Download file from URL into container
-	output.Info(localizer.Sprintf("Downloading %s", file))
+	output.Info(localizer.Sprintf("Downloading %q", file))
 
 	temporaryFolder := "/var/opt/mssql/backup"
 
@@ -542,13 +666,18 @@ func (c *MssqlBase) downloadAndRestoreDb(
 		temporaryFolder,
 	)
 
-	// Restore database from file
-	output.Info(localizer.Sprintf("Restoring database %s", databaseName))
+	if filepath.Ext(file) == ".sql" {
+		output.Info(localizer.Sprintf("Executing .sql file %s", c.usingDatabaseUrl))
+		c.sql.ExecuteSqlFile("c:\\temp\\SQLQuery_1.sql")
+	} else {
+
+		// Restore database from file
+		output.Info(localizer.Sprintf("Restoring database %s", databaseName))
 
-	dbNameAsIdentifier := getDbNameAsIdentifier(databaseName)
-	dbNameAsNonIdentifier := getDbNameAsNonIdentifier(databaseName)
+		dbNameAsIdentifier := getDbNameAsIdentifier(databaseName)
+		dbNameAsNonIdentifier := getDbNameAsNonIdentifier(databaseName)
 
-	text := `SET NOCOUNT ON;
+		text := `SET NOCOUNT ON;
 
 -- Build a SQL Statement to restore any .bak file to the Linux filesystem
 DECLARE @sql NVARCHAR(max)
@@ -589,13 +718,14 @@ WHERE IsPresent = 1
 SET @sql = SUBSTRING(@sql, 1, LEN(@sql)-1)
 EXEC(@sql)`
 
-	c.query(fmt.Sprintf(text, temporaryFolder, file, dbNameAsIdentifier, temporaryFolder, file))
+		c.query(fmt.Sprintf(text, temporaryFolder, file, dbNameAsIdentifier, temporaryFolder, file))
 
-	alterDefaultDb := fmt.Sprintf(
-		"ALTER LOGIN [%s] WITH DEFAULT_DATABASE = [%s]",
-		userName,
-		dbNameAsNonIdentifier)
-	c.query(alterDefaultDb)
+		alterDefaultDb := fmt.Sprintf(
+			"ALTER LOGIN [%s] WITH DEFAULT_DATABASE = [%s]",
+			userName,
+			dbNameAsNonIdentifier)
+		c.query(alterDefaultDb)
+	}
 }
 
 func (c *MssqlBase) downloadImage(
@@ -603,7 +733,7 @@ func (c *MssqlBase) downloadImage(
 	output *output.Output,
 	controller *container.Controller,
 ) {
-	output.Info(localizer.Sprintf("Downloading %v", imageName))
+	output.Info(localizer.Sprintf("Downloading %q", imageName))
 	err := controller.EnsureImage(imageName)
 	if err != nil || c.unitTesting {
 		output.FatalErrorWithHints(
diff --git a/cmd/modern/root/install/mssql.go b/cmd/modern/root/install/mssql.go
index 9465652c..60396478 100644
--- a/cmd/modern/root/install/mssql.go
+++ b/cmd/modern/root/install/mssql.go
@@ -42,7 +42,7 @@ func (c *Mssql) DefineCommand(...cmdparser.CommandOptions) {
 				Steps:       []string{"sqlcmd create mssql --using https://aka.ms/AdventureWorksLT.bak,adventureworks"}},
 			{
 				Description: localizer.Sprintf("Create SQL Server with an empty user database"),
-				Steps:       []string{"sqlcmd create mssql --user-database db1"}},
+				Steps:       []string{"sqlcmd create mssql --database db1"}},
 			{
 				Description: localizer.Sprintf("Install/Create SQL Server with full logging"),
 				Steps:       []string{"sqlcmd create mssql --verbosity 4"}},
diff --git a/cmd/modern/root/install/mssql_test.go b/cmd/modern/root/install/mssql_test.go
index 28d80674..87217f91 100644
--- a/cmd/modern/root/install/mssql_test.go
+++ b/cmd/modern/root/install/mssql_test.go
@@ -25,7 +25,7 @@ func TestInstallMssql(t *testing.T) {
 	cmdparser.TestCmd[*mssql.GetTags]()
 	cmdparser.TestCmd[*Mssql](
 		fmt.Sprintf(
-			`--accept-eula --user-database foo --errorlog-wait-line "Hello from Docker!" --registry %v --repo %v`,
+			`--accept-eula --database foo --errorlog-wait-line "Hello from Docker!" --registry %v --repo %v`,
 			registry,
 			repo))
 
@@ -61,7 +61,7 @@ func TestNegInstallMssql3(t *testing.T) {
 func TestNegInstallMssql4(t *testing.T) {
 	cmdparser.TestSetup(t)
 	assert.Panics(t, func() {
-		cmdparser.TestCmd[*Mssql]("--accept-eula --user-database bad'name")
+		cmdparser.TestCmd[*Mssql]("--accept-eula --database bad'name")
 	})
 }
 
diff --git a/cmd/modern/root/open/ads_windows.go b/cmd/modern/root/open/ads_windows.go
index c98aaad9..66a565e1 100644
--- a/cmd/modern/root/open/ads_windows.go
+++ b/cmd/modern/root/open/ads_windows.go
@@ -65,7 +65,6 @@ func (c *Ads) adsKey(instance, database, authType, user string) string {
 		"Microsoft.SqlTools|"+
 			"itemtype:Profile|"+
 			"id:providerName:MSSQL|"+
-			"applicationName:azdata|"+
 			"authenticationType:%s|"+
 			"database:%s|"+
 			"server:%s|"+
diff --git a/cmd/modern/root/uninstall.go b/cmd/modern/root/uninstall.go
index e44720a3..42b3922b 100644
--- a/cmd/modern/root/uninstall.go
+++ b/cmd/modern/root/uninstall.go
@@ -113,16 +113,40 @@ func (c *Uninstall) run() {
 				c.userDatabaseSafetyCheck(controller, id)
 			}
 
-			output.Info(localizer.Sprintf("Removing context %s", config.CurrentContextName()))
+			output.Info(localizer.Sprintf("Removing context %q", config.CurrentContextName()))
 
 			if controller.ContainerExists(id) {
-				output.Info(localizer.Sprintf("Stopping %s", endpoint.ContainerDetails.Image))
+				output.Info(localizer.Sprintf("Stopping %q", endpoint.ContainerDetails.Image))
 				err := controller.ContainerStop(id)
 				c.CheckErr(err)
 				err = controller.ContainerRemove(id)
 				c.CheckErr(err)
 			} else {
-				output.Warn(localizer.Sprintf("Container %q no longer exists, continuing to remove context...", id))
+				output.Warn(localizer.Sprintf("Container %q (for endpoint %q) no longer exists, continuing to remove context...", id, endpoint.Name))
+			}
+
+			addOns := config.CurrentContextAddOns()
+			for _, a := range addOns {
+				e := config.GetEndpoint(a.Endpoint)
+				if controller.ContainerExists(e.ContainerDetails.Id) {
+					output.Info(localizer.Sprintf("Stopping %q", e.ContainerDetails.Image))
+					err := controller.ContainerStop(e.ContainerDetails.Id)
+					c.CheckErr(err)
+					err = controller.ContainerRemove(e.ContainerDetails.Id)
+					c.CheckErr(err)
+				} else {
+					output.Warn(localizer.Sprintf("Container %q (for endpoint %q) no longer exists, continuing to remove context...", e.ContainerDetails.Id, a.Endpoint))
+				}
+
+				config.DeleteEndpoint(a.Endpoint)
+			}
+
+			network := config.CurrentContextNetwork()
+			if network != nil {
+				if controller.NetworkExists(*network) {
+					output.Info(localizer.Sprintf("Removing container network %q", *network))
+					controller.NetworkDelete(*network)
+				}
 			}
 		}
 
diff --git a/cmd/modern/sqlconfig/sqlconfig.go b/cmd/modern/sqlconfig/sqlconfig.go
index 834947b9..5edd6d55 100644
--- a/cmd/modern/sqlconfig/sqlconfig.go
+++ b/cmd/modern/sqlconfig/sqlconfig.go
@@ -23,6 +23,15 @@ type AssetDetails struct {
 	*ContainerDetails `mapstructure:"container,omitempty" yaml:"container,omitempty"`
 }
 
+type AddOn struct {
+	AddOnsDetails `mapstructure:"addon" yaml:"addon,omitempty"`
+}
+
+type AddOnsDetails struct {
+	Type     string `mapstructure:"type"`
+	Endpoint string `mapstructure:"endpoint"`
+}
+
 type Endpoint struct {
 	*AssetDetails   `mapstructure:"asset,omitempty" yaml:"asset,omitempty"`
 	EndpointDetails `mapstructure:"endpoint" yaml:"endpoint"`
@@ -32,6 +41,8 @@ type Endpoint struct {
 type ContextDetails struct {
 	Endpoint string  `mapstructure:"endpoint"`
 	User     *string `mapstructure:"user,omitempty" yaml:"user,omitempty"`
+	Network  *string `mapstructure:"network,omitempty" yaml:"network,omitempty"`
+	AddOns   []AddOn `mapstructure:"addons,omitempty" yaml:"addons,omitempty"`
 }
 
 type Context struct {
diff --git a/internal/config/config.go b/internal/config/config.go
index 1b24695c..5d8d8ea5 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -91,13 +91,14 @@ func IsEmpty() (isEmpty bool) {
 // contextName and username are unique, and it encrypts the password if
 // requested. The updated configuration is saved to file.
 func AddContextWithContainer(
-	contextName string,
 	imageName string,
+	contextName string,
 	portNumber int,
 	containerId string,
 	username string,
 	password string,
 	passwordEncryption string,
+	network string,
 ) {
 	if containerId == "" {
 		panic("containerId must be provided")
@@ -137,12 +138,21 @@ func AddContextWithContainer(
 		Name: endPointName,
 	})
 
+	contextDetails := ContextDetails{
+		Endpoint: endPointName,
+	}
+
+	if userName != "" {
+		contextDetails.User = &userName
+	}
+
+	if network != "" {
+		contextDetails.Network = &network
+	}
+
 	config.Contexts = append(config.Contexts, Context{
-		ContextDetails: ContextDetails{
-			Endpoint: endPointName,
-			User:     &userName,
-		},
-		Name: contextName,
+		ContextDetails: contextDetails,
+		Name:           contextName,
 	})
 
 	user := User{
@@ -156,7 +166,6 @@ func AddContextWithContainer(
 	}
 
 	config.Users = append(config.Users, user)
-
 	Save()
 }
 
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 7e2540c2..39c074c3 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -83,7 +83,7 @@ func TestConfig(t *testing.T) {
 			GetEndpoint("endpoint")
 			OutputEndpoints(o.Struct, true)
 			OutputEndpoints(o.Struct, false)
-			FindFreePortForTds()
+			FindFreePort(0)
 			DeleteEndpoint("endpoint2")
 			DeleteEndpoint("endpoint3")
 
@@ -131,7 +131,7 @@ func TestConfig(t *testing.T) {
 			ContainerId()
 			RemoveCurrentContext()
 			RemoveCurrentContext()
-			AddContextWithContainer("context", "imageName", 1433, "containerId", "user", "password", "none")
+			AddContextWithContainer("imageName", "context", 1433, "containerId", "user", "password", "none", "")
 			RemoveCurrentContext()
 			DeleteEndpoint("endpoint")
 			DeleteContext("context")
@@ -324,7 +324,7 @@ func TestAddContextWithContainerPanic(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			assert.Panics(t, func() {
-				AddContextWithContainer(tt.args.contextName, tt.args.imageName, tt.args.portNumber, tt.args.containerId, tt.args.username, tt.args.password, tt.args.passwordEncryption)
+				AddContextWithContainer(tt.args.imageName, tt.args.contextName, tt.args.portNumber, tt.args.containerId, tt.args.username, tt.args.password, tt.args.passwordEncryption, "")
 			})
 		})
 	}
diff --git a/internal/config/context.go b/internal/config/context.go
index 64682e5a..84a9c82f 100644
--- a/internal/config/context.go
+++ b/internal/config/context.go
@@ -39,6 +39,44 @@ func AddContext(context Context) string {
 	return context.Name
 }
 
+func AddAddOn(
+	contextName, addOnName string,
+	ContainerId string,
+	Image string,
+	address string,
+	port int,
+) {
+
+	containerDetails := ContainerDetails{
+		Id:    ContainerId,
+		Image: Image}
+
+	assetDetails := AssetDetails{
+		ContainerDetails: &containerDetails}
+
+	endpoint := Endpoint{
+		AssetDetails: &assetDetails,
+		EndpointDetails: EndpointDetails{
+			Address: address,
+			Port:    port},
+		Name: addOnName + "@" + contextName,
+	}
+
+	uniqueEndpointName := AddEndpoint(endpoint)
+
+	for i, c := range config.Contexts {
+		if contextName == c.Name {
+			config.Contexts[i].AddOns = append(c.AddOns, AddOn{
+				AddOnsDetails: AddOnsDetails{
+					Type:     addOnName,
+					Endpoint: uniqueEndpointName}})
+			break
+		}
+	}
+
+	Save()
+}
+
 // CurrentContextName returns the name of the current context in the configuration.
 // The current context is the one that is currently active and used by the application.
 func CurrentContextName() string {
@@ -96,6 +134,32 @@ func CurrentContext() (endpoint Endpoint, user *User) {
 	return
 }
 
+func CurrentContextAddOns() (addOns []AddOn) {
+	currentContextName := GetCurrentContextOrFatal()
+
+	for _, c := range config.Contexts {
+		if c.Name == currentContextName {
+			addOns = c.AddOns
+			break
+		}
+	}
+
+	return
+}
+
+func CurrentContextNetwork() (network *string) {
+	currentContextName := GetCurrentContextOrFatal()
+
+	for _, c := range config.Contexts {
+		if c.Name == currentContextName {
+			network = c.Network
+			break
+		}
+	}
+
+	return
+}
+
 // GetCurrentContextInfo returns endpoint and basic auth info
 // associated with current context
 func GetCurrentContextInfo() (server string, username string, password string) {
diff --git a/internal/config/endpoint-container.go b/internal/config/endpoint-container.go
index dfc87f19..dd29152e 100644
--- a/internal/config/endpoint-container.go
+++ b/internal/config/endpoint-container.go
@@ -63,14 +63,12 @@ func CurrentContextEndpointHasContainer() (exists bool) {
 	return
 }
 
-// FindFreePortForTds is used to find a free port number to use for the TDS
+// FindFreePort is used to find a free port number to use for the TDS
 // protocol. It starts at port number 1433 and continues until it finds a port
 // number that is not currently in use by any of the endpoints in the
 // configuration. It also checks that the port is available on the local machine.
 // If no available port is found after trying up to port number 5000, the function panics.
-func FindFreePortForTds() (portNumber int) {
-	const startingPortNumber = 1433
-
+func FindFreePort(startingPortNumber int) (portNumber int) {
 	portNumber = startingPortNumber
 
 	for {
@@ -91,7 +89,7 @@ func FindFreePortForTds() (portNumber int) {
 
 		portNumber++
 
-		if portNumber == 5000 {
+		if portNumber == startingPortNumber+2000 {
 			panic("Did not find an available port")
 		}
 	}
diff --git a/internal/container/controller.go b/internal/container/controller.go
index 45eead59..f86a6c31 100644
--- a/internal/container/controller.go
+++ b/internal/container/controller.go
@@ -64,29 +64,62 @@ func (c Controller) EnsureImage(image string) (err error) {
 	return
 }
 
+func (c Controller) NetworkCreate(name string) string {
+	resp, err := c.cli.NetworkCreate(context.Background(), name, types.NetworkCreate{})
+	checkErr(err)
+
+	return resp.ID
+}
+
+func (c Controller) NetworkDelete(name string) {
+	err := c.cli.NetworkRemove(context.Background(), name)
+	checkErr(err)
+}
+
+func (c Controller) NetworkExists(name string) bool {
+	networks, err := c.cli.NetworkList(context.Background(), types.NetworkListOptions{})
+	checkErr(err)
+
+	for _, network := range networks {
+		if network.Name == name {
+			return true
+		}
+	}
+
+	return false
+}
+
 // ContainerRun creates a new container using the provided image and env values
-// and binds it to the specified port number. It then starts the container and returns
-// the ID of the container.
+// and binds the internal port to the specified external port number. It then starts
+// the container and returns the ID of the container.
+// Volume mappings are specified as a slice of strings in the format:
+//
+//	volumeMapping := []string{"./DAB-Config:/App/configs"}
 func (c Controller) ContainerRun(
 	image string,
 	env []string,
+	volumeMappings []string,
+	portInternal int,
 	port int,
 	name string,
 	hostname string,
 	architecture string,
 	os string,
+	networkMode string,
 	command []string,
 	unitTestFailure bool,
 ) string {
 	hostConfig := &container.HostConfig{
 		PortBindings: nat.PortMap{
-			nat.Port("1433/tcp"): []nat.PortBinding{
+			nat.Port(strconv.Itoa(portInternal) + "/tcp"): []nat.PortBinding{
 				{
 					HostIP:   "0.0.0.0",
 					HostPort: strconv.Itoa(port),
 				},
 			},
 		},
+		NetworkMode: container.NetworkMode(networkMode),
+		Binds:       volumeMappings,
 	}
 
 	platform := specs.Platform{
@@ -100,6 +133,9 @@ func (c Controller) ContainerRun(
 		Cmd:      command,
 		Env:      env,
 		Hostname: hostname,
+		ExposedPorts: nat.PortSet{
+			nat.Port(strconv.Itoa(portInternal) + "/tcp"): {},
+		},
 	}, hostConfig, nil, &platform, name)
 	checkErr(err)
 
@@ -121,6 +157,16 @@ func (c Controller) ContainerRun(
 	return resp.ID
 }
 
+func (c Controller) ContainerName(containerID string) string {
+	// Inspect the container to get details
+	containerInfo, err := c.cli.ContainerInspect(context.Background(), containerID)
+	checkErr(err)
+
+	// Access the container name from the inspect result
+	containerName := containerInfo.Name[1:] // Removing the leading '/'
+	return containerName
+}
+
 // ContainerWaitForLogEntry is used to wait for a specific string to be written
 // to the logs of a container with the given ID. The function takes in the ID
 // of the container and the string to look for in the logs. It creates a reader
@@ -256,10 +302,22 @@ func (c Controller) DownloadFile(id string, src string, destFolder string) {
 		src,
 	}
 
-	c.runCmdInContainer(id, cmd)
+	_, _, exitCode := c.runCmdInContainer(id, cmd)
+
+	if exitCode != 0 {
+		cmd = []string{
+			"curl",
+			"-o",
+			destFolder + "/" + file, // not using filepath.Join here, this is in the *nix container. always /
+			"-L",
+			src,
+		}
+
+		c.runCmdInContainer(id, cmd)
+	}
 }
 
-func (c Controller) runCmdInContainer(id string, cmd []string) ([]byte, []byte) {
+func (c Controller) runCmdInContainer(id string, cmd []string) ([]byte, []byte, int) {
 	trace("Running command in container: " + strings.Join(cmd, " "))
 
 	response, err := c.cli.ContainerExecCreate(
@@ -301,7 +359,13 @@ func (c Controller) runCmdInContainer(id string, cmd []string) ([]byte, []byte)
 	trace("Stdout: " + string(stdout))
 	trace("Stderr: " + string(stderr))
 
-	return stdout, stderr
+	// Get the exit code
+	execInspect, err := c.cli.ContainerExecInspect(context.Background(), response.ID)
+	checkErr(err)
+
+	trace("ExitCode: %d", execInspect.ExitCode)
+
+	return stdout, stderr, execInspect.ExitCode
 }
 
 // ContainerRunning returns true if the container with the given ID is running.
@@ -329,7 +393,7 @@ func (c Controller) ContainerExists(id string) (exists bool) {
 	)
 	resp, err := c.cli.ContainerList(
 		context.Background(),
-		types.ContainerListOptions{Filters: f},
+		types.ContainerListOptions{Filters: f, All: true},
 	)
 	checkErr(err)
 	if len(resp) > 0 {
diff --git a/internal/container/controller_test.go b/internal/container/controller_test.go
index 347d7aec..119cbfd3 100644
--- a/internal/container/controller_test.go
+++ b/internal/container/controller_test.go
@@ -33,17 +33,7 @@ func TestController_EnsureImage(t *testing.T) {
 	c := NewController()
 	err := c.EnsureImage(imageName)
 	checkErr(err)
-	id := c.ContainerRun(
-		imageName,
-		[]string{},
-		port,
-		"",
-		"",
-		"amd64",
-		"linux",
-		[]string{"ash", "-c", "echo 'Hello World'; sleep 3"},
-		false,
-	)
+	id := c.ContainerRun(imageName, []string{}, nil, 1433, port, "", "", "amd64", "linux", "", []string{"ash", "-c", "echo 'Hello World'; sleep 3"}, false)
 	c.ContainerRunning(id)
 	c.ContainerWaitForLogEntry(id, "Hello World")
 	c.ContainerExists(id)
@@ -80,17 +70,7 @@ func TestController_ContainerRunFailure(t *testing.T) {
 	c := NewController()
 
 	assert.Panics(t, func() {
-		c.ContainerRun(
-			imageName,
-			[]string{},
-			0,
-			"",
-			"",
-			"amd64",
-			"linux",
-			[]string{"ash", "-c", "echo 'Hello World'; sleep 1"},
-			false,
-		)
+		c.ContainerRun(imageName, []string{}, nil, 0, 0, "", "", "amd64", "linux", "", []string{"ash", "-c", "echo 'Hello World'; sleep 1"}, false)
 	})
 }
 
@@ -108,17 +88,7 @@ func TestController_ContainerRunFailureCleanup(t *testing.T) {
 	c := NewController()
 
 	assert.Panics(t, func() {
-		c.ContainerRun(
-			imageName,
-			[]string{},
-			0,
-			"",
-			"",
-			"amd64",
-			"linux",
-			[]string{"ash", "-c", "echo 'Hello World'; sleep 1"},
-			true,
-		)
+		c.ContainerRun(imageName, []string{}, nil, 0, 0, "", "", "amd64", "linux", "", []string{"ash", "-c", "echo 'Hello World'; sleep 1"}, true)
 	})
 }
 
diff --git a/internal/intialize.go b/internal/intialize.go
index e1bb9589..3a9d311f 100644
--- a/internal/intialize.go
+++ b/internal/intialize.go
@@ -9,6 +9,7 @@ import (
 	"github.com/microsoft/go-sqlcmd/internal/http"
 	"github.com/microsoft/go-sqlcmd/internal/io/file"
 	"github.com/microsoft/go-sqlcmd/internal/net"
+	"github.com/microsoft/go-sqlcmd/internal/output/verbosity"
 	"github.com/microsoft/go-sqlcmd/internal/pal"
 	"github.com/microsoft/go-sqlcmd/internal/secret"
 	"github.com/microsoft/go-sqlcmd/internal/sql"
@@ -19,6 +20,7 @@ type InitializeOptions struct {
 	TraceHandler func(format string, a ...any)
 	HintHandler  func([]string)
 	LineBreak    string
+	LoggingLevel verbosity.Level
 }
 
 // Initialize initializes various dependencies for the application with the provided options.
@@ -38,8 +40,13 @@ func Initialize(options InitializeOptions) {
 	if options.LineBreak == "" {
 		panic("LineBreak is empty")
 	}
+
+	enableTraceLogging := false
+	if options.LoggingLevel == verbosity.Trace {
+		enableTraceLogging = true
+	}
 	file.Initialize(options.ErrorHandler, options.TraceHandler)
-	sql.Initialize(options.ErrorHandler, options.TraceHandler, secret.Decode)
+	sql.Initialize(enableTraceLogging, options.ErrorHandler, options.TraceHandler, secret.Decode)
 	config.Initialize(options.ErrorHandler, options.TraceHandler, secret.Encode, secret.Decode, net.IsLocalPortAvailable)
 	container.Initialize(options.ErrorHandler, options.TraceHandler)
 	secret.Initialize(options.ErrorHandler)
diff --git a/internal/sql/error.go b/internal/sql/error.go
index 03256d52..6796f31c 100644
--- a/internal/sql/error.go
+++ b/internal/sql/error.go
@@ -4,6 +4,7 @@
 package sql
 
 var errorCallback func(err error)
+var traceLogging bool
 
 func checkErr(err error) {
 	errorCallback(err)
diff --git a/internal/sql/initialize.go b/internal/sql/initialize.go
index 6016215f..ddd7f985 100644
--- a/internal/sql/initialize.go
+++ b/internal/sql/initialize.go
@@ -6,9 +6,11 @@ package sql
 var decryptCallback func(cipherText string, encryptionMethod string) (secret string)
 
 func Initialize(
+	enableTraceLogging bool,
 	errorHandler func(err error),
 	traceHandler func(format string, a ...any),
 	decryptHandler func(cipherText string, encryptionMethod string) (secret string)) {
+	traceLogging = enableTraceLogging
 	errorCallback = errorHandler
 	traceCallback = traceHandler
 	decryptCallback = decryptHandler
diff --git a/internal/sql/interface.go b/internal/sql/interface.go
index 9203bda5..63281bcc 100644
--- a/internal/sql/interface.go
+++ b/internal/sql/interface.go
@@ -10,6 +10,7 @@ import (
 type Sql interface {
 	Connect(endpoint Endpoint, user *User, options ConnectOptions)
 	Query(text string)
+	ExecuteSqlFile(filename string)
 	ScalarString(query string) string
 }
 
diff --git a/internal/sql/mock.go b/internal/sql/mock.go
index 677dd3a1..80e1add9 100644
--- a/internal/sql/mock.go
+++ b/internal/sql/mock.go
@@ -17,6 +17,9 @@ func (m *mock) Connect(
 func (m *mock) Query(text string) {
 }
 
+func (m *mock) ExecuteSqlFile(filename string) {
+}
+
 func (m *mock) ScalarString(query string) string {
 	return ""
 }
diff --git a/internal/sql/mssql.go b/internal/sql/mssql.go
index e91b1c05..fa09ca83 100644
--- a/internal/sql/mssql.go
+++ b/internal/sql/mssql.go
@@ -5,6 +5,7 @@ package sql
 
 import (
 	"fmt"
+	"io"
 	"os"
 	"strings"
 
@@ -89,6 +90,28 @@ func (m *mssql) Query(text string) {
 	}
 }
 
+type discardCloser struct {
+	io.Writer
+}
+
+func (discardCloser) Close() error {
+	return nil
+}
+
+func (m *mssql) ExecuteSqlFile(filename string) {
+	if traceLogging {
+		m.sqlcmd.SetOutput(os.Stdout)
+		m.sqlcmd.SetError(os.Stderr)
+	} else {
+		m.sqlcmd.SetOutput(discardCloser{Writer: io.Discard})
+		m.sqlcmd.SetError(discardCloser{Writer: io.Discard})
+	}
+
+	trace("Executing .sql file: %q", filename)
+	err := m.sqlcmd.IncludeFile(filename, true)
+	checkErr(err)
+}
+
 func (m *mssql) ScalarString(query string) string {
 	buf := buffer.NewMemoryBuffer()
 	defer func() { _ = buf.Close() }()
