diff --git a/BismNormalizer/BismNormalizer.CommandLine/Program.cs b/BismNormalizer/BismNormalizer.CommandLine/Program.cs index 6421a01..528624b 100644 --- a/BismNormalizer/BismNormalizer.CommandLine/Program.cs +++ b/BismNormalizer/BismNormalizer.CommandLine/Program.cs @@ -21,6 +21,12 @@ namespace BismNormalizer.CommandLine string logFile = null; string scriptFile = null; List skipOptions = null; + bool credsProvided = false; + string sourceUsername = ""; + string sourcePassword = ""; + string targetUsername = ""; + string targetPassword = ""; + StreamWriter writer = null; Comparison _comparison = null; @@ -42,7 +48,7 @@ namespace BismNormalizer.CommandLine Console.WriteLine(""); Console.WriteLine(" USAGE:"); Console.WriteLine(""); - Console.WriteLine(" BismNormalizer.exe BsmnFile [/Log:LogFile] [/Script:ScriptFile] [/Skip:{MissingInSource | MissingInTarget | DifferentDefinitions}]"); + Console.WriteLine(" BismNormalizer.exe BsmnFile [/Log:LogFile] [/Script:ScriptFile] [/Skip:{MissingInSource | MissingInTarget | DifferentDefinitions}] [/CredsProvided:True|False] [/SourceUsername:SourceUsername] [/SourcePassword:SourcePassword] [/TargetUsername:TargetUsername] [/TargetPassword:TargetPassword]"); Console.WriteLine(""); Console.WriteLine(" BsmnFile : Full path to the .bsmn file."); Console.WriteLine(""); @@ -52,6 +58,16 @@ namespace BismNormalizer.CommandLine Console.WriteLine(""); Console.WriteLine(" /Skip:{MissingInSource | MissingInTarget | DifferentDefinitions} : Skip all objects that are missing in source/missing in target/with different definitions. Can pass a comma separated list of multiple skip options; e.g. 'MissingInSource,MissingInTarget,DifferentDefinitions'."); Console.WriteLine(""); + Console.WriteLine(" /CredsProvided:True|False : User credentials from the command line to connect to Analysis Services."); + Console.WriteLine(""); + Console.WriteLine(" /SourceUsername:SourceUsername : Source database username."); + Console.WriteLine(""); + Console.WriteLine(" /SourcePassword:SourcePassword : Source database password."); + Console.WriteLine(""); + Console.WriteLine(" /TargetUsername:TargetUsername : Target database username."); + Console.WriteLine(""); + Console.WriteLine(" /TargetPassword:TargetPassword : Target database password."); + Console.WriteLine(""); return ERROR_SUCCESS; } @@ -61,6 +77,11 @@ namespace BismNormalizer.CommandLine const string logPrefix = "/log:"; const string scriptPrefix = "/script:"; const string skipPrefix = "/skip:"; + const string credsProvidedPrefix = "/credsprovided:"; + const string sourceUsernamePrefix = "/sourceusername:"; + const string sourcePasswordPrefix = "/sourcepassword:"; + const string targetUsernamePrefix = "/targetusername:"; + const string targetPasswordPrefix = "/targetpassword:"; for (int i = 1; i < args.Length; i++) { @@ -84,6 +105,39 @@ namespace BismNormalizer.CommandLine } } } + else if (args[i].Length >= credsProvidedPrefix.Length && args[i].Substring(0, credsProvidedPrefix.Length).ToLower() == credsProvidedPrefix) + { + string credsProvidedString = args[i].Substring(credsProvidedPrefix.Length, args[i].Length - credsProvidedPrefix.Length); + if (credsProvidedString == "True") + { + credsProvided = true; + } + else if (credsProvidedString == "False") + { + credsProvided = false; + } + else + { + Console.WriteLine($"'{args[i]}' is not a valid argument."); + return ERROR_BAD_ARGUMENTS; + } + } + else if (args[i].Length >= sourceUsernamePrefix.Length && args[i].Substring(0, sourceUsernamePrefix.Length).ToLower() == sourceUsernamePrefix) + { + sourceUsername = args[i].Substring(sourceUsernamePrefix.Length, args[i].Length - sourceUsernamePrefix.Length); + } + else if (args[i].Length >= sourcePasswordPrefix.Length && args[i].Substring(0, sourcePasswordPrefix.Length).ToLower() == sourcePasswordPrefix) + { + sourcePassword = args[i].Substring(sourcePasswordPrefix.Length, args[i].Length - sourcePasswordPrefix.Length); + } + else if (args[i].Length >= targetUsernamePrefix.Length && args[i].Substring(0, targetUsernamePrefix.Length).ToLower() == targetUsernamePrefix) + { + targetUsername = args[i].Substring(targetUsernamePrefix.Length, args[i].Length - targetUsernamePrefix.Length); + } + else if (args[i].Length >= targetPasswordPrefix.Length && args[i].Substring(0, targetPasswordPrefix.Length).ToLower() == targetPasswordPrefix) + { + targetPassword = args[i].Substring(targetPasswordPrefix.Length, args[i].Length - targetPasswordPrefix.Length); + } else { Console.WriteLine($"'{args[i]}' is not a valid argument."); @@ -129,7 +183,14 @@ namespace BismNormalizer.CommandLine Console.WriteLine(); Console.WriteLine("--Comparing ..."); - _comparison = ComparisonFactory.CreateComparison(comparisonInfo); + if (credsProvided) + { + _comparison = ComparisonFactory.CreateComparison(comparisonInfo, sourceUsername, sourcePassword, targetUsername, targetPassword); + } + else + { + _comparison = ComparisonFactory.CreateComparison(comparisonInfo); + } _comparison.ValidationMessage += HandleValidationMessage; _comparison.Connect(); _comparison.CompareTabularModels(); @@ -168,7 +229,7 @@ namespace BismNormalizer.CommandLine else { Console.WriteLine($"Deployed changes to database {comparisonInfo.ConnectionInfoTarget.DatabaseName}."); - Console.WriteLine("Passwords have not been set for impersonation accounts (setting passwords is not supported in command-line mode). Ensure the passwords are set before processing."); + Console.WriteLine("Passwords have not been set for impersonation accounts (setting passwords for data sources is not supported in command-line mode). Ensure the passwords are set before processing."); if (comparisonInfo.OptionsInfo.OptionProcessingOption != ProcessingOption.DoNotProcess) { Console.WriteLine("No processing has been done (processing is not supported in command-line mode)."); diff --git a/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs b/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs index 1ef545d..76edf67 100644 --- a/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs +++ b/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.0.1.1")] -[assembly: AssemblyFileVersion("4.0.1.1")] +[assembly: AssemblyVersion("4.0.1.8")] +[assembly: AssemblyFileVersion("4.0.1.8")] diff --git a/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs b/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs index 716b478..59890d5 100644 --- a/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs +++ b/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.0.1.1")] -[assembly: AssemblyFileVersion("4.0.1.1")] +[assembly: AssemblyVersion("4.0.1.8")] +[assembly: AssemblyFileVersion("4.0.1.8")] diff --git a/BismNormalizer/BismNormalizer/BismNormalizer.csproj b/BismNormalizer/BismNormalizer/BismNormalizer.csproj index dd778f1..855216d 100644 --- a/BismNormalizer/BismNormalizer/BismNormalizer.csproj +++ b/BismNormalizer/BismNormalizer/BismNormalizer.csproj @@ -29,6 +29,8 @@ false false true + + false @@ -73,10 +75,13 @@ true - + + ..\packages\EnvDTE.8.0.2\lib\net10\EnvDTE.dll False + True - + + ..\packages\EnvDTE80.8.0.3\lib\net10\EnvDTE80.dll False @@ -191,6 +196,7 @@ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\stdole.7.0.3302\lib\net10\stdole.dll True @@ -381,6 +387,14 @@ + + true + Always + + + true + Always + Always true @@ -555,4 +569,11 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs b/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs index 1428d62..fd0a094 100644 --- a/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs +++ b/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.0.1.1")] -[assembly: AssemblyFileVersion("4.0.1.1")] +[assembly: AssemblyVersion("4.0.1.8")] +[assembly: AssemblyFileVersion("4.0.1.8")] diff --git a/BismNormalizer/BismNormalizer/TabularCompare/ComparisonFactory.cs b/BismNormalizer/BismNormalizer/TabularCompare/ComparisonFactory.cs index d4e8059..7479ee5 100644 --- a/BismNormalizer/BismNormalizer/TabularCompare/ComparisonFactory.cs +++ b/BismNormalizer/BismNormalizer/TabularCompare/ComparisonFactory.cs @@ -59,6 +59,17 @@ namespace BismNormalizer.TabularCompare return CreateComparisonInitialized(comparisonInfo); } + /// + /// Uses factory design pattern to return an object of type Core.Comparison, which is instantiated using MultidimensionalMetadata.Comparison or TabularMeatadata.Comparison depending on SSAS compatibility level. + /// + /// ComparisonInfo object for the comparison. + /// Core.Comparison object + public static Comparison CreateComparison(ComparisonInfo comparisonInfo, string sourceUsername, string sourcePassword, string targetUsername, string targetPassword) + { + comparisonInfo.InitializeCompatibilityLevels(sourceUsername, sourcePassword, targetUsername, targetPassword); + return CreateComparisonInitialized(comparisonInfo); + } + private static Comparison CreateComparisonInitialized(ComparisonInfo comparisonInfo) { Telemetry.TrackEvent("CreateComparisonInitialized", new Dictionary { { "App", "BismNormalizer" } }); diff --git a/BismNormalizer/BismNormalizer/TabularCompare/ComparisonInfo.cs b/BismNormalizer/BismNormalizer/TabularCompare/ComparisonInfo.cs index 50d9d1f..d5ace4e 100644 --- a/BismNormalizer/BismNormalizer/TabularCompare/ComparisonInfo.cs +++ b/BismNormalizer/BismNormalizer/TabularCompare/ComparisonInfo.cs @@ -127,8 +127,6 @@ namespace BismNormalizer.TabularCompare /// /// Finds models' compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when client is not Visual Studio - e.g. command line. /// - /// - /// public void InitializeCompatibilityLevels() { ConnectionInfoSource.InitializeCompatibilityLevel(); @@ -137,6 +135,24 @@ namespace BismNormalizer.TabularCompare PopulateDatabaseProperties(); } + /// + /// Finds models' compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when client is not Visual Studio - e.g. command line. + /// + public void InitializeCompatibilityLevels(string sourceUsername, string sourcePassword, string targetUsername, string targetPassword) + { + ConnectionInfoSource.CredsProvided = true; + ConnectionInfoSource.Username = sourceUsername; + ConnectionInfoSource.Password = sourcePassword; + ConnectionInfoSource.InitializeCompatibilityLevel(); + + ConnectionInfoTarget.CredsProvided = true; + ConnectionInfoTarget.Username = targetUsername; + ConnectionInfoTarget.Password = targetPassword; + ConnectionInfoTarget.InitializeCompatibilityLevel(); + + PopulateDatabaseProperties(); + } + /// /// Finds model compatibility levels (and preps databases on workspace servers for comparison). This overload to be used when running in Visual Studio. Allows user to cancel if doesn't want to close .bim file(s). /// diff --git a/BismNormalizer/BismNormalizer/TabularCompare/ConnectionInfo.cs b/BismNormalizer/BismNormalizer/TabularCompare/ConnectionInfo.cs index 9480194..71bdc21 100644 --- a/BismNormalizer/BismNormalizer/TabularCompare/ConnectionInfo.cs +++ b/BismNormalizer/BismNormalizer/TabularCompare/ConnectionInfo.cs @@ -31,9 +31,14 @@ namespace BismNormalizer.TabularCompare private string _deploymentServerDatabase; private string _deploymentServerCubeName; private DirectoryInfo _projectDirectoryInfo; + private bool _credsProvided = false; + private string _username; + private string _password; #endregion + #region Properties + /// /// Initializes a new instance of the ConnectionInfo class. /// @@ -132,6 +137,38 @@ namespace BismNormalizer.TabularCompare [XmlIgnore()] public string DeploymentServerCubeName => _deploymentServerCubeName; + /// + /// Use credentials are provided for command line execution. + /// + [XmlIgnore()] + public bool CredsProvided + { + get { return _credsProvided; } + set { _credsProvided = value; } + } + + /// + /// Username for command line execution. + /// + [XmlIgnore()] + public string Username + { + get { return _username; } + set { _username = value; } + } + + /// + /// Password for command line execution. + /// + [XmlIgnore()] + public string Password + { + get { return _password; } + set { _password = value; } + } + + #endregion + private void ReadSettingsFile() { FileInfo[] files = _projectDirectoryInfo.GetFiles("*.settings", SearchOption.TopDirectoryOnly); @@ -326,7 +363,7 @@ namespace BismNormalizer.TabularCompare Server amoServer = new Server(); try { - amoServer.Connect("Provider=MSOLAP;Data Source=" + this.ServerName); + amoServer.Connect(BuildConnectionString()); } catch (ConnectionException) when (UseProject) { @@ -349,7 +386,7 @@ namespace BismNormalizer.TabularCompare { string port = File.ReadAllText(portFilePath[0]).Replace("\0", ""); this.ServerName = $"localhost:{Convert.ToString(port)}"; - amoServer.Connect("Provider=MSOLAP;Data Source=" + this.ServerName); + amoServer.Connect(BuildConnectionString()); foundServer = true; break; } @@ -496,7 +533,7 @@ $@"{{ //need next lines in case just created the db using the Execute method //amoServer.Refresh(); //todo workaround for bug 9719887 on 3/10/17 need to disconnect and reconnect amoServer.Disconnect(); - amoServer.Connect("Provider=MSOLAP;Data Source=" + this.ServerName); + amoServer.Connect(BuildConnectionString()); tabularDatabase = amoServer.Databases.FindByName(this.DatabaseName); } @@ -509,5 +546,20 @@ $@"{{ _directQuery = ((tabularDatabase.Model != null && tabularDatabase.Model.DefaultMode == Microsoft.AnalysisServices.Tabular.ModeType.DirectQuery) || tabularDatabase.DirectQueryMode == DirectQueryMode.DirectQuery || tabularDatabase.DirectQueryMode == DirectQueryMode.InMemoryWithDirectQuery || tabularDatabase.DirectQueryMode == DirectQueryMode.DirectQueryWithInMemory); } + + /// + /// Build connection string. + /// + /// + public string BuildConnectionString() + { + string connectionString = $"Provider=MSOLAP;Data Source={this.ServerName};"; + if (this.CredsProvided) + { + connectionString += $"User ID={this.Username};Password={this.Password};"; + } + + return connectionString; + } } } diff --git a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs index 0824707..9ff1477 100644 --- a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs +++ b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs @@ -57,7 +57,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata this.Disconnect(); _server = new Server(); - _server.Connect($"Provider=MSOLAP;Data Source={_connectionInfo.ServerName}"); + _server.Connect(_connectionInfo.BuildConnectionString()); _database = _server.Databases.FindByName(_connectionInfo.DatabaseName); if (_database == null) @@ -1648,7 +1648,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata _server.Disconnect(); _server = new Server(); - _server.Connect("Provider=MSOLAP;Data Source=" + _connectionInfo.ServerName); + _server.Connect(_connectionInfo.BuildConnectionString()); Amo.XmlaResultCollection results = _server.Execute(tmslCommand); if (results.ContainsErrors) throw new Amo.OperationException(results); diff --git a/BismNormalizer/BismNormalizer/TabularCompare/UI/Connections.cs b/BismNormalizer/BismNormalizer/TabularCompare/UI/Connections.cs index 5e8c408..98d4a40 100644 --- a/BismNormalizer/BismNormalizer/TabularCompare/UI/Connections.cs +++ b/BismNormalizer/BismNormalizer/TabularCompare/UI/Connections.cs @@ -252,7 +252,7 @@ namespace BismNormalizer.TabularCompare.UI { projects.Add(derivedProjectName, project); } - else if (project.Kind == EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder) + else if (project.Kind == "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}") { foreach (EnvDTE.ProjectItem projectItem in project.ProjectItems) { diff --git a/BismNormalizer/BismNormalizer/app.config b/BismNormalizer/BismNormalizer/app.config index eb7f0e0..4f0c964 100644 --- a/BismNormalizer/BismNormalizer/app.config +++ b/BismNormalizer/BismNormalizer/app.config @@ -1,8 +1,8 @@ - + -
+
@@ -11,13 +11,13 @@ localhost| - + localhost| - + True @@ -75,24 +75,24 @@ - + - - + + - - + + - - + + - - + + diff --git a/BismNormalizer/BismNormalizer/packages.config b/BismNormalizer/BismNormalizer/packages.config index c46aeab..f9a9ec9 100644 --- a/BismNormalizer/BismNormalizer/packages.config +++ b/BismNormalizer/BismNormalizer/packages.config @@ -1,5 +1,7 @@  + + @@ -10,6 +12,7 @@ + @@ -25,5 +28,6 @@ + \ No newline at end of file diff --git a/BismNormalizer/BismNormalizer/source.extension.vsixmanifest b/BismNormalizer/BismNormalizer/source.extension.vsixmanifest index df284e5..a97f822 100644 --- a/BismNormalizer/BismNormalizer/source.extension.vsixmanifest +++ b/BismNormalizer/BismNormalizer/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + BISM Normalizer BISM Normalizer manages Analysis Services tabular models http://bism-normalizer.com/ diff --git a/RestApiSample/RestApiSample/Program.cs b/RestApiSample/RestApiSample/Program.cs index b7de12a..a20fd08 100644 --- a/RestApiSample/RestApiSample/Program.cs +++ b/RestApiSample/RestApiSample/Program.cs @@ -22,7 +22,8 @@ namespace RestApiSample private static async void CallRefreshAsync() { HttpClient client = new HttpClient(); - client.BaseAddress = new Uri("https://.asazure.windows.net/servers//models//"); + //client.BaseAddress = new Uri("https://.asazure.windows.net/servers//models//"); + client.BaseAddress = new Uri("https://southcentralus.asazure.windows.net/servers/chwade003/models/AdventureWorks0/"); // Send refresh request client.DefaultRequestHeaders.Accept.Clear(); @@ -65,7 +66,8 @@ namespace RestApiSample { string resourceURI = "https://*.asazure.windows.net"; - string authority = "https://login.windows.net//oauth2/authorize"; + //string authority = "https://login.windows.net//oauth2/authorize"; + string authority = "https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/authorize"; // Authority address can optionally use tenant ID in place of "common". If service principal or B2B enabled, this is a requirement. AuthenticationContext ac = new AuthenticationContext(authority); #region Interactive or username/password @@ -82,7 +84,8 @@ namespace RestApiSample #endregion //Service principal: - ClientCredential cred = new ClientCredential("", ""); + //ClientCredential cred = new ClientCredential("", ""); + ClientCredential cred = new ClientCredential("99ae7bd1-6b02-425f-928e-97baa957d3f1", "0T8BYov1JciG+q3B4bB4bY8EbBjWpY7aC3OBp0u9tj8="); AuthenticationResult ar = await ac.AcquireTokenAsync(resourceURI, cred); return ar.AccessToken;