|
| 1 | +function Test-DbaInstantFileInitialization { |
| 2 | + <# |
| 3 | + .SYNOPSIS |
| 4 | + Tests whether Instant File Initialization (IFI) is properly configured for SQL Server Engine service accounts. |
| 5 | +
|
| 6 | + .DESCRIPTION |
| 7 | + Audits Instant File Initialization (IFI) configuration for all SQL Server Engine services on the specified computer(s). |
| 8 | +
|
| 9 | + IFI allows SQL Server to skip zeroing out data file space during file creation and auto-growth operations, which can dramatically speed up database creation, restore operations, and auto-growth events. Microsoft recommends enabling IFI as a best practice for all SQL Server installations. |
| 10 | +
|
| 11 | + IFI is controlled by the Windows "Perform Volume Maintenance Tasks" privilege (SeManageVolumePrivilege). The recommended approach is to grant this privilege to the virtual service account "NT SERVICE\<ServiceName>" rather than to the actual service account (StartName), as this follows the principle of least privilege and is account-independent. |
| 12 | +
|
| 13 | + This command checks both the virtual service account (NT SERVICE\<ServiceName>) and the actual start account (StartName) to determine: |
| 14 | + - IsEnabled: IFI is enabled via either account (the service will benefit from IFI) |
| 15 | + - IsBestPractice: IFI is enabled via the virtual service account only (the recommended configuration) |
| 16 | +
|
| 17 | + Note: This command checks direct privilege assignments only. IFI may also be enabled indirectly via group membership (e.g., Administrators), which is not detected by this command. |
| 18 | +
|
| 19 | + Requires Local Admin rights on destination computer(s). |
| 20 | +
|
| 21 | + References: |
| 22 | + https://docs.microsoft.com/en-us/sql/relational-databases/databases/database-instant-file-initialization |
| 23 | + https://blog.ordix.de/instant-file-initialization-microsoft-sql-server-set-up-check |
| 24 | +
|
| 25 | + .PARAMETER ComputerName |
| 26 | + Specifies the SQL Server host computer(s) to test IFI configuration on. Accepts server names, IP addresses, or DbaInstance objects. |
| 27 | +
|
| 28 | + .PARAMETER Credential |
| 29 | + Specifies a PSCredential object used to authenticate to the target computer(s) when the current user account is insufficient. |
| 30 | +
|
| 31 | + .PARAMETER EnableException |
| 32 | + By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. |
| 33 | + This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. |
| 34 | + Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. |
| 35 | +
|
| 36 | + .NOTES |
| 37 | + Tags: IFI, Privilege, Security, BestPractice, OS |
| 38 | + Author: the dbatools team + Claude |
| 39 | +
|
| 40 | + Website: https://dbatools.io |
| 41 | + Copyright: (c) 2018 by dbatools, licensed under MIT |
| 42 | + License: MIT https://opensource.org/licenses/MIT |
| 43 | +
|
| 44 | + .LINK |
| 45 | + https://dbatools.io/Test-DbaInstantFileInitialization |
| 46 | +
|
| 47 | + .OUTPUTS |
| 48 | + PSCustomObject |
| 49 | +
|
| 50 | + Returns one object per SQL Server Engine service found on each computer tested. |
| 51 | +
|
| 52 | + Default display properties (via Select-DefaultView): |
| 53 | + - ComputerName: The target computer name |
| 54 | + - InstanceName: The SQL Server instance name |
| 55 | + - ServiceName: The Windows service name (e.g. MSSQLSERVER, MSSQL$INSTANCENAME) |
| 56 | + - StartName: The actual Windows account running the service |
| 57 | + - IsEnabled: Boolean indicating if IFI is enabled via either the virtual or start account |
| 58 | + - IsBestPractice: Boolean indicating if IFI is enabled via the virtual service account (NT SERVICE\<ServiceName>) only |
| 59 | +
|
| 60 | + Additional properties available: |
| 61 | + - ServiceNameIFI: Boolean indicating if the virtual service account (NT SERVICE\<ServiceName>) has IFI privilege |
| 62 | + - StartNameIFI: Boolean indicating if the actual start account (StartName) has IFI privilege |
| 63 | +
|
| 64 | + .EXAMPLE |
| 65 | + PS C:\> Test-DbaInstantFileInitialization -ComputerName sqlserver2019 |
| 66 | +
|
| 67 | + Tests IFI configuration for all SQL Server Engine services on sqlserver2019. |
| 68 | +
|
| 69 | + .EXAMPLE |
| 70 | + PS C:\> Test-DbaInstantFileInitialization -ComputerName sql1, sql2, sql3 |
| 71 | +
|
| 72 | + Tests IFI configuration for all SQL Server Engine services on sql1, sql2, and sql3. |
| 73 | +
|
| 74 | + .EXAMPLE |
| 75 | + PS C:\> 'sql1', 'sql2' | Test-DbaInstantFileInitialization |
| 76 | +
|
| 77 | + Tests IFI configuration for all SQL Server Engine services on sql1 and sql2. |
| 78 | +
|
| 79 | + .EXAMPLE |
| 80 | + PS C:\> Test-DbaInstantFileInitialization -ComputerName sqlserver2019 | Where-Object IsBestPractice -eq $false |
| 81 | +
|
| 82 | + Returns SQL Server services on sqlserver2019 where IFI is not configured as best practice. |
| 83 | +
|
| 84 | + #> |
| 85 | + [CmdletBinding()] |
| 86 | + param ( |
| 87 | + [parameter(ValueFromPipeline)] |
| 88 | + [DbaInstance[]]$ComputerName = $env:COMPUTERNAME, |
| 89 | + [PSCredential]$Credential, |
| 90 | + [switch]$EnableException |
| 91 | + ) |
| 92 | + |
| 93 | + process { |
| 94 | + foreach ($computer in $ComputerName) { |
| 95 | + try { |
| 96 | + Write-Message -Level Verbose -Message "Getting SQL Server Engine services on $computer" |
| 97 | + $splatGetService = @{ |
| 98 | + ComputerName = $computer |
| 99 | + Credential = $Credential |
| 100 | + Type = "Engine" |
| 101 | + EnableException = $EnableException |
| 102 | + } |
| 103 | + $services = Get-DbaService @splatGetService |
| 104 | + } catch { |
| 105 | + Stop-Function -Message "Failed to get SQL Server services on $computer" -ErrorRecord $_ -Target $computer -Continue |
| 106 | + } |
| 107 | + |
| 108 | + if (-not $services) { |
| 109 | + Write-Message -Level Verbose -Message "No SQL Server Engine services found on $computer" |
| 110 | + continue |
| 111 | + } |
| 112 | + |
| 113 | + try { |
| 114 | + Write-Message -Level Verbose -Message "Getting Windows privileges on $computer" |
| 115 | + $splatGetPrivilege = @{ |
| 116 | + ComputerName = $computer |
| 117 | + Credential = $Credential |
| 118 | + EnableException = $EnableException |
| 119 | + } |
| 120 | + $privileges = Get-DbaPrivilege @splatGetPrivilege |
| 121 | + } catch { |
| 122 | + Stop-Function -Message "Failed to get privileges on $computer" -ErrorRecord $_ -Target $computer -Continue |
| 123 | + } |
| 124 | + |
| 125 | + foreach ($service in $services) { |
| 126 | + Write-Message -Level Verbose -Message "Checking IFI for service $($service.ServiceName) on $computer" |
| 127 | + |
| 128 | + $serviceNameIFI = ($privileges | Where-Object User -eq "NT SERVICE\$($service.ServiceName)").InstantFileInitialization -eq $true |
| 129 | + $startNameIFI = ($privileges | Where-Object User -eq $service.StartName).InstantFileInitialization -eq $true |
| 130 | + |
| 131 | + $isEnabled = $serviceNameIFI -or $startNameIFI |
| 132 | + $isBestPractice = $serviceNameIFI -and -not $startNameIFI |
| 133 | + |
| 134 | + [PSCustomObject]@{ |
| 135 | + ComputerName = $service.ComputerName |
| 136 | + InstanceName = $service.InstanceName |
| 137 | + ServiceName = $service.ServiceName |
| 138 | + StartName = $service.StartName |
| 139 | + ServiceNameIFI = $serviceNameIFI |
| 140 | + StartNameIFI = $startNameIFI |
| 141 | + IsEnabled = $isEnabled |
| 142 | + IsBestPractice = $isBestPractice |
| 143 | + } | Select-DefaultView -Property ComputerName, InstanceName, ServiceName, StartName, IsEnabled, IsBestPractice |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | +} |
0 commit comments