├── .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 () {$_}} | 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 |
116 |
--------------------------------------------------------------------------------