├── .gitignore ├── ConEmu.reg ├── ConEmu.xml ├── GoogleChrome-external_extensions.json ├── GoogleChrome-master_bookmarks.html ├── GoogleChrome-master_preferences.json ├── README.md ├── Security.Cryptography.dll ├── Vagrantfile ├── examples ├── csharp │ ├── Example.cs │ ├── Example.csproj │ └── run.ps1 ├── go │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── run.ps1 ├── java │ ├── build.gradle │ ├── run.ps1 │ ├── settings.gradle │ └── src │ │ └── main │ │ └── java │ │ └── Example.java ├── powershell │ ├── common.ps1 │ ├── create-database-TheSimpsons.ps1 │ ├── sqlclient.ps1 │ ├── sqlps.ps1 │ └── use-encrypted-connection.ps1 └── python │ ├── main.py │ ├── requirements.txt │ └── run.ps1 ├── provision-base.ps1 ├── provision-chocolatey.ps1 ├── provision-sql-server-management-studio.ps1 ├── provision-sql-server-network-encryption.ps1 ├── provision-sql-server.ps1 ├── ps.ps1 ├── sql-server.png └── sql-server.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/ 2 | build/ 3 | .gradle/ 4 | bin/ 5 | obj/ 6 | tmp/ 7 | *.exe 8 | -------------------------------------------------------------------------------- /ConEmu.reg: -------------------------------------------------------------------------------- 1 | Windows Registry Editor Version 5.00 2 | 3 | [HKEY_CLASSES_ROOT\*\shell\ConEmu Here] 4 | "Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0" 5 | [HKEY_CLASSES_ROOT\*\shell\ConEmu Here\command] 6 | @="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -run {MSYS2} -cur_console:n" 7 | 8 | [HKEY_CLASSES_ROOT\directory\background\shell\ConEmu Here] 9 | "Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0" 10 | [HKEY_CLASSES_ROOT\directory\background\shell\ConEmu Here\command] 11 | @="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -run {MSYS2} -cur_console:n" 12 | 13 | [HKEY_CLASSES_ROOT\directory\shell\ConEmu Here] 14 | "Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0" 15 | [HKEY_CLASSES_ROOT\directory\shell\ConEmu Here\command] 16 | @="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -dir \"%1\" -run {MSYS2} -cur_console:n" 17 | 18 | [HKEY_CLASSES_ROOT\Drive\shell\ConEmu Here] 19 | "Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0" 20 | [HKEY_CLASSES_ROOT\Drive\shell\ConEmu Here\command] 21 | @="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -dir \"%1\" -run {MSYS2} -cur_console:n" 22 | 23 | [HKEY_CLASSES_ROOT\LibraryFolder\Background\shell\ConEmu Here] 24 | "Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0" 25 | [HKEY_CLASSES_ROOT\LibraryFolder\Background\shell\ConEmu Here\command] 26 | @="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -run {MSYS2} -cur_console:n" 27 | -------------------------------------------------------------------------------- /ConEmu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | -------------------------------------------------------------------------------- /GoogleChrome-external_extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // JSON Formatter (https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa). 3 | "bcjindcccaagfpapjjmafapmmgkkhgoa": { 4 | "external_update_url": "https://clients2.google.com/service/update2/crx" 5 | }, 6 | // uBlock Origin (https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm). 7 | "cjpalhdlnbpafiamejdnhcphjbkeiagm": { 8 | "external_update_url": "https://clients2.google.com/service/update2/crx" 9 | } 10 | } -------------------------------------------------------------------------------- /GoogleChrome-master_bookmarks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Bookmarks 4 |

Bookmarks

5 |

6 |

Bookmarks bar

7 |

8 |

Channel 9: Videos for developers from the people building Microsoft Products & Services 9 |

10 |

