Skip to content

Commit e971dc1

Browse files
authored
Build common module with ModuleBuilder (#2430)
1 parent 18f6ecb commit e971dc1

53 files changed

Lines changed: 7044 additions & 5207 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
### Changed
99

10+
- SqlServerDsc.Common
11+
- Moved functions into individual files and use ModuleBuilder to assemble.
12+
1013
- SqlServerDsc
1114
- Refactor integration tests for _SQL Server Reporting Services_ and _Power BI_
1215
_Report Server_ ([issue #2431](https://github.com/dsccommunity/SqlServerDsc/issues/2431)).

build.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ BuildWorkflow:
6969
CopyPaths:
7070
- DSCResources
7171
- en-US
72-
- Modules
7372
Prefix: prefix.ps1
7473
Suffix: suffix.ps1
7574
Encoding: UTF8
@@ -113,6 +112,13 @@ NestedModule:
113112
AddToManifest: false
114113
Exclude: PSGetModuleInfo.xml
115114

115+
SqlServerDsc.Common:
116+
Prefix: prefix.ps1
117+
VersionedOutputDirectory: false
118+
CopyPaths:
119+
- en-US
120+
Encoding: UTF8
121+
116122
####################################################
117123
# Pester Configuration (Sampler) #
118124
####################################################
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
<#
2+
.SYNOPSIS
3+
Connect to a SQL Server Database Engine and return the server object.
4+
5+
.PARAMETER ServerName
6+
String containing the host name of the SQL Server to connect to.
7+
Default value is the current computer name.
8+
9+
.PARAMETER InstanceName
10+
String containing the SQL Server Database Engine instance to connect to.
11+
Default value is 'MSSQLSERVER'.
12+
13+
.PARAMETER SetupCredential
14+
The credentials to use to impersonate a user when connecting to the
15+
SQL Server Database Engine instance. If this parameter is left out, then
16+
the current user will be used to connect to the SQL Server Database Engine
17+
instance using Windows Integrated authentication.
18+
19+
.PARAMETER LoginType
20+
Specifies which type of logon credential should be used. The valid types
21+
are 'WindowsUser' or 'SqlLogin'. Default value is 'WindowsUser'
22+
If set to 'WindowsUser' then the it will impersonate using the Windows
23+
login specified in the parameter SetupCredential.
24+
If set to 'WindowsUser' then the it will impersonate using the native SQL
25+
login specified in the parameter SetupCredential.
26+
27+
.PARAMETER StatementTimeout
28+
Set the query StatementTimeout in seconds. Default 600 seconds (10 minutes).
29+
30+
.PARAMETER Encrypt
31+
Specifies if encryption should be used.
32+
33+
.EXAMPLE
34+
Connect-Sql
35+
36+
Connects to the default instance on the local server.
37+
38+
.EXAMPLE
39+
Connect-Sql -InstanceName 'MyInstance'
40+
41+
Connects to the instance 'MyInstance' on the local server.
42+
43+
.EXAMPLE
44+
Connect-Sql ServerName 'sql.company.local' -InstanceName 'MyInstance' -ErrorAction 'Stop'
45+
46+
Connects to the instance 'MyInstance' on the server 'sql.company.local'.
47+
#>
48+
function Connect-Sql
49+
{
50+
[CmdletBinding(DefaultParameterSetName = 'SqlServer')]
51+
param
52+
(
53+
[Parameter(ParameterSetName = 'SqlServer')]
54+
[Parameter(ParameterSetName = 'SqlServerWithCredential')]
55+
[ValidateNotNull()]
56+
[System.String]
57+
$ServerName = (Get-ComputerName),
58+
59+
[Parameter(ParameterSetName = 'SqlServer')]
60+
[Parameter(ParameterSetName = 'SqlServerWithCredential')]
61+
[ValidateNotNull()]
62+
[System.String]
63+
$InstanceName = 'MSSQLSERVER',
64+
65+
[Parameter(ParameterSetName = 'SqlServerWithCredential', Mandatory = $true)]
66+
[ValidateNotNull()]
67+
[Alias('SetupCredential', 'DatabaseCredential')]
68+
[System.Management.Automation.PSCredential]
69+
$Credential,
70+
71+
[Parameter(ParameterSetName = 'SqlServerWithCredential')]
72+
[ValidateSet('WindowsUser', 'SqlLogin')]
73+
[System.String]
74+
$LoginType = 'WindowsUser',
75+
76+
[Parameter()]
77+
[ValidateSet('tcp', 'np', 'lpc')]
78+
[System.String]
79+
$Protocol,
80+
81+
[Parameter()]
82+
[System.UInt16]
83+
$Port,
84+
85+
[Parameter()]
86+
[ValidateNotNull()]
87+
[System.Int32]
88+
$StatementTimeout = 600,
89+
90+
[Parameter()]
91+
[System.Management.Automation.SwitchParameter]
92+
$Encrypt
93+
)
94+
95+
Import-SqlDscPreferredModule
96+
97+
<#
98+
Build the connection string in the format: [protocol:]hostname[\instance][,port]
99+
Examples:
100+
- ServerName (default instance, no protocol/port)
101+
- ServerName\Instance (named instance)
102+
- tcp:ServerName (default instance with protocol)
103+
- tcp:ServerName\Instance (named instance with protocol)
104+
- ServerName,1433 (default instance with port)
105+
- ServerName\Instance,50200 (named instance with port)
106+
- tcp:ServerName,1433 (default instance with protocol and port)
107+
- tcp:ServerName\Instance,50200 (named instance with protocol and port)
108+
#>
109+
if ($InstanceName -eq 'MSSQLSERVER')
110+
{
111+
$databaseEngineInstance = $ServerName
112+
}
113+
else
114+
{
115+
$databaseEngineInstance = '{0}\{1}' -f $ServerName, $InstanceName
116+
}
117+
118+
# Append port if specified
119+
if ($PSBoundParameters.ContainsKey('Port'))
120+
{
121+
$databaseEngineInstance = '{0},{1}' -f $databaseEngineInstance, $Port
122+
}
123+
124+
# Prepend protocol if specified
125+
if ($PSBoundParameters.ContainsKey('Protocol'))
126+
{
127+
$databaseEngineInstance = '{0}:{1}' -f $Protocol, $databaseEngineInstance
128+
}
129+
130+
$sqlServerObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server'
131+
$sqlConnectionContext = $sqlServerObject.ConnectionContext
132+
$sqlConnectionContext.ServerInstance = $databaseEngineInstance
133+
$sqlConnectionContext.StatementTimeout = $StatementTimeout
134+
$sqlConnectionContext.ConnectTimeout = $StatementTimeout
135+
$sqlConnectionContext.ApplicationName = 'SqlServerDsc'
136+
137+
if ($Encrypt.IsPresent)
138+
{
139+
$sqlConnectionContext.EncryptConnection = $true
140+
}
141+
142+
if ($PSCmdlet.ParameterSetName -eq 'SqlServer')
143+
{
144+
<#
145+
This is only used for verbose messaging and not for the connection
146+
string since this is using Integrated Security=true (SSPI).
147+
#>
148+
$connectUserName = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
149+
150+
Write-Verbose -Message (
151+
$script:localizedData.ConnectingUsingIntegrated -f $connectUsername
152+
)
153+
}
154+
else
155+
{
156+
$connectUserName = $Credential.UserName
157+
158+
Write-Verbose -Message (
159+
$script:localizedData.ConnectingUsingImpersonation -f $connectUsername, $LoginType
160+
)
161+
162+
if ($LoginType -eq 'SqlLogin')
163+
{
164+
$sqlConnectionContext.LoginSecure = $false
165+
$sqlConnectionContext.Login = $connectUserName
166+
$sqlConnectionContext.SecurePassword = $Credential.Password
167+
}
168+
169+
if ($LoginType -eq 'WindowsUser')
170+
{
171+
$sqlConnectionContext.LoginSecure = $true
172+
$sqlConnectionContext.ConnectAsUser = $true
173+
$sqlConnectionContext.ConnectAsUserName = $connectUserName
174+
$sqlConnectionContext.ConnectAsUserPassword = $Credential.GetNetworkCredential().Password
175+
}
176+
}
177+
178+
try
179+
{
180+
$onlineStatus = 'Online'
181+
$connectTimer = [System.Diagnostics.StopWatch]::StartNew()
182+
$sqlConnectionContext.Connect()
183+
184+
<#
185+
The addition of the ConnectTimeout property to the ConnectionContext will force the
186+
Connect() method to block until successful. THe SMO object's Status property may not
187+
report 'Online' immediately even though the Connect() was successful. The loop is to
188+
ensure the SMO's Status property was been updated.
189+
#>
190+
$sleepInSeconds = 2
191+
do
192+
{
193+
$instanceStatus = $sqlServerObject.Status
194+
if ([System.String]::IsNullOrEmpty($instanceStatus))
195+
{
196+
$instanceStatus = 'Unknown'
197+
}
198+
else
199+
{
200+
# Property Status is of type Enum ServerStatus, we return the string equivalent.
201+
$instanceStatus = $instanceStatus.ToString()
202+
}
203+
204+
if ($instanceStatus -eq $onlineStatus)
205+
{
206+
break
207+
}
208+
209+
Write-Debug -Message (
210+
$script:localizedData.WaitForDatabaseEngineInstanceStatus -f $instanceStatus, $onlineStatus, $sleepInSeconds
211+
)
212+
213+
Start-Sleep -Seconds $sleepInSeconds
214+
$sqlServerObject.Refresh()
215+
} while ($connectTimer.Elapsed.TotalSeconds -lt $StatementTimeout)
216+
217+
if ($instanceStatus -match '^Online$')
218+
{
219+
Write-Verbose -Message (
220+
$script:localizedData.ConnectedToDatabaseEngineInstance -f $databaseEngineInstance
221+
)
222+
223+
return $sqlServerObject
224+
}
225+
else
226+
{
227+
$errorMessage = $script:localizedData.DatabaseEngineInstanceNotOnline -f @(
228+
$databaseEngineInstance,
229+
$instanceStatus
230+
)
231+
232+
$invalidOperationException = New-Object -TypeName 'InvalidOperationException' -ArgumentList @($errorMessage)
233+
234+
$newObjectParameters = @{
235+
TypeName = 'System.Management.Automation.ErrorRecord'
236+
ArgumentList = @(
237+
$invalidOperationException,
238+
'CS0001',
239+
'InvalidOperation',
240+
$databaseEngineInstance
241+
)
242+
}
243+
244+
$errorRecordToThrow = New-Object @newObjectParameters
245+
246+
Write-Error -ErrorRecord $errorRecordToThrow
247+
}
248+
}
249+
catch
250+
{
251+
$errorMessage = $script:localizedData.FailedToConnectToDatabaseEngineInstance -f $databaseEngineInstance
252+
253+
$invalidOperationException = New-Object -TypeName 'InvalidOperationException' -ArgumentList @($errorMessage, $_.Exception)
254+
255+
$newObjectParameters = @{
256+
TypeName = 'System.Management.Automation.ErrorRecord'
257+
ArgumentList = @(
258+
$invalidOperationException,
259+
'CS0002',
260+
'InvalidOperation',
261+
$databaseEngineInstance
262+
)
263+
}
264+
265+
$errorRecordToThrow = New-Object @newObjectParameters
266+
267+
Write-Error -ErrorRecord $errorRecordToThrow
268+
}
269+
finally
270+
{
271+
$connectTimer.Stop()
272+
<#
273+
Connect will ensure we actually can connect, but we need to disconnect
274+
from the session so we don't have anything hanging. If we need run a
275+
method on the returned $sqlServerObject it will automatically open a
276+
new session and then close, therefore we don't need to keep this
277+
session open.
278+
#>
279+
$sqlConnectionContext.Disconnect()
280+
}
281+
}

0 commit comments

Comments
 (0)