1+ param (
2+ # Automatically skip loading assemblies that are already loaded (useful when SqlServer module is already imported)
3+ [Alias (' SkipLoadedAssemblies' , ' AllowSharedAssemblies' )]
4+ [switch ]$AvoidConflicts
5+ )
6+
17function Get-DbatoolsLibraryPath {
28 [CmdletBinding ()]
39 param ()
@@ -54,29 +60,42 @@ if ($PSVersionTable.PSEdition -ne "Core") {
5460 "Microsoft.SqlServer.Rmo",
5561 "System.Private.CoreLib",
5662 "Azure.Core",
57- "Azure.Identity"
63+ "Azure.Identity",
64+ "Microsoft.Data.Tools.Utilities",
65+ "Microsoft.Data.Tools.Schema.Sql",
66+ "Microsoft.SqlServer.TransactSql.ScriptDom"
5867 };
5968
60- var name = new AssemblyName(e.Name);
61- var assemblyName = name.Name.ToString();
69+ var requestedName = new AssemblyName(e.Name);
70+ var assemblyName = requestedName.Name;
71+
72+ // First, check if any version of this assembly is already loaded
73+ // This handles version mismatches (e.g., SMO requesting SqlClient 5.0.0.0 when 6.0.2 is loaded)
74+ foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
75+ {
76+ try
77+ {
78+ if (assembly.GetName().Name == assemblyName)
79+ {
80+ return assembly;
81+ }
82+ }
83+ catch
84+ {
85+ // Some assemblies may throw when accessing GetName()
86+ }
87+ }
88+
89+ // Only load from disk if not already loaded and it's in our list
6290 foreach (string dll in dlls)
6391 {
6492 if (assemblyName == dll)
6593 {
6694 string filelocation = "$dir " + dll + ".dll";
67- //Console.WriteLine(filelocation);
6895 return Assembly.LoadFrom(filelocation);
6996 }
7097 }
7198
72- foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
73- {
74- // maybe this needs to change?
75- var info = assembly.GetName();
76- if (info.FullName == e.Name) {
77- return assembly;
78- }
79- }
8099 return null;
81100 }
82101 }
@@ -96,14 +115,24 @@ if ($PSVersionTable.PSEdition -ne "Core") {
96115# REMOVED win-sqlclient logic - SqlClient is now directly in lib
97116$sqlclient = [System.IO.Path ]::Combine($script :libraryroot , " lib" , " Microsoft.Data.SqlClient.dll" )
98117
99- try {
100- Import-Module $sqlclient
101- } catch {
102- throw " Couldn't import $sqlclient | $PSItem "
118+ # Get loaded assemblies once for reuse (used for AvoidConflicts checks and later assembly loading)
119+ $script :loadedAssemblies = [System.AppDomain ]::CurrentDomain.GetAssemblies()
120+
121+ # Check if SqlClient is already loaded when AvoidConflicts is set
122+ $skipSqlClient = $false
123+ if ($AvoidConflicts ) {
124+ $skipSqlClient = $script :loadedAssemblies | Where-Object { $_.GetName ().Name -eq ' Microsoft.Data.SqlClient' }
125+ if ($skipSqlClient ) {
126+ Write-Verbose " Skipping Microsoft.Data.SqlClient.dll - already loaded"
127+ }
103128}
104129
105- if ($PSVersionTable.PSEdition -ne " Core" ) {
106- [System.AppDomain ]::CurrentDomain.remove_AssemblyResolve($onAssemblyResolveEventHandler )
130+ if (-not $skipSqlClient ) {
131+ try {
132+ Import-Module $sqlclient
133+ } catch {
134+ throw " Couldn't import $sqlclient | $PSItem "
135+ }
107136}
108137
109138if ($PSVersionTable.PSEdition -eq " Core" ) {
@@ -114,6 +143,9 @@ if ($PSVersionTable.PSEdition -eq "Core") {
114143 ' Microsoft.IdentityModel.Abstractions' ,
115144 ' Microsoft.SqlServer.Dac' ,
116145 ' Microsoft.SqlServer.Dac.Extensions' ,
146+ ' Microsoft.Data.Tools.Utilities' ,
147+ ' Microsoft.Data.Tools.Schema.Sql' ,
148+ ' Microsoft.SqlServer.TransactSql.ScriptDom' ,
117149 ' Microsoft.SqlServer.Smo' ,
118150 ' Microsoft.SqlServer.SmoExtended' ,
119151 ' Microsoft.SqlServer.SqlWmiManagement' ,
@@ -129,9 +161,11 @@ if ($PSVersionTable.PSEdition -eq "Core") {
129161 ' Azure.Core' ,
130162 ' Azure.Identity' ,
131163 ' Microsoft.IdentityModel.Abstractions' ,
132- ' Microsoft.Data.SqlClient' ,
133164 ' Microsoft.SqlServer.Dac' ,
134165 ' Microsoft.SqlServer.Dac.Extensions' ,
166+ ' Microsoft.Data.Tools.Utilities' ,
167+ ' Microsoft.Data.Tools.Schema.Sql' ,
168+ ' Microsoft.SqlServer.TransactSql.ScriptDom' ,
135169 ' Microsoft.SqlServer.Smo' ,
136170 ' Microsoft.SqlServer.SmoExtended' ,
137171 ' Microsoft.SqlServer.SqlWmiManagement' ,
@@ -159,8 +193,8 @@ if ($PSVersionTable.OS -match "ARM64") {
159193}
160194# endregion Names
161195
162- # this takes 10ms
163- $assemblies = [ System.AppDomain ]::CurrentDomain.GetAssemblies()
196+ # Build string of loaded assembly names once for efficient checking
197+ $script :loadedAssemblyNames = $ script :loadedAssemblies .FullName | Out-String
164198
165199try {
166200 $null = Import-Module ([IO.Path ]::Combine($script :libraryroot , " third-party" , " bogus" , " Bogus.dll" ))
@@ -169,22 +203,34 @@ try {
169203}
170204
171205foreach ($name in $names ) {
172- # REMOVED win-sqlclient handling and mac-specific logic since files are in standard lib folder
173-
174206 $x64only = ' Microsoft.SqlServer.Replication' , ' Microsoft.SqlServer.XEvent.Linq' , ' Microsoft.SqlServer.BatchParser' , ' Microsoft.SqlServer.Rmo' , ' Microsoft.SqlServer.BatchParserClient'
175207
176208 if ($name -in $x64only -and $env: PROCESSOR_ARCHITECTURE -eq " x86" ) {
177209 Write-Verbose - Message " Skipping $name . x86 not supported for this library."
178210 continue
179211 }
180212
181- $assemblyPath = [IO.Path ]::Combine($script :libraryroot , " lib" , " $name .dll" )
182- $assemblyfullname = $assemblies.FullName | Out-String
183- if (-not ($assemblyfullname.Contains (" $name ," ))) {
184- $null = try {
185- $null = Import-Module $assemblyPath
186- } catch {
187- Write-Error " Could not import $assemblyPath : $ ( $_ | Out-String ) "
213+ # Check if assembly is already loaded (always check to avoid duplicate loads)
214+ if ($script :loadedAssemblyNames.Contains (" $name ," )) {
215+ if ($AvoidConflicts ) {
216+ Write-Verbose " Skipping $name .dll - already loaded"
188217 }
218+ continue
219+ }
220+
221+ # Load the assembly
222+ $assemblyPath = [IO.Path ]::Combine($script :libraryroot , " lib" , " $name .dll" )
223+ try {
224+ $null = Import-Module $assemblyPath
225+ } catch {
226+ Write-Error " Could not import $assemblyPath : $ ( $_ | Out-String ) "
189227 }
228+ }
229+
230+ # Keep the assembly resolver registered for Windows PowerShell
231+ # It's needed at runtime when SMO and other assemblies try to resolve dependencies
232+ # The resolver handles version mismatches (e.g., SMO requesting SqlClient 5.0.0.0 when 6.0.2 is loaded)
233+ if ($PSVersionTable.PSEdition -ne " Core" -and $redirector ) {
234+ # Store the redirector in script scope so it stays alive and can be accessed if needed
235+ $script :assemblyRedirector = $redirector
190236}
0 commit comments