11 | -------------------------------------------------------------------------------- /GoogleChrome-master_preferences.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "restore_on_startup": 1 4 | }, 5 | "bookmark_bar": { 6 | "show_on_all_tabs": true 7 | }, 8 | "sync_promo": { 9 | "show_on_first_run_allowed": false 10 | }, 11 | "distribution": { 12 | "import_bookmarks_from_file": "C:\\Program Files\\Google\\Chrome\\Application\\master_bookmarks.html", 13 | "import_bookmarks": true, 14 | "import_history": true, 15 | "import_home_page": true, 16 | "import_search_engine": true, 17 | "suppress_first_run_bubble": true, 18 | "do_not_create_desktop_shortcut": true, 19 | "do_not_create_quick_launch_shortcut": false, 20 | "do_not_launch_chrome": true, 21 | "do_not_register_for_update_launch": true, 22 | "make_chrome_default": true, 23 | "make_chrome_default_for_user": true, 24 | "suppress_first_run_default_browser_prompt": false, 25 | "system_level": true, 26 | "verbose_logging": true 27 | }, 28 | "first_run_tabs": [ 29 | "chrome://extensions", 30 | "chrome://version", 31 | "https://github.com/rgl", 32 | "https://ruilopes.com" 33 | ] 34 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is an example Vagrant environment for a SQL Server 2022 Express installation. 2 | 3 | It will: 4 | 5 | * Change the SQL Server Settings 6 | * Mixed mode authentication 7 | * Allow TCP/IP connections 8 | * Allow encrypted connections (using a private CA) 9 | * Create Users 10 | * SQL Server Users: `alice.doe` (in the `sysadmin` role), `carol.doe`, `eve.doe` and `grace.doe`. 11 | * Windows Users: `bob.doe`, `dave.doe`, `frank.doe` and `henry.doe`. 12 | * All have the `HeyH0Password` password. 13 | * Create the `TheSimpsons` Database 14 | * Create the `db_executor` database role with permissions to execute stored procedures. 15 | * Add users to database roles 16 | * `carol.doe` in the `db_datawriter`, `db_datareader` and `db_executor` roles. 17 | * `eve.doe` in the `db_datareader` and `db_executor` roles. 18 | * Run PowerShell, Python, Java, C# and Go [examples](examples/). 19 | 20 | 21 | # Usage 22 | 23 | Install the [Windows 2022 base box](https://github.com/rgl/windows-vagrant). 24 | 25 | Run `vagrant up --no-destroy-on-error` to launch the environment. 26 | 27 | Login into the Windows VM, open ConEmu/bash, and dump the SQL Server TLS details: 28 | 29 | ```bash 30 | # see the TLS certificate validation result: 31 | echo | openssl s_client -connect $COMPUTERNAME:1433 -servername $COMPUTERNAME -CAfile /c/vagrant/tmp/ca/example-ca-crt.pem 32 | # see the TLS certificate being returned by the server: 33 | echo | openssl s_client -connect $COMPUTERNAME:1433 -servername $COMPUTERNAME -CAfile /c/vagrant/tmp/ca/example-ca-crt.pem | openssl x509 -noout -text -in - 34 | ``` 35 | 36 | 37 | # Reference 38 | 39 | * [TDS 8.0 and TLS 1.3 support](https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/tds-8-and-tls-1-3?view=sql-server-ver16) 40 | 41 | 42 | # Example queries 43 | 44 | ## List active connections 45 | 46 | List active connections details: 47 | 48 | ```sql 49 | select 50 | c.client_net_address, 51 | s.login_name, 52 | db_name(s.database_id) as database_name, 53 | s.program_name, 54 | c.encrypt_option, 55 | c.connect_time 56 | from 57 | sys.dm_exec_connections as c 58 | inner join sys.dm_exec_sessions as s 59 | on c.session_id = s.session_id 60 | order by 61 | c.client_net_address, 62 | s.login_name, 63 | s.program_name 64 | ``` 65 | 66 | **NB** you can customize what appears on `s.program_name` by setting the `Application Name` 67 | connection string property, e.g., `Application Name=Example Application;`. 68 | 69 | ## List database principals permissions 70 | 71 | ```sql 72 | select 73 | principals.principal_id, 74 | principals.name, 75 | principals.type_desc, 76 | principals.authentication_type_desc, 77 | permissions.state_desc, 78 | permissions.permission_name 79 | from 80 | sys.database_principals as principals 81 | inner join sys.database_permissions as permissions 82 | on principals.principal_id = permissions.grantee_principal_id 83 | order by 84 | principals.name, 85 | principals.type_desc, 86 | principals.authentication_type_desc, 87 | permissions.state_desc, 88 | permissions.permission_name 89 | ``` 90 | 91 | ## List database schema tables row count 92 | 93 | ```sql 94 | select 95 | schema_name(schema_id) as schema_name, 96 | t.name as table_name, 97 | sum(p.rows) as row_count 98 | from 99 | sys.tables as t 100 | inner join sys.partitions as p 101 | on t.object_id = p.object_id 102 | and p.index_id in (0, 1) 103 | group by 104 | schema_name(schema_id), 105 | t.name 106 | ``` 107 | 108 | ## List database row count and storage usage 109 | 110 | ```sql 111 | select 112 | sum(p.rows) as row_count, 113 | (select sum(case when type = 1 then size end) * cast(8 * 1024 as bigint) from sys.master_files where database_id = db_id()) as data_size_bytes, 114 | (select sum(case when type = 0 then size end) * cast(8 * 1024 as bigint) from sys.master_files where database_id = db_id()) as log_size_bytes 115 | from 116 | sys.tables as t 117 | inner join sys.partitions as p 118 | on t.object_id = p.object_id 119 | and p.index_id in (0, 1) 120 | ``` 121 | 122 | ## List databases storage usage 123 | 124 | ```sql 125 | select 126 |   db_name(database_id) as database_name, 127 |   sum(case when type = 1 then size end) * cast(8 * 1024 as bigint) as data_size_bytes, 128 |   sum(case when type = 0 then size end) * cast(8 * 1024 as bigint) as log_size_bytes 129 | from 130 |   sys.master_files 131 | group by 132 |   database_id 133 | ``` 134 | -------------------------------------------------------------------------------- /Security.Cryptography.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rgl/sql-server-vagrant/7835ccb45fdb80800ceb8c8a6fdcef889d50347e/Security.Cryptography.dll -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | ip_address = '10.10.10.100' 2 | 3 | Vagrant.configure("2") do |config| 4 | config.vm.box = "windows-2022-amd64" 5 | 6 | config.vm.provider "libvirt" do |lv, config| 7 | lv.memory = 4*1024 8 | lv.cpus = 2 9 | lv.cpu_mode = "host-passthrough" 10 | #lv.nested = true 11 | lv.keymap = "pt" 12 | config.vm.synced_folder ".", "/vagrant", type: "smb", smb_username: ENV["USER"], smb_password: ENV["VAGRANT_SMB_PASSWORD"] 13 | end 14 | 15 | config.vm.provider "virtualbox" do |vb, config| 16 | vb.linked_clone = true 17 | vb.memory = 4*1024 18 | vb.customize ["modifyvm", :id, "--vram", 256] 19 | vb.customize ["modifyvm", :id, "--accelerate3d", "on"] 20 | vb.customize ["modifyvm", :id, "--accelerate2dvideo", "on"] 21 | vb.customize ["modifyvm", :id, "--clipboard", "bidirectional"] 22 | vb.customize ["modifyvm", :id, "--draganddrop", "bidirectional"] 23 | config.vm.synced_folder ".", "/vagrant", type: "smb", smb_username: ENV["USER"], smb_password: ENV["VAGRANT_SMB_PASSWORD"] 24 | end 25 | 26 | config.vm.hostname = 'mssql' 27 | config.vm.network :private_network, ip: ip_address 28 | config.vm.provision "shell", path: "ps.ps1", args: "provision-chocolatey.ps1" 29 | config.vm.provision "shell", path: "ps.ps1", args: "provision-base.ps1" 30 | config.vm.provision "shell", path: "ps.ps1", args: "provision-sql-server.ps1" 31 | config.vm.provision "shell", path: "ps.ps1", args: ["provision-sql-server-network-encryption.ps1", ip_address] 32 | config.vm.provision "shell", path: "ps.ps1", args: "provision-sql-server-management-studio.ps1" 33 | config.vm.provision "shell", path: "ps.ps1", args: "examples/powershell/sqlps.ps1" 34 | config.vm.provision "shell", path: "ps.ps1", args: "examples/powershell/sqlclient.ps1" 35 | config.vm.provision "shell", path: "ps.ps1", args: "examples/powershell/create-database-TheSimpsons.ps1" 36 | config.vm.provision "shell", path: "ps.ps1", args: "examples/powershell/use-encrypted-connection.ps1" 37 | config.vm.provision "shell", path: "ps.ps1", args: "examples/python/run.ps1" 38 | config.vm.provision "shell", path: "ps.ps1", args: "examples/java/run.ps1" 39 | config.vm.provision "shell", path: "ps.ps1", args: "examples/csharp/run.ps1" 40 | config.vm.provision "shell", path: "ps.ps1", args: "examples/go/run.ps1" 41 | end 42 | -------------------------------------------------------------------------------- /examples/csharp/Example.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Data.SqlClient; 3 | 4 | class Example 5 | { 6 | static void Main(string[] args) 7 | { 8 | Console.WriteLine("SQL Server Version:"); 9 | Console.WriteLine(SqlExecuteScalar(@"Server=.\SQLEXPRESS; Database=master; Integrated Security=true", "select @@version")); 10 | 11 | Console.WriteLine("SQL Server User Name (integrated Windows authentication credentials) with .NET SqlClient:"); 12 | Console.WriteLine(SqlExecuteScalar(@"Server=.\SQLEXPRESS; Database=master; Integrated Security=true", "select suser_name()")); 13 | 14 | string tcpIpConnectionString = string.Format( 15 | "Server={0},1433; User ID=alice.doe; Password=HeyH0Password; Database=master", 16 | Environment.GetEnvironmentVariable("COMPUTERNAME")); 17 | 18 | Console.WriteLine("SQL Server User Name (alice.doe; username/password credentials; TCP/IP connection) with .NET SqlClient:"); 19 | Console.WriteLine(SqlExecuteScalar(tcpIpConnectionString, "select suser_name()")); 20 | 21 | Console.WriteLine("Is this SQL Server connection encrypted? (alice.doe; username/password credentials; Encrypted TCP/IP connection):"); 22 | Console.WriteLine(SqlExecuteScalar(tcpIpConnectionString + "; Encrypt=strict", "select encrypt_option from sys.dm_exec_connections where session_id=@@SPID")); 23 | } 24 | 25 | private static object SqlExecuteScalar(string connectionString, string sql) 26 | { 27 | using (var connection = new SqlConnection(connectionString)) 28 | { 29 | connection.Open(); 30 | 31 | using (var command = connection.CreateCommand()) 32 | { 33 | command.CommandText = sql; 34 | return command.ExecuteScalar(); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/csharp/Example.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/csharp/run.ps1: -------------------------------------------------------------------------------- 1 | if (!(Get-Command -ErrorAction SilentlyContinue dotnet.exe) -or !(dotnet --list-sdks)) { 2 | # see https://dotnet.microsoft.com/en-us/download/dotnet/6.0 3 | # see https://github.com/dotnet/core/blob/main/release-notes/6.0/6.0.20/6.0.20.md 4 | 5 | # opt-out from dotnet telemetry. 6 | [Environment]::SetEnvironmentVariable('DOTNET_CLI_TELEMETRY_OPTOUT', '1', 'Machine') 7 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = '1' 8 | 9 | # install the dotnet sdk. 10 | $archiveUrl = 'https://download.visualstudio.microsoft.com/download/pr/6a7d9254-d184-41a1-91fc-00ed876297a9/9db88f1a5fe2375b8c389d7087db132e/dotnet-sdk-6.0.412-win-x64.exe' 11 | $archiveHash = '7465163a2681b37bf164c6a257fc72e3865c98ed56a6a1a378302c91a0482a9c3405ca5adae46d3cd93859751b8724a0f67aa942e8a982e52a65306556c2a3ab' 12 | $archiveName = Split-Path -Leaf $archiveUrl 13 | $archivePath = "$env:TEMP\$archiveName" 14 | Write-Host "Downloading $archiveName..." 15 | (New-Object Net.WebClient).DownloadFile($archiveUrl, $archivePath) 16 | $archiveActualHash = (Get-FileHash $archivePath -Algorithm SHA512).Hash 17 | if ($archiveHash -ne $archiveActualHash) { 18 | throw "$archiveName downloaded from $archiveUrl to $archivePath has $archiveActualHash hash witch does not match the expected $archiveHash" 19 | } 20 | Write-Host "Installing $archiveName..." 21 | &$archivePath /install /quiet /norestart | Out-String -Stream 22 | if ($LASTEXITCODE) { 23 | throw "Failed to install dotnet-sdk with Exit Code $LASTEXITCODE" 24 | } 25 | Remove-Item $archivePath 26 | 27 | # reload PATH. 28 | $env:PATH = "$([Environment]::GetEnvironmentVariable('PATH', 'Machine'));$([Environment]::GetEnvironmentVariable('PATH', 'User'))" 29 | 30 | # add the nuget.org source. 31 | # see https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-add-source 32 | Write-Host "Adding the nuget nuget.org source..." 33 | dotnet nuget add source --name nuget.org https://api.nuget.org/v3/index.json 34 | dotnet nuget list source 35 | } 36 | 37 | # show information about dotnet. 38 | dotnet --info 39 | 40 | # restore the packages. 41 | dotnet restore 42 | 43 | # build and run. 44 | dotnet --diagnostics build --configuration Release 45 | dotnet --diagnostics run --configuration Release 46 | -------------------------------------------------------------------------------- /examples/go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rgl/sql-server-vagrant/examples/go 2 | 3 | go 1.20 4 | 5 | require github.com/denisenkom/go-mssqldb v0.12.3 6 | 7 | require ( 8 | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect 9 | github.com/golang-sql/sqlexp v0.1.0 // indirect 10 | golang.org/x/crypto v0.3.0 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /examples/go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= 2 | github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= 3 | github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= 7 | github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= 8 | github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= 9 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 10 | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= 11 | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 12 | github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= 13 | github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= 14 | github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= 15 | github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= 16 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 17 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 18 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 19 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 20 | golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 21 | golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 22 | golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= 23 | golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= 24 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 25 | golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 26 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 27 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 28 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 29 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 30 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 31 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 32 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 33 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 34 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 35 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 36 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 37 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 38 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 39 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 40 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 41 | -------------------------------------------------------------------------------- /examples/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "log" 7 | "os" 8 | 9 | _ "github.com/denisenkom/go-mssqldb" 10 | ) 11 | 12 | func sqlExecuteScalar(connectionString string, sqlStatement string) string { 13 | db, err := sql.Open("sqlserver", connectionString) 14 | if err != nil { 15 | log.Fatal("Open connection failed:", err.Error()) 16 | } 17 | defer db.Close() 18 | 19 | err = db.Ping() 20 | if err != nil { 21 | log.Fatal("Ping failed:", err.Error()) 22 | } 23 | 24 | var scalar string 25 | 26 | err = db.QueryRow(sqlStatement).Scan(&scalar) 27 | if err != nil { 28 | log.Fatal("Scan failed:", err.Error()) 29 | } 30 | 31 | return scalar 32 | } 33 | 34 | func main() { 35 | connectionString := fmt.Sprintf( 36 | "Server=%s; Port=1433; Database=master; User ID=alice.doe; Password=HeyH0Password", 37 | os.Getenv("COMPUTERNAME")) 38 | 39 | fmt.Println("SQL Server Version:") 40 | fmt.Println(sqlExecuteScalar(connectionString, "select @@version")) 41 | 42 | fmt.Println("SQL Server User Name (alice.doe; username/password credentials; TCP/IP connection):") 43 | fmt.Println(sqlExecuteScalar(connectionString, "select suser_name()")) 44 | 45 | fmt.Println("Is this SQL Server connection encrypted? (alice.doe; username/password credentials; Encrypted TCP/IP connection):") 46 | fmt.Println(sqlExecuteScalar(connectionString+"; Encrypt=true", "select encrypt_option from sys.dm_exec_connections where session_id=@@SPID")) 47 | } 48 | -------------------------------------------------------------------------------- /examples/go/run.ps1: -------------------------------------------------------------------------------- 1 | # install go. 2 | # see https://community.chocolatey.org/packages/golang 3 | choco install -y golang --version 1.20.6 4 | 5 | # setup the current process environment. 6 | $env:GOROOT = 'C:\Program Files\Go' 7 | $env:PATH += ";$env:GOROOT\bin" 8 | 9 | # setup the Machine environment. 10 | [Environment]::SetEnvironmentVariable('GOROOT', $env:GOROOT, 'Machine') 11 | [Environment]::SetEnvironmentVariable( 12 | 'PATH', 13 | "$([Environment]::GetEnvironmentVariable('PATH', 'Machine'));$env:GOROOT\bin", 14 | 'Machine') 15 | 16 | Write-Host '# go env' 17 | go env 18 | 19 | Write-Host '# build and run' 20 | Start-Example go { 21 | $p = Start-Process go 'build','-v' ` 22 | -RedirectStandardOutput build-stdout.txt ` 23 | -RedirectStandardError build-stderr.txt ` 24 | -Wait ` 25 | -PassThru 26 | Write-Output (Get-Content build-stdout.txt,build-stderr.txt) 27 | Remove-Item build-stdout.txt,build-stderr.txt 28 | if ($p.ExitCode) { 29 | throw "Failed to compile" 30 | } 31 | .\go.exe 32 | } 33 | -------------------------------------------------------------------------------- /examples/java/build.gradle: -------------------------------------------------------------------------------- 1 | // see https://docs.gradle.org/8.1/userguide/java_plugin.html 2 | // see https://docs.gradle.org/8.1/userguide/application_plugin.html 3 | // see https://docs.gradle.org/8.1/userguide/building_java_projects.html#sec:java_dependency_management_overview 4 | // see https://github.com/johnrengelman/shadow 5 | 6 | plugins { 7 | id 'com.github.johnrengelman.shadow' version '8.1.1' 8 | } 9 | 10 | apply plugin: 'com.github.johnrengelman.shadow' 11 | apply plugin: 'application' 12 | 13 | mainClassName = 'Example' 14 | version = '1.0.0' 15 | sourceCompatibility = 17 16 | targetCompatibility = 17 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | // see https://github.com/microsoft/mssql-jdbc/releases/tag/v11.2.3 24 | // see https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc/11.2.3.jre17 25 | implementation "com.microsoft.sqlserver:mssql-jdbc:11.2.3.jre${targetCompatibility}" 26 | } 27 | -------------------------------------------------------------------------------- /examples/java/run.ps1: -------------------------------------------------------------------------------- 1 | # use the Windows Trust store (set to $false to use java cacerts). 2 | $useWindowsTrustStore = $true 3 | 4 | # install dependencies. 5 | # see https://community.chocolatey.org/packages/temurin17 6 | # see https://community.chocolatey.org/packages/gradle 7 | choco install -y temurin17 8 | choco install -y gradle --version 8.1.1 9 | 10 | # install the SQL Server JDBC Auth driver. 11 | # see https://github.com/Microsoft/mssql-jdbc 12 | $archiveVersion = '11.2.3' 13 | $archiveUrl = "https://github.com/microsoft/mssql-jdbc/releases/download/v$archiveVersion/mssql-jdbc_auth.zip" 14 | $archivePath = "$env:TEMP\mssql-jdbc_auth-$archiveVersion.zip" 15 | if (Test-Path $archivePath) { 16 | Remove-Item $archivePath | Out-Null 17 | } 18 | (New-Object Net.WebClient).DownloadFile($archiveUrl, $archivePath) 19 | $jdbcAuthPath = 'C:\Program Files\mssql-jdbc_auth' 20 | if (Test-Path $jdbcAuthPath) { 21 | Remove-Item -Recurse -Force $jdbcAuthPath | Out-Null 22 | } 23 | Expand-Archive $archivePath $jdbcAuthPath 24 | 25 | # update $env:PATH with the recently installed Chocolatey packages. 26 | Import-Module C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1 27 | Update-SessionEnvironment 28 | 29 | # add our Example CA certificate to the default java trust store. 30 | if (!$useWindowsTrustStore) { 31 | @( 32 | 'C:\Program Files\*\*\lib\security\cacerts' 33 | ) | ForEach-Object {Get-ChildItem $_} | ForEach-Object { 34 | $keyStore = $_ 35 | $alias = 'Example CA' 36 | $keytool = Resolve-Path "$keyStore\..\..\..\bin\keytool.exe" 37 | $keytoolOutput = &$keytool ` 38 | -noprompt ` 39 | -list ` 40 | -storepass changeit ` 41 | -cacerts ` 42 | -alias "$alias" 43 | if ($keytoolOutput -match 'keytool error: java.lang.Exception: Alias .+ does not exist') { 44 | Write-Host "Adding $alias to the java $keyStore keystore..." 45 | # NB we use Start-Process because keytool writes to stderr... and that 46 | # triggers PowerShell to fail, so we work around this by redirecting 47 | # stdout and stderr to a temporary file. 48 | # NB keytool exit code is always 1, so we cannot rely on that. 49 | Start-Process ` 50 | -FilePath $keytool ` 51 | -ArgumentList ` 52 | '-noprompt', 53 | '-import', 54 | '-trustcacerts', 55 | '-storepass changeit', 56 | '-cacerts', 57 | "-alias `"$alias`"", 58 | '-file c:\vagrant\tmp\ca\example-ca-crt.der' ` 59 | -RedirectStandardOutput "$env:TEMP\keytool-stdout.txt" ` 60 | -RedirectStandardError "$env:TEMP\keytool-stderr.txt" ` 61 | -NoNewWindow ` 62 | -Wait 63 | $keytoolOutput = Get-Content -Raw "$env:TEMP\keytool-stdout.txt","$env:TEMP\keytool-stderr.txt" 64 | if ($keytoolOutput -notmatch 'Certificate was added to keystore') { 65 | Write-Host $keytoolOutput 66 | throw "failed to import Example CA" 67 | } 68 | } elseif ($LASTEXITCODE) { 69 | Write-Host $keytoolOutput 70 | throw "failed to list Example CA with exit code $LASTEXITCODE" 71 | } 72 | } 73 | } 74 | 75 | # build into a fat jar. 76 | # NB gradle build would also work, but having a fat jar is nicier for distribution. 77 | gradle --no-daemon shadowJar 78 | 79 | # run the example. 80 | # NB gradle run would also work, but this shows how a user would use the fat jar. 81 | # NB for using the integrated authentication we must have sqljdbc_auth.dll in the 82 | # current directory, %PATH%, or inside one of the directories defined in the 83 | # java.library.path java property (as done here; it points to the drivers 84 | # installed from github above). 85 | $javaLibraryPath = "$jdbcAuthPath\x64" 86 | java ` 87 | "-Djava.library.path=$javaLibraryPath" ` 88 | $(if ($useWindowsTrustStore) {'-Djavax.net.ssl.trustStoreType=Windows-ROOT'} else {$null}) ` 89 | -jar build/libs/example-1.0.0-all.jar 90 | -------------------------------------------------------------------------------- /examples/java/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'example' 2 | -------------------------------------------------------------------------------- /examples/java/src/main/java/Example.java: -------------------------------------------------------------------------------- 1 | // see https://github.com/Microsoft/mssql-jdbc 2 | import java.sql.Connection; 3 | import java.sql.DriverManager; 4 | import java.sql.ResultSet; 5 | import java.sql.Statement; 6 | 7 | public class Example { 8 | public static void main(String[] args) throws Exception { 9 | String integratedSecurityConnectionString = String.format( 10 | "jdbc:sqlserver://%s:1433;database=master;integratedSecurity=true;", 11 | System.getenv("COMPUTERNAME")); 12 | 13 | System.out.println("SQL Server Version:"); 14 | System.out.println(queryScalar(integratedSecurityConnectionString, "select @@version")); 15 | 16 | System.out.println("SQL Server User Name (integrated authentication credentials; TCP/IP connection):"); 17 | System.out.println(queryScalar(integratedSecurityConnectionString, "select suser_name()")); 18 | 19 | String connectionString = String.format( 20 | "jdbc:sqlserver://%s:1433;database=master;user=alice.doe;password=HeyH0Password;", 21 | System.getenv("COMPUTERNAME")); 22 | 23 | System.out.println("SQL Server User Name (alice.doe; username/password credentials; TCP/IP connection):"); 24 | System.out.println(queryScalar(connectionString, "select suser_name()")); 25 | 26 | System.out.println("Is this SQL Server connection encrypted? (alice.doe; username/password credentials; Encrypted TCP/IP connection):"); 27 | System.out.println(queryScalar(connectionString + ";encrypt=strict", "select encrypt_option from sys.dm_exec_connections where session_id=@@SPID")); 28 | } 29 | 30 | private static String queryScalar(String connectionString, String sql) throws Exception { 31 | try (Connection connection = DriverManager.getConnection(connectionString)) { 32 | try (Statement statement = connection.createStatement()) { 33 | try (ResultSet resultSet = statement.executeQuery(sql)) { 34 | if (resultSet.next()) { 35 | return resultSet.getString(1); 36 | } 37 | return null; 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/powershell/common.ps1: -------------------------------------------------------------------------------- 1 | # NB to be able to connect to SQL Server you must install the sql2014-powershell 2 | # chocolatey package. We don't do it here because this machine already has the 3 | # sqlps PowerShell module (installed by the SQL Server installer). 4 | 5 | # load the SQL Server PowerShell provider and related Smo .NET assemblies. 6 | Push-Location # save the current location... 7 | Import-Module Sqlps -DisableNameChecking # ... because importing the module changes the current directory to "SQLSERVER:" 8 | Pop-Location # ... and we do not want that. 9 | 10 | # helper function to execute a scalar returning sql statement. 11 | function SqlExecuteScalar($connectionString, $sql) { 12 | $connection = New-Object System.Data.SqlClient.SqlConnection $connectionString 13 | $connection.Open() 14 | try { 15 | $command = $connection.CreateCommand() 16 | try { 17 | $command.CommandText = $sql 18 | return $command.ExecuteScalar() 19 | } 20 | finally { 21 | $command.Dispose() 22 | } 23 | } finally { 24 | $connection.Dispose() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/powershell/create-database-TheSimpsons.ps1: -------------------------------------------------------------------------------- 1 | . .\common.ps1 2 | 3 | $serverInstance = '.\SQLEXPRESS' 4 | $databaseName = 'TheSimpsons' 5 | 6 | Write-Host "Creating the $databaseName database..." 7 | $database = New-Object Microsoft.SqlServer.Management.Smo.Database $serverInstance,$databaseName 8 | $database.Create() 9 | $database.Refresh() 10 | 11 | Write-Host "Creating the db_executor role in the $databaseName database..." 12 | $role = New-Object Microsoft.SqlServer.Management.Smo.DatabaseRole $database,'db_executor' 13 | $role.Create() 14 | $rolePermissions = New-Object Microsoft.SqlServer.Management.Smo.DatabasePermissionSet 15 | $rolePermissions.Add([Microsoft.SqlServer.Management.Smo.DatabasePermission]::Execute) | Out-Null 16 | $database.Grant($rolePermissions, $role.Name) 17 | 18 | Write-Host 'Creating databases users and assigning roles...' 19 | @{ 20 | 'carol.doe' = @('db_datawriter', 'db_datareader', 'db_executor') 21 | 'eve.doe' = @('db_datareader', 'db_executor') 22 | }.GetEnumerator() | ForEach-Object { 23 | $userName = $_.Name 24 | $userRoles = $_.Value 25 | 26 | Write-Host "Creating the $userName database user..." 27 | $user = New-Object Microsoft.SqlServer.Management.Smo.User $database,$userName 28 | $user.Login = $userName 29 | $user.Create() 30 | 31 | $userRoles | ForEach-Object { 32 | Write-Host "Adding the $userName user to the $_ database role..." 33 | $role = $database.Roles[$_] 34 | $role.AddMember($userName) 35 | $role.Alter() 36 | } 37 | } 38 | 39 | Write-Host "Creating the $databaseName schema..." 40 | $r = Invoke-Sqlcmd -ServerInstance $serverInstance -Database $databaseName -Query @' 41 | create table Character( 42 | Id nvarchar(255) not null, 43 | Name nvarchar(80) not null, 44 | Gender varchar(10) not null); 45 | go 46 | create procedure GetTotalCharactersByGender 47 | @gender varchar(10) 48 | as 49 | set nocount on; 50 | select 51 | count(*) as Total 52 | from 53 | Character 54 | where 55 | Gender=@gender; 56 | go 57 | '@ 58 | 59 | Write-Host 'Getting The Simpsons characters...' 60 | $q = @' 61 | select ?s ?name ?gender where { 62 | wd:Q886 wdt:P674 ?s. 63 | ?s rdfs:label ?name filter(lang(?name) = 'en'). 64 | ?s wdt:P21 ?_gender. 65 | ?_gender rdfs:label ?gender filter(lang(?gender) = 'en'). 66 | } 67 | order by asc(?name) 68 | '@ 69 | $r = Invoke-RestMethod "https://query.wikidata.org/sparql?query=$([Uri]::EscapeDataString($q))&format=json" 70 | $theSimpsons = $r.results.bindings | ForEach-Object { 71 | New-Object PSObject -Property @{ 72 | Id = $_.s.value 73 | Name = $_.name.value 74 | Gender = $_.gender.value}} 75 | 76 | Write-Host "Populating the $databaseName database..." 77 | $connection = New-Object System.Data.SqlClient.SqlConnection "Server=$serverInstance; Database=$databaseName; Integrated Security=true" 78 | $connection.Open() 79 | try { 80 | $command = $connection.CreateCommand() 81 | try { 82 | $idParameter = $command.Parameters.Add('@Id', [System.Data.SqlDbType]::NVarChar, 255) 83 | $nameParameter = $command.Parameters.Add('@Name', [System.Data.SqlDbType]::NVarChar, 80) 84 | $genderParameter = $command.Parameters.Add('@Gender', [System.Data.SqlDbType]::VarChar, 10) 85 | $command.CommandText = 'insert into Character(Id, Name, Gender) values(@Id, @Name, @Gender)' 86 | $command.Prepare() 87 | $theSimpsons | ForEach-Object { 88 | $idParameter.Value = $_.Id 89 | $nameParameter.Value = $_.Name 90 | $genderParameter.Value = $_.Gender 91 | $rowsAffected = $command.ExecuteNonQuery() 92 | if ($rowsAffected -ne 1) { 93 | throw "failed to insert Character into the database" 94 | } 95 | } 96 | } 97 | finally { 98 | $command.Dispose() 99 | } 100 | } finally { 101 | $connection.Dispose() 102 | } 103 | 104 | # execute the GetTotalCharactersByGender stored procedure. 105 | 'male','female' | ForEach-Object { 106 | $r = Invoke-Sqlcmd ` 107 | -ServerInstance $serverInstance ` 108 | -Database $databaseName ` 109 | -Username eve.doe ` 110 | -Password HeyH0Password ` 111 | -Query "exec GetTotalCharactersByGender '$_'" 112 | Write-Host "There are $($r.Total) $_ characters on the $databaseName database" 113 | } 114 | -------------------------------------------------------------------------------- /examples/powershell/sqlclient.ps1: -------------------------------------------------------------------------------- 1 | . .\common.ps1 2 | 3 | Write-Host 'SQL Server Version:' 4 | Write-Host (SqlExecuteScalar 'Server=.\SQLEXPRESS; Database=master; Integrated Security=true' 'select @@version') 5 | 6 | Write-Host 'SQL Server User Name (integrated Windows authentication credentials) with .NET SqlClient:' 7 | Write-Host (SqlExecuteScalar 'Server=.\SQLEXPRESS; Database=master; Integrated Security=true' 'select suser_name()') 8 | 9 | Write-Host 'SQL Server User Name (alice.doe; username/password credentials; TCP/IP connection) with .NET SqlClient:' 10 | Write-Host (SqlExecuteScalar 'Server=localhost,1433; User ID=alice.doe; Password=HeyH0Password; Database=master' 'select suser_name()') 11 | -------------------------------------------------------------------------------- /examples/powershell/sqlps.ps1: -------------------------------------------------------------------------------- 1 | . .\common.ps1 2 | 3 | Write-Host 'SQL Server Version:' 4 | (Invoke-Sqlcmd -ServerInstance .\SQLEXPRESS -Query 'select @@version as value').value 5 | 6 | Write-Host 'SQL Server User Name (integrated Windows authentication credentials):' 7 | (Invoke-Sqlcmd -ServerInstance .\SQLEXPRESS -Query 'select suser_name() as value').value 8 | 9 | Write-Host 'SQL Server User Name (alice.doe; username/password credentials; TCP/IP connection):' 10 | (Invoke-Sqlcmd -ServerInstance 'localhost,1433' -Username alice.doe -Password HeyH0Password -Query 'select suser_name() as value').value 11 | -------------------------------------------------------------------------------- /examples/powershell/use-encrypted-connection.ps1: -------------------------------------------------------------------------------- 1 | . .\common.ps1 2 | 3 | $encryptOptionQuery = 'select encrypt_option from sys.dm_exec_connections where session_id=@@SPID' 4 | 5 | Write-Host 'Asserting that the SQL Server connection is encrypted (Invoke-Sqlcmd; alice.doe; username/password credentials; Encrypted TCP/IP connection)...' 6 | $encryptOption = (Invoke-Sqlcmd ` 7 | -ServerInstance "$env:COMPUTERNAME,1433" ` 8 | -EncryptConnection ` 9 | -Username alice.doe ` 10 | -Password HeyH0Password ` 11 | -Query $encryptOptionQuery).encrypt_option 12 | if ($encryptOption -ne 'TRUE') { 13 | throw "expecting the connection encrypt_option to be TRUE but its $encryptOption" 14 | } 15 | 16 | Write-Host 'Asserting that the SQL Server connection is encrypted (SqlClient; alice.doe; username/password credentials; Encrypted TCP/IP connection)...' 17 | # NB you can also use TrustServerCertificate=true for testing purposes (but never do that in production). 18 | $encryptOption = SqlExecuteScalar "Server=$env:COMPUTERNAME,1433; Encrypt=true; User ID=alice.doe; Password=HeyH0Password; Database=master" $encryptOptionQuery 19 | if ($encryptOption -ne 'TRUE') { 20 | throw "expecting the connection encrypt_option to be TRUE but its $encryptOption" 21 | } 22 | -------------------------------------------------------------------------------- /examples/python/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pyodbc 3 | 4 | # see http://mkleehammer.github.io/pyodbc/ 5 | def sql_execute_scalar(connection_string, sql): 6 | with pyodbc.connect(connection_string) as connection: 7 | with connection.cursor() as cursor: 8 | cursor.execute(sql) 9 | return cursor.fetchval() 10 | 11 | connection_string = 'DRIVER={ODBC Driver 18 for SQL Server};SERVER=%s;PORT=1433;DATABASE=master;UID=alice.doe;PWD=HeyH0Password' % os.environ['COMPUTERNAME'] 12 | 13 | print('SQL Server Version:') 14 | print(sql_execute_scalar(connection_string, 'select @@version')) 15 | 16 | print('SQL Server User Name (alice.doe; username/password credentials; TCP/IP connection):') 17 | print(sql_execute_scalar(connection_string, 'select suser_name()')) 18 | 19 | print('Is this SQL Server connection encrypted? (alice.doe; username/password credentials; Encrypted TCP/IP connection):') 20 | print(sql_execute_scalar(connection_string + ';Encrypt=strict', 'select encrypt_option from sys.dm_exec_connections where session_id=@@SPID')) 21 | -------------------------------------------------------------------------------- /examples/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # see https://pypi.org/project/pyodbc/ 2 | pyodbc==4.0.39 3 | -------------------------------------------------------------------------------- /examples/python/run.ps1: -------------------------------------------------------------------------------- 1 | # install the odbc driver. 2 | # NB when you change this version, you might also need to update the connection 3 | # string in main.py (to a name returned by the Get-OdbcDriver cmdlet). 4 | # see https://community.chocolatey.org/packages/sqlserver-odbcdriver 5 | choco install -y sqlserver-odbcdriver --version 18.2.1.1 6 | 7 | # list the installed odbc drivers. 8 | Get-OdbcDriver -Platform '64-bit' ` 9 | | Sort-Object Name ` 10 | | Format-Table Name 11 | 12 | # install python. 13 | # see https://community.chocolatey.org/packages/python 14 | choco install -y python --version 3.11.4 15 | 16 | # update $env:PATH with the recently installed Chocolatey packages. 17 | Import-Module C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1 18 | Update-SessionEnvironment 19 | 20 | # install the example dependencies. 21 | python -m pip -q install -r requirements.txt 22 | 23 | # run the example. 24 | python main.py 25 | -------------------------------------------------------------------------------- /provision-base.ps1: -------------------------------------------------------------------------------- 1 | # set keyboard layout. 2 | # NB you can get the name from the list: 3 | # [Globalization.CultureInfo]::GetCultures('InstalledWin32Cultures') | Out-GridView 4 | Set-WinUserLanguageList pt-PT -Force 5 | 6 | # set the date format, number format, etc. 7 | Set-Culture pt-PT 8 | 9 | # set the welcome screen culture and keyboard layout. 10 | # NB the .DEFAULT key is for the local SYSTEM account (S-1-5-18). 11 | New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS | Out-Null 12 | 'Control Panel\International','Keyboard Layout' | ForEach-Object { 13 | Remove-Item -Path "HKU:.DEFAULT\$_" -Recurse -Force 14 | Copy-Item -Path "HKCU:$_" -Destination "HKU:.DEFAULT\$_" -Recurse -Force 15 | } 16 | 17 | # set the timezone. 18 | # tzutil /l lists all available timezone ids 19 | & $env:windir\system32\tzutil /s "GMT Standard Time" 20 | 21 | # show window content while dragging. 22 | Set-ItemProperty -Path 'HKCU:Control Panel\Desktop' -Name DragFullWindows -Value 1 23 | 24 | # show hidden files. 25 | Set-ItemProperty -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name Hidden -Value 1 26 | 27 | # show file extensions. 28 | Set-ItemProperty -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name HideFileExt -Value 0 29 | 30 | # display full path in the title bar. 31 | New-Item -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState -Force ` 32 | | New-ItemProperty -Name FullPath -Value 1 -PropertyType DWORD ` 33 | | Out-Null 34 | 35 | Write-Host 'Setting the Desktop Background...' 36 | Add-Type -AssemblyName System.Drawing 37 | $backgroundColor = [System.Drawing.Color]::FromArgb(30, 30, 30) 38 | $backgroundPath = 'C:\Windows\Web\Wallpaper\Windows\sql-server.png' 39 | $logo = [System.Drawing.Image]::FromFile((Resolve-Path 'sql-server.png')) 40 | $b = New-Object System.Drawing.Bitmap($logo.Width, $logo.Height) 41 | $g = [System.Drawing.Graphics]::FromImage($b) 42 | $g.Clear($backgroundColor) 43 | $g.DrawImage($logo, 0, 0, $logo.Width, $logo.Height) 44 | $b.Save($backgroundPath) 45 | Set-ItemProperty -Path 'HKCU:Control Panel\Desktop' -Name Wallpaper -Value $backgroundPath 46 | Set-ItemProperty -Path 'HKCU:Control Panel\Desktop' -Name WallpaperStyle -Value 0 47 | Set-ItemProperty -Path 'HKCU:Control Panel\Desktop' -Name TileWallpaper -Value 0 48 | Set-ItemProperty -Path 'HKCU:Control Panel\Colors' -Name Background -Value ($backgroundColor.R,$backgroundColor.G,$backgroundColor.B -join ' ') 49 | Add-Type @' 50 | using System; 51 | using System.Drawing; 52 | using System.Runtime.InteropServices; 53 | 54 | public static class WindowsWallpaper 55 | { 56 | private const int COLOR_DESKTOP = 0x01; 57 | 58 | [DllImport("user32", SetLastError=true)] 59 | private static extern bool SetSysColors(int cElements, int[] lpaElements, int[] lpaRgbValues); 60 | 61 | private const uint SPI_SETDESKWALLPAPER = 0x14; 62 | private const uint SPIF_UPDATEINIFILE = 0x01; 63 | private const uint SPIF_SENDWININICHANGE = 0x02; 64 | 65 | [DllImport("user32", SetLastError=true)] 66 | private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, string pvParam, uint fWinIni); 67 | 68 | public static void Set(Color color, string path) 69 | { 70 | var elements = new int[] { COLOR_DESKTOP }; 71 | var colors = new int[] { ColorTranslator.ToWin32(color) }; 72 | SetSysColors(elements.Length, elements, colors); 73 | SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_SENDWININICHANGE); 74 | } 75 | } 76 | '@ -ReferencedAssemblies System.Drawing 77 | [WindowsWallpaper]::Set($backgroundColor, $backgroundPath) 78 | 79 | Write-Host 'Setting the Lock Screen Background...' 80 | $backgroundPath = 'C:\Windows\Web\Screen\lock-screen.png' 81 | Copy-Item 'sql-server.png' $backgroundPath 82 | New-Item -Path HKLM:Software\Policies\Microsoft\Windows\Personalization -Force ` 83 | | New-ItemProperty -Name LockScreenImage -Value $backgroundPath ` 84 | | New-ItemProperty -Name PersonalColors_Background -Value '#1e1e1e' ` 85 | | New-ItemProperty -Name PersonalColors_Accent -Value '#007acc' ` 86 | | Out-Null 87 | 88 | # add support for installing powershell modules from powershellgallery. 89 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force | Out-Null 90 | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 91 | 92 | # replace notepad with notepad3. 93 | choco install -y notepad3 94 | 95 | # install 7zip. 96 | choco install -y 7zip.install 97 | 98 | # install git. 99 | choco install -y git --params '/GitOnlyOnPath /NoAutoCrlf /SChannel' 100 | choco install -y gitextensions 101 | choco install -y meld 102 | 103 | # update $env:PATH with the recently installed Chocolatey packages. 104 | Import-Module C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1 105 | Update-SessionEnvironment 106 | 107 | # configure git. 108 | # see http://stackoverflow.com/a/12492094/477532 109 | git config --global user.name 'Rui Lopes' 110 | git config --global user.email 'rgl@ruilopes.com' 111 | git config --global push.default simple 112 | git config --global core.autocrlf false 113 | git config --global diff.guitool meld 114 | git config --global difftool.meld.path 'C:/Program Files (x86)/Meld/Meld.exe' 115 | git config --global difftool.meld.cmd '\"C:/Program Files (x86)/Meld/Meld.exe\" \"$LOCAL\" \"$REMOTE\"' 116 | git config --global merge.tool meld 117 | git config --global mergetool.meld.path 'C:/Program Files (x86)/Meld/Meld.exe' 118 | git config --global mergetool.meld.cmd '\"C:/Program Files (x86)/Meld/Meld.exe\" \"$LOCAL\" \"$BASE\" \"$REMOTE\" --auto-merge --output \"$MERGED\"' 119 | #git config --list --show-origin 120 | 121 | # install Visual Studio Code. 122 | choco install -y vscode 123 | Update-SessionEnvironment 124 | code --install-extension ms-mssql.mssql 125 | code --install-extension ms-vscode.PowerShell 126 | 127 | # install Google Chrome. 128 | # see https://www.chromium.org/administrators/configuring-other-preferences 129 | choco install -y googlechrome 130 | $chromeLocation = 'C:\Program Files\Google\Chrome\Application' 131 | cp -Force GoogleChrome-external_extensions.json (Resolve-Path "$chromeLocation\*\default_apps\external_extensions.json") 132 | cp -Force GoogleChrome-master_preferences.json "$chromeLocation\master_preferences" 133 | cp -Force GoogleChrome-master_bookmarks.html "$chromeLocation\master_bookmarks.html" 134 | 135 | # set the default browser to chrome. 136 | choco install -y SetDefaultBrowser 137 | SetDefaultBrowser HKLM "Google Chrome" 138 | 139 | # install msys2. 140 | choco install -y msys2 141 | 142 | # configure the msys2 launcher to let the shell inherith the PATH. 143 | $msys2BasePath = 'C:\tools\msys64' 144 | $msys2ConfigPath = "$msys2BasePath\msys2.ini" 145 | [IO.File]::WriteAllText( 146 | $msys2ConfigPath, 147 | ([IO.File]::ReadAllText($msys2ConfigPath) ` 148 | -replace '#?(MSYS2_PATH_TYPE=).+','$1inherit') 149 | ) 150 | 151 | # configure msys2 to mount C:\Users at /home. 152 | [IO.File]::WriteAllText( 153 | "$msys2BasePath\etc\nsswitch.conf", 154 | ([IO.File]::ReadAllText("$msys2BasePath\etc\nsswitch.conf") ` 155 | -replace '(db_home: ).+','$1windows') 156 | ) 157 | Write-Output 'C:\Users /home' | Out-File -Encoding ASCII -Append "$msys2BasePath\etc\fstab" 158 | 159 | # define a function for easying the execution of bash scripts. 160 | $bashPath = "$msys2BasePath\usr\bin\bash.exe" 161 | function Bash($script) { 162 | $eap = $ErrorActionPreference 163 | $ErrorActionPreference = 'Continue' 164 | try { 165 | # we also redirect the stderr to stdout because PowerShell 166 | # oddly interleaves them. 167 | # see https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin 168 | echo 'exec 2>&1;set -eu;export PATH="/usr/bin:$PATH"' $script | &$bashPath 169 | if ($LASTEXITCODE) { 170 | throw "bash execution failed with exit code $LASTEXITCODE" 171 | } 172 | } finally { 173 | $ErrorActionPreference = $eap 174 | } 175 | } 176 | 177 | # configure the shell. 178 | Bash @' 179 | pacman --noconfirm -S vim 180 | 181 | cat>~/.bash_history<<"EOF" 182 | EOF 183 | 184 | cat>~/.bashrc<<"EOF" 185 | # If not running interactively, don't do anything 186 | [[ "$-" != *i* ]] && return 187 | 188 | export EDITOR=vim 189 | export PAGER=less 190 | 191 | alias l='ls -lF --color' 192 | alias ll='l -a' 193 | alias h='history 25' 194 | alias j='jobs -l' 195 | EOF 196 | 197 | cat>~/.inputrc<<"EOF" 198 | "\e[A": history-search-backward 199 | "\e[B": history-search-forward 200 | "\eOD": backward-word 201 | "\eOC": forward-word 202 | set show-all-if-ambiguous on 203 | set completion-ignore-case on 204 | EOF 205 | 206 | cat>~/.vimrc<<"EOF" 207 | syntax on 208 | set background=dark 209 | set esckeys 210 | set ruler 211 | set laststatus=2 212 | set nobackup 213 | 214 | autocmd BufNewFile,BufRead Vagrantfile set ft=ruby 215 | autocmd BufNewFile,BufRead *.config set ft=xml 216 | 217 | " Usefull setting for working with Ruby files. 218 | autocmd FileType ruby set tabstop=2 shiftwidth=2 smarttab expandtab softtabstop=2 autoindent 219 | autocmd FileType ruby set smartindent cinwords=if,elsif,else,for,while,try,rescue,ensure,def,class,module 220 | 221 | " Usefull setting for working with Python files. 222 | autocmd FileType python set tabstop=4 shiftwidth=4 smarttab expandtab softtabstop=4 autoindent 223 | " Automatically indent a line that starts with the following words (after we press ENTER). 224 | autocmd FileType python set smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class 225 | 226 | " Usefull setting for working with Go files. 227 | autocmd FileType go set tabstop=4 shiftwidth=4 smarttab expandtab softtabstop=4 autoindent 228 | " Automatically indent a line that starts with the following words (after we press ENTER). 229 | autocmd FileType go set smartindent cinwords=if,else,switch,for,func 230 | EOF 231 | '@ 232 | 233 | # install ConEmu. 234 | choco install -y conemu 235 | cp ConEmu.xml "$env:APPDATA\ConEmu.xml" 236 | reg import ConEmu.reg 237 | 238 | # cleanup the taskbar by removing the existing icons and unpinning all applications; once the user logs on. 239 | # NB the shell executes these RunOnce commands about ~10s after the user logs on. 240 | [IO.File]::WriteAllText( 241 | "$env:TEMP\ConfigureTaskbar.ps1", 242 | @' 243 | # unpin all applications. 244 | # NB this can only be done in a logged on session. 245 | $pinnedTaskbarPath = "$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" 246 | (New-Object -Com Shell.Application).NameSpace($pinnedTaskbarPath).Items() ` 247 | | ForEach-Object { 248 | $unpinVerb = $_.Verbs() | Where-Object { $_.Name -eq 'Unpin from tas&kbar' } 249 | if ($unpinVerb) { 250 | $unpinVerb.DoIt() 251 | } else { 252 | $shortcut = (New-Object -Com WScript.Shell).CreateShortcut($_.Path) 253 | if (!$shortcut.TargetPath -and ($shortcut.IconLocation -eq '%windir%\explorer.exe,0')) { 254 | Remove-Item -Force $_.Path 255 | } 256 | } 257 | } 258 | Get-Item HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband ` 259 | | Set-ItemProperty -Name Favorites -Value 0xff ` 260 | | Set-ItemProperty -Name FavoritesResolve -Value 0xff ` 261 | | Set-ItemProperty -Name FavoritesVersion -Value 3 ` 262 | | Set-ItemProperty -Name FavoritesChanges -Value 1 ` 263 | | Set-ItemProperty -Name FavoritesRemovedChanges -Value 1 264 | 265 | # hide the search icon. 266 | Set-ItemProperty -Path HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Search -Name SearchboxTaskbarMode -Value 0 267 | 268 | # hide the task view icon. 269 | Set-ItemProperty -Path HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name ShowTaskViewButton -Value 0 270 | 271 | # never combine the taskbar buttons. 272 | # possibe values: 273 | # 0: always combine and hide labels (default) 274 | # 1: combine when taskbar is full 275 | # 2: never combine 276 | Set-ItemProperty -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name TaskbarGlomLevel -Value 2 277 | 278 | # restart explorer to apply the changed settings. 279 | (Get-Process explorer).Kill() 280 | 281 | # create Desktop shortcuts. 282 | Import-Module C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1 283 | Remove-Item -Force 'C:\Users\Public\Desktop\*.lnk' 284 | Remove-Item -Force "$env:USERPROFILE\Desktop\*.lnk" 285 | Install-ChocolateyShortcut ` 286 | -ShortcutFilePath "$env:USERPROFILE\Desktop\Computer Certificates.lnk" ` 287 | -TargetPath 'C:\Windows\System32\certlm.msc' 288 | Install-ChocolateyShortcut ` 289 | -ShortcutFilePath "$env:USERPROFILE\Desktop\Services.lnk" ` 290 | -TargetPath 'C:\Windows\System32\services.msc' 291 | # add MSYS2 shortcut to the Desktop and Start Menu. 292 | Install-ChocolateyShortcut ` 293 | -ShortcutFilePath "$env:USERPROFILE\Desktop\MSYS2 Bash.lnk" ` 294 | -TargetPath 'C:\Program Files\ConEmu\ConEmu64.exe' ` 295 | -Arguments '-run {MSYS2} -icon C:\tools\msys64\msys2.ico' ` 296 | -IconLocation C:\tools\msys64\msys2.ico ` 297 | -WorkingDirectory '%USERPROFILE%' 298 | Install-ChocolateyShortcut ` 299 | -ShortcutFilePath "C:\Users\All Users\Microsoft\Windows\Start Menu\Programs\MSYS2 Bash.lnk" ` 300 | -TargetPath 'C:\Program Files\ConEmu\ConEmu64.exe' ` 301 | -Arguments '-run {MSYS2} -icon C:\tools\msys64\msys2.ico' ` 302 | -IconLocation C:\tools\msys64\msys2.ico ` 303 | -WorkingDirectory '%USERPROFILE%' 304 | # add SQL Server Management Studio shortcut to the Desktop. 305 | Install-ChocolateyShortcut ` 306 | -ShortcutFilePath "$env:USERPROFILE\Desktop\SQL Server Management Studio.lnk" ` 307 | -TargetPath 'C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Ssms.exe' 308 | '@) 309 | New-Item -Path HKCU:Software\Microsoft\Windows\CurrentVersion\RunOnce -Force ` 310 | | New-ItemProperty -Name ConfigureTaskbar -Value 'PowerShell -WindowStyle Hidden -File "%TEMP%\ConfigureTaskbar.ps1"' -PropertyType ExpandString ` 311 | | Out-Null 312 | -------------------------------------------------------------------------------- /provision-chocolatey.ps1: -------------------------------------------------------------------------------- 1 | # see https://community.chocolatey.org/packages/chocolatey 2 | $env:chocolateyVersion = '2.1.0' 3 | 4 | Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1') 5 | -------------------------------------------------------------------------------- /provision-sql-server-management-studio.ps1: -------------------------------------------------------------------------------- 1 | # see https://community.chocolatey.org/packages/sql-server-management-studio 2 | choco install -y sql-server-management-studio --version 19.1.56 # SQL Server Management Studio 19.1. 3 | -------------------------------------------------------------------------------- /provision-sql-server-network-encryption.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string]$ip = $null 3 | ) 4 | 5 | # define a function for easying the execution of bash scripts. 6 | $bashPath = 'C:\tools\msys64\usr\bin\bash.exe' 7 | function Bash($script) { 8 | $eap = $ErrorActionPreference 9 | $ErrorActionPreference = 'Continue' 10 | try { 11 | # we also redirect the stderr to stdout because PowerShell 12 | # oddly interleaves them. 13 | # see https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin 14 | Write-Output 'exec 2>&1;set -eu;export PATH="/usr/bin:$PATH"' $script | &$bashPath 15 | if ($LASTEXITCODE) { 16 | throw "bash execution failed with exit code $LASTEXITCODE" 17 | } 18 | } finally { 19 | $ErrorActionPreference = $eap 20 | } 21 | } 22 | 23 | # create a testing CA and a certificate for the current machine. 24 | $ca_file_name = 'example-ca' 25 | $ca_common_name = 'Example CA' 26 | $domain = $env:COMPUTERNAME 27 | if (!$ip) { 28 | $ip = (Get-NetAdapter -Name 'Ethernet 2' | Get-NetIPAddress -AddressFamily IPv4).IPAddress 29 | } 30 | 31 | Bash @" 32 | mkdir -p /c/vagrant/tmp/ca 33 | cd /c/vagrant/tmp/ca 34 | 35 | # see https://www.openssl.org/docs/man1.0.2/apps/x509v3_config.html 36 | 37 | # create CA certificate. 38 | if [ ! -f $ca_file_name-crt.pem ]; then 39 | openssl genrsa \ 40 | -out $ca_file_name-key.pem \ 41 | 2048 \ 42 | 2>/dev/null 43 | chmod 400 $ca_file_name-key.pem 44 | openssl req -new \ 45 | -sha256 \ 46 | -subj "/CN=$ca_common_name" \ 47 | -key $ca_file_name-key.pem \ 48 | -out $ca_file_name-csr.pem 49 | openssl x509 -req -sha256 \ 50 | -signkey $ca_file_name-key.pem \ 51 | -extensions a \ 52 | -extfile <(echo "[a] 53 | basicConstraints=critical,CA:TRUE,pathlen:0 54 | keyUsage=critical,digitalSignature,keyCertSign,cRLSign 55 | ") \ 56 | -days $(5*365) \ 57 | -in $ca_file_name-csr.pem \ 58 | -out $ca_file_name-crt.pem 59 | openssl x509 \ 60 | -in $ca_file_name-crt.pem \ 61 | -outform der \ 62 | -out $ca_file_name-crt.der 63 | # dump the certificate contents (for logging purposes). 64 | #openssl x509 -noout -text -in $ca_file_name-crt.pem 65 | fi 66 | 67 | # create a server certificate that is usable by SQL Server. 68 | if [ ! -f $domain-crt.pem ]; then 69 | openssl genrsa \ 70 | -out $domain-key.pem \ 71 | 2048 \ 72 | 2>/dev/null 73 | chmod 400 $domain-key.pem 74 | openssl req -new \ 75 | -sha256 \ 76 | -subj "/CN=$domain" \ 77 | -key $domain-key.pem \ 78 | -out $domain-csr.pem 79 | openssl x509 -req -sha256 \ 80 | -CA $ca_file_name-crt.pem \ 81 | -CAkey $ca_file_name-key.pem \ 82 | -CAcreateserial \ 83 | -extensions a \ 84 | -extfile <(echo "[a] 85 | subjectAltName=DNS:$domain,IP:$ip 86 | extendedKeyUsage=critical,serverAuth 87 | ") \ 88 | -days $(5*365) \ 89 | -in $domain-csr.pem \ 90 | -out $domain-crt.pem 91 | openssl pkcs12 -export \ 92 | -keyex \ 93 | -inkey $domain-key.pem \ 94 | -in $domain-crt.pem \ 95 | -certfile $domain-crt.pem \ 96 | -passout pass: \ 97 | -out $domain-key.p12 98 | # dump the certificate contents (for logging purposes). 99 | #openssl x509 -noout -text -in $domain-crt.pem 100 | #openssl pkcs12 -info -nodes -passin pass: -in $domain-key.p12 101 | fi 102 | "@ 103 | 104 | Write-Host "Importing $ca_file_name CA..." 105 | Import-Certificate ` 106 | -FilePath "c:\vagrant\tmp\ca\$ca_file_name-crt.der" ` 107 | -CertStoreLocation Cert:\LocalMachine\Root ` 108 | | Out-Null 109 | 110 | Write-Host "Importing $domain p12..." 111 | Import-PfxCertificate ` 112 | -FilePath "c:\vagrant\tmp\ca\$domain-key.p12" ` 113 | -CertStoreLocation Cert:\LocalMachine\My ` 114 | -Password $null ` 115 | -Exportable ` 116 | | Out-Null 117 | 118 | Write-Host "Configuring SQL Server to allow encrypted connections at $domain..." 119 | $certificate = Get-ChildItem -DnsName $domain Cert:\LocalMachine\My 120 | $superSocketNetLibPath = Resolve-Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL*.SQLEXPRESS\MSSQLServer\SuperSocketNetLib' 121 | Set-ItemProperty ` 122 | -Path $superSocketNetLibPath ` 123 | -Name Certificate ` 124 | -Value $certificate.Thumbprint 125 | Set-ItemProperty ` 126 | -Path $superSocketNetLibPath ` 127 | -Name ForceEncryption ` 128 | -Value 0 # NB set to 1 to force all connections to be encrypted. 129 | 130 | Write-Host "Granting SQL Server Read permissions to the $domain private key..." 131 | # NB this originally came from http://stackoverflow.com/questions/17185429/how-to-grant-permission-to-private-key-from-powershell/22146915#22146915 132 | function Get-PrivateKeyContainerPath() { 133 | param( 134 | [Parameter(Mandatory=$true)][string][ValidateNotNullOrEmpty()]$name, 135 | [Parameter(Mandatory=$true)][boolean]$isCng 136 | ) 137 | if ($isCng) { 138 | $searchDirectories = @('Microsoft\Crypto\Keys', 'Microsoft\Crypto\SystemKeys') 139 | } else { 140 | $searchDirectories = @('Microsoft\Crypto\RSA\MachineKeys', 'Microsoft\Crypto\RSA\S-1-5-18', 'Microsoft\Crypto\RSA\S-1-5-19', 'Crypto\DSS\S-1-5-20') 141 | } 142 | $commonApplicationDataDirectory = [Environment]::GetFolderPath('CommonApplicationData') 143 | foreach ($searchDirectory in $searchDirectories) { 144 | $privateKeyFile = Get-ChildItem -Path "$commonApplicationDataDirectory\$searchDirectory" -Filter $name -Recurse 145 | if ($privateKeyFile) { 146 | return $privateKeyFile.FullName 147 | } 148 | } 149 | throw "cannot find private key file path for the $name key container" 150 | } 151 | Add-Type -Path '.\Security.Cryptography.dll' # from https://clrsecurity.codeplex.com/ 152 | function Grant-PrivateKeyReadPermissions($certificate, $accountName) { 153 | if ([Security.Cryptography.X509Certificates.X509CertificateExtensionMethods]::HasCngKey($certificate)) { 154 | $privateKey = [Security.Cryptography.X509Certificates.X509Certificate2ExtensionMethods]::GetCngPrivateKey($certificate) 155 | $keyContainerName = $privateKey.UniqueName 156 | $privateKeyPath = Get-PrivateKeyContainerPath $keyContainerName $true 157 | } elseif ($certificate.PrivateKey) { 158 | $privateKey = $certificate.PrivateKey 159 | $keyContainerName = $certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName 160 | $privateKeyPath = Get-PrivateKeyContainerPath $keyContainerName $false 161 | } else { 162 | throw 'certificate does not have a private key, or that key is inaccessible, therefore permission cannot be granted' 163 | } 164 | $acl = Get-Acl -Path $privateKeyPath 165 | $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule @($accountName, 'Read', 'Allow'))) 166 | Set-Acl $privateKeyPath $acl 167 | } 168 | Grant-PrivateKeyReadPermissions $certificate 'MSSQL$SQLEXPRESS' 169 | Restart-Service 'MSSQL$SQLEXPRESS' -Force 170 | -------------------------------------------------------------------------------- /provision-sql-server.ps1: -------------------------------------------------------------------------------- 1 | # install SQL Server. 2 | # see https://community.chocolatey.org/packages/sql-server-express 3 | choco install -y sql-server-express --version 2022.16.0.1000 # SQL Server 2022 Express. 4 | 5 | # update $env:PSModulePath to include the modules installed by recently installed Chocolatey packages. 6 | $env:PSModulePath = "$([Environment]::GetEnvironmentVariable('PSModulePath', 'User'));$([Environment]::GetEnvironmentVariable('PSModulePath', 'Machine'))" 7 | 8 | # install the Sql Server PowerShell Module. 9 | # see https://www.powershellgallery.com/packages/Sqlserver 10 | # see https://learn.microsoft.com/en-us/powershell/module/sqlserver/?view=sqlserver-ps 11 | # see https://learn.microsoft.com/en-us/sql/powershell/download-sql-server-ps-module?view=sql-server-ver16 12 | Install-Module SqlServer -AllowClobber -RequiredVersion 22.1.1 13 | 14 | # load the SQL Server PowerShell provider and related Smo .NET assemblies. 15 | Import-Module SqlServer 16 | 17 | # allow remote TCP/IP connections. 18 | # see http://stefanteixeira.com/2015/09/01/automating-sqlserver-config-with-powershell-wmi/ 19 | Write-Host 'Enabling remote TCP/IP access (port 1433)...' 20 | $wmi = New-Object 'Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer' 21 | $tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ServerInstance[@Name='SQLEXPRESS']/ServerProtocol[@Name='Tcp']") 22 | $tcp.IsEnabled = $true 23 | $tcp.IPAddresses | Where-Object { $_.Name -eq 'IPAll' } | ForEach-Object { 24 | foreach ($property in $_.IPAddressProperties) { 25 | switch ($property.Name) { 26 | 'Enabled' { $property.Value = $true } 27 | 'TcpPort' { $property.Value = '1433' } 28 | 'TcpDynamicPorts' { $property.Value = '0' } 29 | } 30 | } 31 | } 32 | $tcp.Alter() 33 | Restart-Service 'MSSQL$SQLEXPRESS' -Force 34 | 35 | Write-Host 'Enabling Mixed Mode Authentication...' 36 | $instanceName = '.\SQLEXPRESS' 37 | $server = New-Object Microsoft.SqlServer.Management.Smo.Server $instanceName 38 | $server.Settings.LoginMode = 'Mixed' 39 | $server.Alter() 40 | 41 | # create a bunch of test users. 42 | $testUsers = @( 43 | 'alice.doe' 44 | 'bob.doe' 45 | 'carol.doe' 46 | 'dave.doe' 47 | 'eve.doe' 48 | 'frank.doe' 49 | 'grace.doe' 50 | 'henry.doe' 51 | ) 52 | # create SQL Server accounts for the women. 53 | Write-Host 'Creating SQL Server Users...' 54 | $testUsers | ForEach-Object {$i=0} { if (![bool]($i++ % 2)) {$_}} | ForEach-Object { 55 | $login = New-Object Microsoft.SqlServer.Management.Smo.Login $instanceName,$_ 56 | $login.LoginType = 'SqlLogin' 57 | $login.PasswordPolicyEnforced = $false 58 | $login.PasswordExpirationEnabled = $false 59 | $login.Create('HeyH0Password') 60 | } 61 | # grant sysadmin permissions to alice.doe. 62 | $sysadminRole = $server.Roles['sysadmin'] 63 | $sysadminRole.AddMember('alice.doe') 64 | $sysadminRole.Alter() 65 | # create Windows accounts for the men. 66 | Write-Host 'Creating Windows Users and adding them to SQL Server...' 67 | $testUsers | ForEach-Object {$i=0} { if ([bool]($i++ % 2)) {$_}} | ForEach-Object { 68 | # see the ADS_USER_FLAG_ENUM enumeration at https://msdn.microsoft.com/en-us/library/aa772300(v=vs.85).aspx 69 | $AdsScript = 0x00001 70 | $AdsAccountDisable = 0x00002 71 | $AdsNormalAccount = 0x00200 72 | $AdsDontExpirePassword = 0x10000 73 | $user = ([ADSI]'WinNT://.').Create('User', $_) 74 | $user.Put('FullName', (Get-Culture).TextInfo.ToTitleCase(($_ -replace '\.',' '))) 75 | $user.Put('Description', 'Test Account') 76 | $user.Userflags = $AdsNormalAccount -bor $AdsDontExpirePassword 77 | $user.SetPassword('HeyH0Password') 78 | $user.SetInfo() 79 | # add the user to the Users group. 80 | ([ADSI]'WinNT://./Users,Group').Add("WinNT://$_,User") 81 | # add the Windows user to SQL Server. 82 | $login = New-Object Microsoft.SqlServer.Management.Smo.Login $instanceName,"$env:COMPUTERNAME\$_" 83 | $login.LoginType = 'WindowsUser' 84 | $login.PasswordPolicyEnforced = $false 85 | $login.PasswordExpirationEnabled = $false 86 | $login.Create() 87 | } 88 | 89 | # restart it to be able to use the recently added users. 90 | Restart-Service 'MSSQL$SQLEXPRESS' -Force 91 | 92 | Write-Host 'Creating the firewall rule to allow inbound TCP/IP access to the SQL Server port 1443...' 93 | New-NetFirewallRule ` 94 | -Name 'SQL-SERVER-In-TCP' ` 95 | -DisplayName 'SQL Server (TCP-In)' ` 96 | -Direction Inbound ` 97 | -Enabled True ` 98 | -Protocol TCP ` 99 | -LocalPort 1433 ` 100 | | Out-Null 101 | -------------------------------------------------------------------------------- /ps.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)] 3 | [String]$script, 4 | [Parameter(ValueFromRemainingArguments=$true)] 5 | [String[]]$scriptArguments 6 | ) 7 | 8 | Set-StrictMode -Version Latest 9 | $ProgressPreference = 'SilentlyContinue' 10 | $ErrorActionPreference = 'Stop' 11 | trap { 12 | Write-Host "ERROR: $_" 13 | ($_.ScriptStackTrace -split '\r?\n') -replace '^(.*)$','ERROR: $1' | Write-Host 14 | ($_.Exception.ToString() -split '\r?\n') -replace '^(.*)$','ERROR EXCEPTION: $1' | Write-Host 15 | Exit 1 16 | } 17 | 18 | # enable TLS 1.1 and 1.2. 19 | [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol ` 20 | -bor [Net.SecurityProtocolType]::Tls11 ` 21 | -bor [Net.SecurityProtocolType]::Tls12 22 | 23 | # wrap the choco command (to make sure this script aborts when it fails). 24 | function Start-Choco([string[]]$Arguments, [int[]]$SuccessExitCodes=@(0)) { 25 | $command, $commandArguments = $Arguments 26 | if ($command -eq 'install') { 27 | $Arguments = @($command, '--no-progress') + $commandArguments 28 | } 29 | for ($n = 0; $n -lt 10; ++$n) { 30 | if ($n) { 31 | # NB sometimes choco fails with "The package was not found with the source(s) listed." 32 | # but normally its just really a transient "network" error. 33 | Write-Host "Retrying choco install..." 34 | Start-Sleep -Seconds 3 35 | } 36 | &C:\ProgramData\chocolatey\bin\choco.exe @Arguments 37 | if ($SuccessExitCodes -Contains $LASTEXITCODE) { 38 | return 39 | } 40 | } 41 | throw "$(@('choco')+$Arguments | ConvertTo-Json -Compress) failed with exit code $LASTEXITCODE" 42 | } 43 | function choco { 44 | Start-Choco $Args 45 | } 46 | 47 | function Start-Example([string]$name, [scriptblock]$script) { 48 | $path = "$env:TEMP\$name" 49 | if (Test-Path $path) { 50 | Remove-Item -Recurse -Force $path 51 | } 52 | Copy-Item -Recurse "c:\vagrant\examples\$name" $path 53 | Push-Location $path 54 | &$script 55 | Pop-Location 56 | } 57 | 58 | Set-Location c:/vagrant 59 | $script = Resolve-Path $script 60 | Set-Location (Split-Path $script -Parent) 61 | Write-Host "Running $script..." 62 | . $script @scriptArguments 63 | -------------------------------------------------------------------------------- /sql-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rgl/sql-server-vagrant/7835ccb45fdb80800ceb8c8a6fdcef889d50347e/sql-server.png -------------------------------------------------------------------------------- /sql-server.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 17 | 26 | 28 | 32 | 36 | 37 | 46 | 48 | 52 | 56 | 57 | 67 | 69 | 73 | 77 | 78 | 79 | 81 | 82 | 84 | image/svg+xml 85 | 87 | 88 | 89 | 90 | 91 | 94 | 97 | 100 | 104 | 108 | 112 | 113 | 114 | 115 | 116 | --------------------------------------------------------------------------------