static async Task <int> Main(string[] args) { var watch = Stopwatch.StartNew(); string[] parsedArgs = args.TakeWhile(a => a != "--").ToArray(); string usage = @"Usage: rescaler [-simulate] [-verbose] <edition> <size> [+includedb1] [-excludedb1] [+includedb2] [-excludedb2] ... simulate: Dry run verbose: Verbose logging edition: Basic/Standard/Premium size: Basic/S0.../P1... includedb...: Substring to contain (name of: resource group, server, database) Specify credentials using a service principal by setting the environment variables: AzureTenantId AzureClientId AzureClientSecret Multiple service principals can be specified by prefixing/postfixing the environment variables."; bool simulate = parsedArgs.Contains("-simulate"); parsedArgs = parsedArgs.Where(a => a != "-simulate").ToArray(); bool verbose = parsedArgs.Contains("-verbose"); parsedArgs = parsedArgs.Where(a => a != "-verbose").ToArray(); if (parsedArgs.Length < 2) { Log(usage); return(1); } string[] filterdbs = parsedArgs.Skip(2).ToArray(); parsedArgs = parsedArgs.Take(2).ToArray(); if (filterdbs.Length == 0) { Log($"At least 1 Include/Exclude filter must be specified."); Log(usage); return(1); } var invalidfilters = filterdbs.Where(db => !db.StartsWith('+') && !db.StartsWith('-')).ToArray(); if (invalidfilters.Length > 0) { foreach (var filter in invalidfilters) { Log($"Include/Exclude filters must be prefixed with + or -: '{filter}'"); } Log(usage); return(1); } if (parsedArgs.Length != 2) { Log(usage); return(1); } string dbedition = parsedArgs[0]; string dbsize = parsedArgs[1]; var servicePrincipals = GetServicePrincipals(); if (servicePrincipals.Length == 0) { Log("Missing environment variables: AzureTenantId, AzureClientId, AzureClientSecret"); return(1); } Log($"Got {servicePrincipals.Length} service principals: '{string.Join("', '", servicePrincipals.Select(sp => sp.FriendlyName))}'"); await ServicePrincipal.GetAzureAccessTokensAsync(servicePrincipals); var accessTokens = servicePrincipals.Where(sp => sp.AccessToken != null).ToArray(); Log($"Got {accessTokens.Length} access tokens."); if (accessTokens.Length == 0) { return(1); } var rescaler = new Rescaler(); var tasks = accessTokens.Select(accessToken => rescaler.RescaleAsync(accessToken, dbedition, dbsize, filterdbs, simulate, verbose)); await Task.WhenAll(tasks); Log($"Total done: {watch.Elapsed}"); return(0); }