This blog was published in 2018. Some information may have changed.
There have been a number of customers that have hit an issue with the Test-WindowsBestPractices cmdlet which is part of the PowerShell Toolkit. The problem started to manifest in the November 2017 timeframe when a Cumulative Update (CU) was rolled out across Windows Server 2012, 2012 R2 and 2016. I have confirmed this bug with Microsoft and have an open case with them to keep status on when (and if) a fix will be rolled into the previously mentioned versions of Windows Server.
I have confirmed that this issue is fixed in the latest Insider Preview builds of 17093 or greater. To explain the root of the issue below are two examples of running Get-MPIOSetting on Windows Server 2016 and the other on Windows Server 10.0.17093.
Windows Server 2016
In this example Get-MPIOSetting is output to a variable $mpio. Prior to the issue coming up using this method the $mpio variable was addressable to get/set the individual properties. Using this method after the Windows Server CU was applied shows that the individual properties can no longer be retrieved directly.
Windows Server 10.0.17093
Using the latest version of the Windows Server Insider Preview and applying the same method as explained for the Windows Server 2016 shows that the properties are now properly retrieved.
The impact of this issue in Windows Server 2012, 2012 R2 and 2016 for Pure Storage customers who use the Test-WindowsBestPractices cmdlet is that it simply doesn’t work properly. I have tried a number of methods that I’m not particularly fond of like substring. There I said it. Every line of PowerShell that used ____. Below is the new version that I implemented in the PowerShell Toolkit 1802.22. This checks for Windows Server version and then substrings the results of Get-MPIOSetting. Why do I check what version? Well that’s the other problem. I get different substring results between Windows Server 2012 R2 and 2016. The outcome for now is that customers should use Get-MPIOSetting and Set-MPIOSetting directly and not the Test-WindowsBestPractices cmdlet. Details for how use those cmdlets are outlined in the article Step 02 — Configuring Multipath-IO which is part of the Microsoft Platform Guide. The hope is that a fix will come out for the previous versions of Windows Server I mentioned sooner than later.
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 |
<# Get-MPIOSetting Output with Best Practices PS C:> Get-MPIOSetting PathVerificationState : Disabled PathVerificationPeriod : 30 PDORemovePeriod : 30 RetryCount : 3 RetryInterval : 1 UseCustomPathRecoveryTime : Enabled CustomPathRecoveryTime : 20 DiskTimeoutValue : 60 #> switch ((Get-CimInstance Win32_OperatingSystem).version) { 6.3.9600 { Write-Host “Windows 2012 R2 — Current MPIO Settings for $($env:COMPUTERNAME)” $MPIO = $null $MPIO = Get-MPIOSetting | Out-String $MPIO.Replace(” “,“”) $PathVerificationState = $MPIO.Substring(32,8) $PDORemovePeriod = $MPIO.Substring(101,2) $UseCustomPathRecoveryTime = $MPIO.Substring(195,8) $CustomPathRecoveryTime = $MPIO.Substring(232,2) $DiskTimeOutValue = $MPIO.Substring(264,2) if($PathVerificationState -eq ‘Disabled’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: PathVerificationState is $($PathVerificationState).” $resp = Read-Host “REQUIRED ACTION: Set the PathVerificationState to Enabled?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -NewPathVerificationState Enabled } else { Write-Host “WARNING: Not changing the PathVerificationState to Enabled could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: PathVerificationState is Enabled. No action required.” } if($PDORemovePeriod -ne ’30’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: PDORemovePeriod is set to $($PDORemovePeriod).” $resp = Read-Host “REQUIRED ACTION: Set the PDORemovePeriod to 30?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -NewPDORemovePeriod 30 } else { Write-Host “WARNING: Not changing the PathVerificationState to Enabled could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: PDORemovePeriod is set to 30. No action required.” } if($UseCustomPathRecoveryTime -eq ‘Disabled’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: UseCustomPathRecoveryTime is set to $($UseCustomPathRecoveryTime).” $resp = Read-Host “REQUIRED ACTION: Set the UseCustomPathRecoveryTime to Enabled?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -CustomPathRecovery Enabled } else { Write-Host “WARNING: Not changing the UseCustomPathRecoveryTime to Enabled could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline #Write-Host “: UseCustomPathRecoveryTime is set to $($UseCustomPathRecoveryTime). No action required.” Write-Host “: UseCustomPathRecoveryTime is set to Enabled. No action required.” } if($CustomPathRecoveryTime -ne ’20’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: CustomPathRecoveryTime is set to $($CustomPathRecoveryTime).” $resp = Read-Host “REQUIRED ACTION: Set the CustomPathRecoveryTime to 20?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -CustomPathRecovery Enabled } else { Write-Host “WARNING: Not changing the CustomPathRecoveryTime to 20 could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: CustomPathRecoveryTime is set to $($CustomPathRecoveryTime). No action required.” } if($DiskTimeOutValue -ne ’60’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: DiskTimeOutValue is set to $($DiskTimeOutValue).” $resp = Read-Host “REQUIRED ACTION: Set the DiskTimeOutValue to 60?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -NewDiskTimeout 60 } else { Write-Host “WARNING: Not changing the DiskTimeOutValue to 60 could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: DiskTimeOutValue is set to $($DiskTimeOutValue). No action required.” } } # Windows 2012 R2 10.0.14393 { Write-Host “Windows 2016” $MPIO = Get-MPIOSetting | Out-String $MPIO.Trim() $MPIO.Replace(” “,“”) $PathVerificationState = $MPIO.Substring(32,8) $PDORemovePeriod = $MPIO.Substring(102,2) $UseCustomPathRecoveryTime = $MPIO.Substring(196,8) $CustomPathRecoveryTime = $MPIO.Substring(233,2) $DiskTimeOutValue = $MPIO.Substring(265,2) if($PathVerificationState -eq ‘Disabled’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: PathVerificationState is $($PathVerificationState).” $resp = Read-Host “REQUIRED ACTION: Set the PathVerificationState to Enabled?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -NewPathVerificationState Enabled } else { Write-Host “WARNING: Not changing the PathVerificationState to Enabled could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: PathVerificationState is Enabled. No action required.” } if($PDORemovePeriod -ne ’30’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: PDORemovePeriod is set to $($PDORemovePeriod).” $resp = Read-Host “REQUIRED ACTION: Set the PDORemovePeriod to 30?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -NewPDORemovePeriod 30 } else { Write-Host “WARNING: Not changing the PathVerificationState to Enabled could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: PDORemovePeriod is set to 30. No action required.” } if($UseCustomPathRecoveryTime -eq ‘Disabled’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: UseCustomPathRecoveryTime is set to $($UseCustomPathRecoveryTime).” $resp = Read-Host “REQUIRED ACTION: Set the UseCustomPathRecoveryTime to Enabled?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -CustomPathRecovery Enabled } else { Write-Host “WARNING: Not changing the UseCustomPathRecoveryTime to Enabled could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline #Write-Host “: UseCustomPathRecoveryTime is set to $($UseCustomPathRecoveryTime). No action required.” Write-Host “: UseCustomPathRecoveryTime is set to Enabled. No action required.” } if($CustomPathRecoveryTime -ne ’20’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: CustomPathRecoveryTime is set to $($CustomPathRecoveryTime).” $resp = Read-Host “REQUIRED ACTION: Set the CustomPathRecoveryTime to 20?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -CustomPathRecovery Enabled } else { Write-Host “WARNING: Not changing the CustomPathRecoveryTime to 20 could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: CustomPathRecoveryTime is set to $($CustomPathRecoveryTime). No action required.” } if($DiskTimeOutValue -ne ’60’) { Write-Host “FAILED” -ForegroundColor Red -NoNewline Write-Host “: DiskTimeOutValue is set to $($DiskTimeOutValue).” $resp = Read-Host “REQUIRED ACTION: Set the DiskTimeOutValue to 60?” if ($resp.ToUpper() -eq ‘Y’) { Set-MPIOSetting -NewDiskTimeout 60 } else { Write-Host “WARNING: Not changing the DiskTimeOutValue to 60 could cause unexpected path recovery issues.” -ForegroundColor Yellow } } else { Write-Host “PASSED” -ForegroundColor Green -NoNewline Write-Host “: DiskTimeOutValue is set to $($DiskTimeOutValue). No action required.” } } # Windows 2016 } |
Hope this helps explain why there are issues with the Test-WindowsBestPractices cmdlet. Stay tuned for updates.
Thanks,
Barkz