I went to the trouble of downloading the localdb versions of SQL so i could build a lab fast.
The PowerShell Example Below Dynamically creates multiple versions of SQL Server, all with the sa password of MyRealPasswordForTheDemo#312
###################################################################################################
## Create semi-random Localdb instances and also add them to the CMS
###################################################################################################
#LDB-rand-DQUPE
Clear-Host
###################################################################################################
## BEGIN Configuration
###################################################################################################
## [string[]] $CMSEnvironments = "Prod","Dev","QA","STG", "UAT","Prod" ## repeating Prod twice means twice as many prod servers as other layers
[string[]] $CMSEnvironments = "Prod","Dev","QA" ## repeating Prod twice means twice as many prod servers as other layers
[string] $SQLServerName = "LocalHost"
[int] $ServersPerLayer = 1
[string] $ScriptsDirectory = ""
[Hashtable] $AvailableSQLVersions = @{ "SQL2014" =" 12.0";"SQL2016" = "13.0";"SQL2017" = "14.0";"SQL2019" = "15.0"} #$AvailableSQLVersions.GetType()
$Password = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('TXlSZWFsUGFzc3dvcmRGb3JUaGVEZW1vIzMxMg=='))
$UserName = "sa"
$UseSQLLogin = $false;
###################################################################################################
## END Configuration
###################################################################################################
Function Get-RandomCharacters { # https://powersnippets.com/create-password/
[CmdletBinding()]Param ( # Version 01.01.00, by iRon
[Int]$Size = 8, [Char[]]$Complexity = "ULNS", [Char[]]$Exclude
)
$AllTokens = @(); $Chars = @(); $TokenSets = @{
UpperCase = [Char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
LowerCase = [Char[]]'abcdefghijklmnopqrstuvwxyz'
Numbers = [Char[]]'0123456789'
Symbols = [Char[]]'!"#$%&''()*+,-./:;<=>?@[\]^_`{|}~'
}
$TokenSets.Keys | Where-Object {$Complexity -Contains $_[0]} | ForEach-Object {
$TokenSet = $TokenSets.$_ | Where-Object {$Exclude -cNotContains $_} | ForEach-Object {$_}
If ($_[0] -cle "Z") {$Chars += $TokenSet | Get-Random} #Character sets defined in uppercase are mandatory
$AllTokens += $TokenSet
}
While ($Chars.Count -lt $Size) {$Chars += $AllTokens | Get-Random}
($Chars | Sort-Object {Get-Random}) -Join "" #Mix the (mandatory) characters and output string
}
###################################################################################################
##check for all the possible LocalDB versions for variety
###################################################################################################
$PathToLocalDB = 'C:\Program Files\Microsoft SQL Server\150\Tools\Binn\SQLLocalDB.exe' ##SQL2019
if($env:COMPUTERNAME -eq 'STORMBASE') {$BasePath = 'D:\Data\GitHub\Workspace\AutomatedInstall\DBA_sps\'} else{$BasePath = 'C:\Data\GitHub\Workspace\AutomatedInstall\DBA_sps\'}
$LogPath = [System.IO.Path]::Combine($BasePath,"LocalDBSQLScriptLogs_" + (Get-Date).ToString("yyyy-MM-dd") + ".txt")
## $PathToLocalDB defaults to the "latest" version of SQL with the above logic.
###################################################################################################
##Remove any LocalDB instances that already exist, except for the default
###################################################################################################
$CurrentLocalDBs = &$PathToLocalDB 'info'
foreach($localDB in $CurrentLocalDBs)
{
if ($localDB -ne 'MSSQLLocalDB' -and $localDB -ne "v11.0")
{
$SQLQuery ="DELETE FROM msdb.dbo.sysmanagement_shared_registered_servers WHERE name = '" + $localDB.ToString() + "';"
Invoke-SQLCMD -Query $SQLQuery -Database "msdb" -ServerInstance $SQLServerName -TrustServerCertificate
&$PathToLocalDB 'stop' $localDB.ToString()
&$PathToLocalDB 'delete' $localDB.ToString()
}
}
###################################################################################################
## now add multiple servers to each environment
###################################################################################################
foreach($LocalDBVersion in $AvailableSQLVersions.GetEnumerator() ) #ForEach-Object($LocalDBVersion in $AvailableSQLVersions.GetEnumerator()){Write-Host $LocalDBVersion.Name + "-->" + $LocalDBVersion.Value -ForegroundColor Green}
#$AvailableSQLVersions.GetEnumerator() | ForEach-Object {"$($_.Key) - $($_.Value)"}
{
[int] $i=0
foreach($val in $CMSEnvironments)
{
$SQLQuery = "IF NOT EXISTS(SELECT 1 FROM msdb.dbo.[sysmanagement_shared_server_groups] WHERE [name] = '_" + $val.ToString() + "_Apps' INSERT INTO msdb.dbo.[sysmanagement_shared_server_groups](name,description,server_type,parent_id) VALUES('_" + $val.ToString() + "_Apps','" + $val.ToString() + "',0,1)"
#ETL This block is creating ONE ETL server per environment, to mimic how it is done in one of my environments
$results = Get-RandomCharacters 8 UN
$results ='WIN-' + $results + '-' + 'ETL'
Write-Host $results -ForegroundColor Green
&$PathToLocalDB 'create' ($results.ToString()) ($LocalDBVersion.Value.ToString())
&$PathToLocalDB 'start' $results.ToString()
$SQLQuery = @"
DECLARE @P1 varchar(128) = '{0}';
IF NOT EXISTS(SELECT * FROM msdb.dbo.[sysmanagement_shared_server_groups] WHERE name = '_ETL_Apps' AND parent_id = 1)
INSERT INTO msdb.dbo.[sysmanagement_shared_server_groups](name,description,server_type,parent_id) SELECT '_ETL_Apps','_ETL_Apps',0,1;
INSERT INTO msdb.dbo.sysmanagement_shared_registered_servers(server_group_id,name,server_name,description,server_type)
SELECT grpz.[server_group_id],@P1,'(LocalDB)\' + @P1,@P1 + ';Version {2};{3}',0
FROM msdb.dbo.[sysmanagement_shared_server_groups] grpz
WHERE grpz.[name] = '_ETL_Apps'
"@ -f $results,$val,$LocalDBVersion.Key.ToString(),$LocalDBVersion.Value.ToString()
#$SQLQuery
Invoke-SQLCMD -Query $SQLQuery -Database "msdb" -ServerInstance $SQLServerName -TrustServerCertificate
for ($i=0;$i -le $ServersPerLayer;$i++)
{
$results = Get-RandomCharacters 8 UN
$results ='WIN-' + $results + '-' + $val
#$results
&$PathToLocalDB 'create' $results $LocalDBVersion.Value
&$PathToLocalDB 'start' $results.ToString()
$SQLQuery = @"
DECLARE @P1 varchar(128) = '{0}';
IF NOT EXISTS(SELECT * FROM msdb.dbo.[sysmanagement_shared_server_groups] WHERE name = '_{1}_Apps' AND parent_id = 1)
INSERT INTO msdb.dbo.[sysmanagement_shared_server_groups](name,description,server_type,parent_id) SELECT '_{1}_Apps','_{1}_Apps',0,1;
INSERT INTO msdb.dbo.sysmanagement_shared_registered_servers(server_group_id,name,server_name,description,server_type)
SELECT grpz.[server_group_id],@P1,'(LocalDB)\' + @P1,@P1 + ';Version {2};{3}',0
FROM msdb.dbo.[sysmanagement_shared_server_groups] grpz
WHERE grpz.[name] = '_{1}_Apps'
"@ -f $results,$val,$LocalDBVersion.Key.ToString(),$LocalDBVersion.Value.ToString()
Invoke-SQLCMD -Query $SQLQuery -Database "msdb" -ServerInstance $SQLServerName -TrustServerCertificate
##now we need some base tools in our new instance!
#"SQL_005_sp_createdb.sql" --allows ceach instance to create databases with the same name (placing in subfolders)
$sqlfile = [System.IO.Path]::Combine($BasePath,'SQL_005_sp_createdb.sql')
Invoke-SQLCMD -InputFile $sqlfile -Database "master" -ServerInstance ("(LocalDB)\$results") -TrustServerCertificate
$SQLQuery = "IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = 'SandBox') EXECUTE sp_createdb 'SandBox' "
Invoke-SQLCMD -Query $SQLQuery -Database "master" -ServerInstance ("(LocalDB)\$results") -TrustServerCertificate
if($Server -ne '' -and [System.IO.Directory]::Exists($BasePath))
{
$CurrentServerName = ("(LocalDB)\$results")
$SQLDatabase = 'master'
###################################################################################################
## any files in current folder?
###################################################################################################
$AllSQLFiles = [System.IO.Directory]::GetFiles($BasePath,'*.sql') | Sort-Object
foreach($sqlfile in $AllSQLFiles)
{
try
{
$StagingFileName = "--Begin " + [System.IO.Path]::GetFileName($sqlfile)
Write-Host $StagingFileName -ForegroundColor Green
Out-File -LiteralPath $LogPath -InputObject $StagingFileName -Append -Encoding ASCII -Width 99999
if($UseSQLLogin)
{
Invoke-SQLCMD -InputFile $sqlfile -ServerInstance $CurrentServerName -Database $SQLDatabase -UserName $UserName -Password $Password -Querytimeout 0 -Verbose 4>&1 -TrustServerCertificate| Out-File -LiteralPath $LogPath -Append -Encoding ASCII -Width 99999
}
else
{
Invoke-SQLCMD -InputFile $sqlfile -ServerInstance $CurrentServerName -Database $SQLDatabase -Querytimeout 0 -Verbose 4>&1 -TrustServerCertificate| Out-File -LiteralPath $LogPath -Append -Encoding ASCII -Width 99999
}
$StagingFileName = "--End " + [System.IO.Path]::GetFileName($sqlfile)
Out-File -LiteralPath $LogPath -InputObject $StagingFileName -Append -Encoding ASCII -Width 99999
}
catch
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
$StagingFileName = "--Error " + [System.IO.Path]::GetFileName($sqlfile)
Out-File -LiteralPath $LogPath -InputObject $FailedItem -Append -Encoding ASCII -Width 99999
Out-File -LiteralPath $LogPath -InputObject $ErrorMessage -Append -Encoding ASCII -Width 99999
Out-File -LiteralPath $LogPath -InputObject $StagingFileName -Append -Encoding ASCII -Width 99999
}
}
###################################################################################################
##foreach folder single level only.
###################################################################################################
$AllDirectories = [System.IO.Directory]::GetDirectories($BasePath) | Sort-Object
foreach($CurrentDirectory in $AllDirectories)
{
$AllSQLFiles = [System.IO.Directory]::GetFiles($CurrentDirectory,'*.sql') | Sort-Object
foreach($sqlfile in $AllSQLFiles)
{
try
{
$StagingFileName = "--Begin " + $CurrentDirectory + " | " + [System.IO.Path]::GetFileName($sqlfile)
Write-Host $StagingFileName -ForegroundColor Green
Out-File -LiteralPath $LogPath -InputObject $StagingFileName -Append -Encoding ASCII -Width 99999
if($UseSQLLogin)
{
Invoke-SQLCMD -InputFile $sqlfile -ServerInstance $CurrentServerName -Database $SQLDatabase -UserName $UserName -Password $Password -Querytimeout 0 -Verbose 4>&1 -TrustServerCertificate| Out-File -LiteralPath $LogPath -Append -Encoding ASCII -Width 99999
}
else
{
Invoke-SQLCMD -InputFile $sqlfile -ServerInstance $CurrentServerName -Database $SQLDatabase -Querytimeout 0 -Verbose 4>&1 -TrustServerCertificate| Out-File -LiteralPath $LogPath -Append -Encoding ASCII -Width 99999
}
$StagingFileName = "--End " + $CurrentDirectory + " | " + [System.IO.Path]::GetFileName($sqlfile)
Out-File -LiteralPath $LogPath -InputObject $StagingFileName -Append -Encoding ASCII -Width 99999
}
catch
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
$StagingFileName = "--Error " + $CurrentDirectory + " | " + [System.IO.Path]::GetFileName($sqlfile)
Out-File -LiteralPath $LogPath -InputObject $FailedItem -Append -Encoding ASCII -Width 99999
Out-File -LiteralPath $LogPath -InputObject $ErrorMessage -Append -Encoding ASCII -Width 99999
Out-File -LiteralPath $LogPath -InputObject $StagingFileName -Append -Encoding ASCII -Width 99999
}
} #$AllSQLFiles
} #$AllDirectories
} #if($Server -ne ''
##Create Some Random Databases With Random Tables
Write-Host '--Begin EXECUTE [dbo].[sp_CreateRandomBuzzWordDatabases];' -ForegroundColor Green
$SQLQuery = "EXECUTE [dbo].[sp_CreateRandomBuzzWordDatabases];"
Invoke-SQLCMD -Query $SQLQuery -Database "master" -ServerInstance $CurrentServerName -TrustServerCertificate
Write-Host '--End EXECUTE [dbo].[sp_CreateRandomBuzzWordDatabases];' -ForegroundColor Green
} # for $ServersPerLayer
} # $CMSEnvironments
} # $AvailableSQLVersions
###################################################################################################
## Now randomly Organize the newly added Servers into The Groups
###################################################################################################
$SQLQuery = @"
DECLARE @serverGroup int
SELECT @serverGroup = server_group_id FROM msdb.dbo.sysmanagement_shared_server_groups WHERE name = 'All Applications' AND parent_id = 1
SELECT @serverGroup
IF @serverGroup > 1
EXECUTE msdb.dbo.sp_sysmanagement_delete_shared_server_group @server_group_id = @serverGroup -- int
--###################################################################################################
--##top 20 business apps for my group names
--###################################################################################################
DECLARE @GroupNames TABLE(RW int identity(1,1) NOT NULL PRIMARY KEY,GroupName VARCHAR(50) )
INSERT INTO @GroupNames(GroupName)
VALUES('Evernote'),('Wunderlist'),( 'Pocket'),('RescueTime'),( 'Toggl'),( 'Eternity Time Log'),('Basecamp'),( 'Trello'),( 'Asana'),('Slack'),( 'Stride'),( 'Skype for Business'),('Streak'),( 'Insightly'),( 'Nimble'),('Square'),( 'PayPal Here'),( 'Dwolla'),('QuickBooks Online'),( 'Freshbooks'),( 'Wave')
DECLARE @AllApplicationsID INT
IF NOT EXISTS(SELECT * FROM msdb.dbo.sysmanagement_shared_server_groups WHERE name = 'All Applications' AND parent_id = 1)
BEGIN
INSERT INTO msdb.dbo.sysmanagement_shared_server_groups([name],[description],[server_type],[parent_id])
SELECT 'All Applications','All Applications',0,1
END
SELECT @AllApplicationsID = server_group_id FROM msdb.dbo.sysmanagement_shared_server_groups WHERE name = 'All Applications' AND parent_id = 1
--create some Application Groups under 'All Applications'
INSERT INTO msdb.dbo.sysmanagement_shared_server_groups([name],[description],[server_type],[parent_id])
SELECT GroupName,GroupName,0,@AllApplicationsID
FROM @GroupNames MySource
LEFT OUTER JOIN msdb.dbo.sysmanagement_shared_server_groups MyLookup
ON MySource.GroupName = MyLookup.name AND MyLookup.parent_id = @AllApplicationsID
WHERE MyLookup.server_group_id IS NULL
--Now delete anything under those groups
DELETE srvz
FROM msdb.dbo.sysmanagement_shared_registered_servers srvz
INNER JOIN msdb.dbo.sysmanagement_shared_server_groups grpz ON srvz.server_group_id = grpz.server_group_id
INNER JOIN @GroupNames MySource ON MySource.GroupName = grpz.name AND grpz.parent_id = @AllApplicationsID
--now add anything that is under [_]%[_]Apps randomly to one of the app groups
;WITH grps
AS
(
SELECT row_number() OVER(ORDER BY (SELECT NULL)) % 20 AS RW,grpz.* FROM msdb.dbo.sysmanagement_shared_server_groups grpz
INNER JOIN msdb.dbo.sysmanagement_shared_server_groups parentz
ON grpz.parent_id = parentz.server_group_id
WHERE parentz.name = 'All Applications'
)
,srv
AS
(
SELECT row_number() OVER(ORDER BY (SELECT NULL)) % 20 AS RW,srvz.* FROM msdb.dbo.sysmanagement_shared_registered_servers srvz
INNER JOIN msdb.dbo.sysmanagement_shared_server_groups grpz ON srvz.server_group_id = grpz.server_group_id
where grpz.name LIKE '[_]%[_]Apps'
)
INSERT INTO msdb.dbo.sysmanagement_shared_registered_servers([server_group_id],[name],[server_name],[description],[server_type])
SELECT grps.[server_group_id],srv.[name],srv.[server_name],srv.[description], 0 AS [server_type] --,grps.name
FROM grps INNER JOIN srv ON grps.RW = srv.RW
"@
Invoke-SQLCMD -Query $SQLQuery -Database "msdb" -ServerInstance $SQLServerName -TrustServerCertificate