-
-
Notifications
You must be signed in to change notification settings - Fork 859
Expand file tree
/
Copy pathTest-DbaDiskAllocation.ps1
More file actions
219 lines (172 loc) · 10.8 KB
/
Test-DbaDiskAllocation.ps1
File metadata and controls
219 lines (172 loc) · 10.8 KB
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
function Test-DbaDiskAllocation {
<#
.SYNOPSIS
Validates disk allocation unit sizes against SQL Server best practice recommendations.
.DESCRIPTION
Examines all NTFS volumes on target servers to verify they are formatted with 64KB allocation units, which is the recommended cluster size for optimal SQL Server performance. When checking a single server, returns a simple true/false result. For multiple servers, returns detailed information including server name, disk details, and compliance status for each volume.
The function can automatically detect SQL Server instances and identify which disks contain database files, helping you focus on storage that directly impacts SQL Server performance. System drives are automatically excluded from best practice validation since they typically don't require the 64KB allocation unit size.
This validation is essential during SQL Server deployment planning and storage configuration audits, as improper allocation unit sizes can significantly impact database I/O performance.
References:
https://technet.microsoft.com/en-us/library/dd758814(v=sql.100).aspx - "The performance question here is usually not one of correlation per the formula, but whether the cluster size has been explicitly defined at 64 KB, which is a best practice for SQL Server."
.PARAMETER ComputerName
Specifies the target server(s) to examine for disk allocation unit compliance. Accepts multiple server names for bulk validation.
Use this to verify storage configuration across your SQL Server environment during deployment or storage audits.
.PARAMETER NoSqlCheck
Skips detection of SQL Server database files and examines all NTFS volumes regardless of their SQL Server usage.
Use this when you want to validate allocation units on all drives, not just those containing SQL Server data or log files.
.PARAMETER SqlCredential
Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential).
Windows Authentication, SQL Server Authentication, Active Directory - Password, and Active Directory - Integrated are all supported.
For MFA support, please use Connect-DbaInstance.
.PARAMETER Credential
Specifies an alternate Windows account to use when enumerating drives on the server. May require Administrator privileges. To use:
$cred = Get-Credential, then pass $cred object to the -Credential parameter.
.PARAMETER WhatIf
If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
.PARAMETER Confirm
If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
.PARAMETER EnableException
By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message.
This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting.
Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch.
.NOTES
Tags: Storage, Disk, OS
Author: Chrissy LeMaire (@cl), netnerds.net
Website: https://dbatools.io
Copyright: (c) 2018 by dbatools, licensed under MIT
License: MIT https://opensource.org/licenses/MIT
.OUTPUTS
PSCustomObject
Returns one object per NTFS volume found on the target server.
Default properties (when -NoSqlCheck is not specified):
- Server: Computer name of the target server
- Name: Drive letter or volume name (e.g., "C:", "D:")
- Label: Volume label or name assigned to the drive
- BlockSize: Allocation unit size in bytes (65536 = 64KB is best practice)
- IsSqlDisk: Boolean indicating if the volume contains SQL Server database or log files
- IsBestPractice: Boolean indicating if BlockSize equals 65536 (64KB) - false for system drives
When -NoSqlCheck is specified, the IsSqlDisk property is omitted:
- Server: Computer name of the target server
- Name: Drive letter or volume name
- Label: Volume label
- BlockSize: Allocation unit size in bytes
- IsBestPractice: Boolean indicating if BlockSize equals 65536 (64KB)
.LINK
https://dbatools.io/Test-DbaDiskAllocation
.EXAMPLE
PS C:\> Test-DbaDiskAllocation -ComputerName sqlserver2014a
Scans all disks on server sqlserver2014a for best practice allocation unit size.
.EXAMPLE
PS C:\> Test-DbaDiskAllocation -ComputerName sqlserver2014 | Select-Output *
Scans all disks on server sqlserver2014a for allocation unit size and returns detailed results for each.
.EXAMPLE
PS C:\> Test-DbaDiskAllocation -ComputerName sqlserver2014a -NoSqlCheck
Scans all disks not hosting SQL Server data or log files on server sqlserver2014a for best practice allocation unit size.
#>
[CmdletBinding()]
[OutputType("System.Collections.ArrayList", "System.Boolean")]
param (
[parameter(Mandatory, ValueFromPipeline)]
[object[]]$ComputerName,
[switch]$NoSqlCheck,
[PSCredential]$SqlCredential,
[PSCredential]$Credential,
[switch]$EnableException
)
begin {
$sessionoptions = New-CimSessionOption -Protocol DCOM
}
process {
foreach ($computer in $ComputerName) {
$fullComputerName = Resolve-DbaComputerName -ComputerName $computer -Credential $Credential
if (!$fullComputerName) {
Stop-Function -Message "Couldn't resolve hostname $computer. Skipping." -Continue
}
Write-Message -Level Verbose -Message "Creating CimSession on $fullComputerName over WSMan."
if (!$Credential) {
$cimSession = New-CimSession -ComputerName $fullComputerName -ErrorAction SilentlyContinue
} else {
$cimSession = New-CimSession -ComputerName $fullComputerName -ErrorAction SilentlyContinue -Credential $Credential
}
if ($null -eq $cimSession.id) {
Write-Message -Level Verbose -Message "Creating CimSession on $fullComputerName over WSMan failed. Creating CimSession on $fullComputerName over DCOM."
if (!$Credential) {
$cimSession = New-CimSession -ComputerName $fullComputerName -SessionOption $sessionoptions -ErrorAction SilentlyContinue
} else {
$cimSession = New-CimSession -ComputerName $fullComputerName -SessionOption $sessionoptions -ErrorAction SilentlyContinue -Credential $Credential
}
}
if ($null -eq $cimSession.id) {
Stop-Function -Message "Can't create CimSession on $fullComputerName" -Target $computer
}
Write-Message -Level Verbose -Message "Getting Disk Allocation from $computer"
try {
Write-Message -Level Verbose -Message "Getting disk information from $computer."
$disks = Get-CimInstance -CimSession $cimSession -ClassName win32_volume -Filter "FileSystem='NTFS'" -ErrorAction Stop | Sort-Object -Property Name
} catch {
Stop-Function -Message "Can't connect to WMI on $computer."
return
}
if ($NoSqlCheck -eq $false) {
Write-Message -Level Verbose -Message "Checking for SQL Services"
$sqlInstances = (Get-DbaService -ComputerName $fullComputerName -Type Engine -AdvancedProperties | Where-Object State -eq Running | Sort-Object -Property Name).SqlInstance
Write-Message -Level Verbose -Message "$($sqlInstances.Count) instance(s) found."
}
foreach ($disk in $disks) {
if (!$disk.name.StartsWith("\\")) {
$diskname = $disk.Name
if ($NoSqlCheck -eq $false) {
$sqldisk = $false
foreach ($instance in $sqlInstances) {
try {
$server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential
} catch {
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue
}
$sql = "SELECT COUNT(*) AS Count FROM sys.master_files WHERE physical_name LIKE '$diskname%'"
$sqlcount = $server.Query($sql).Count
if ($sqlcount -gt 0) {
$sqldisk = $true
break
}
}
}
if ($disk.BlockSize -eq 65536) {
$IsBestPractice = $true
} else {
$IsBestPractice = $false
}
$windowsdrive = "$env:SystemDrive\"
if ($diskname -eq $windowsdrive) {
$IsBestPractice = $false
}
if ($NoSqlCheck -eq $false) {
$output = [PSCustomObject]@{
ComputerName = $computer
DiskName = $diskname
DiskLabel = $disk.Label
BlockSize = $disk.BlockSize
IsSqlDisk = $sqldisk
IsBestPractice = $IsBestPractice
}
$defaults = 'ComputerName', 'DiskName', 'DiskLabel', 'BlockSize', 'IsSqlDisk', 'IsBestPractice'
} else {
$output = [PSCustomObject]@{
ComputerName = $computer
DiskName = $diskname
DiskLabel = $disk.Label
BlockSize = $disk.BlockSize
IsBestPractice = $IsBestPractice
}
$defaults = 'ComputerName', 'DiskName', 'DiskLabel', 'BlockSize', 'IsBestPractice'
}
# Add aliases for backwards compatibility
Add-Member -InputObject $output -MemberType AliasProperty -Name Server -Value ComputerName
Add-Member -InputObject $output -MemberType AliasProperty -Name Name -Value DiskName
Add-Member -InputObject $output -MemberType AliasProperty -Name Label -Value DiskLabel
Select-DefaultView -InputObject $output -Property $defaults
}
}
}
}
}