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.
<# 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