Providers/AD/Private/Set-ADTestServerPin.ps1
|
function Set-ADTestServerPin { <# .SYNOPSIS Pins every AD and DNS call this provider makes to one domain controller .DESCRIPTION The provider calls the RSAT cmdlets from more than two hundred places, and none of them named a server: each one relied on automatic discovery instead. That is fine until a domain registers a controller it is not running, at which point discovery starts handing back the dead one and calls begin failing - not at the start, where it would be obvious, but whenever the discovery cache happens to re-resolve. A seed can get three steps in and then fail the rest, which is how this was found. Rather than edit every call site, this sets `$PSDefaultParameterValues` in the module's own scope, which reaches the provider's functions when they call the RSAT cmdlets. Three things make that safe: - It is module scope, not global, so nothing is written into the caller's session and nothing survives `Remove-Module`. - A command that has no `-Server` parameter is unaffected, so the provider's own `*-ADTest*` functions are untouched even though they match the wildcard. - A caller who has deliberately set their own default for these cmdlets still wins, which is the right way round. `Disconnect-ADEnvironment` clears it, and so does connecting somewhere else. .PARAMETER Server The domain controller to pin to. .PARAMETER Clear Remove the pin instead of setting one. .EXAMPLE PS> Set-ADTestServerPin -Server 'DC01.ad.contoso.com' DESCRIPTION: Points every later AD and DNS call at one controller OUTPUT: None USE CASE: Called by Connect-ADEnvironment once it has found one that answers .EXAMPLE PS> Set-ADTestServerPin -Clear DESCRIPTION: Removes the pin OUTPUT: None USE CASE: Called by Disconnect-ADEnvironment .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Sets a module-scope preference variable; changes nothing outside the session.')] [CmdletBinding()] [OutputType([void])] param( [Parameter()] [string]$Server, [Parameter()] [switch]$Clear ) if (-not $script:PSDefaultParameterValues) { $script:PSDefaultParameterValues = @{} } foreach ($key in '*-AD*:Server', '*-DnsServer*:ComputerName') { $null = $script:PSDefaultParameterValues.Remove($key) } if ($Clear -or [string]::IsNullOrWhiteSpace($Server)) { Write-Verbose 'Cleared the domain controller pin' return } # The RSAT cmdlets take -Server; the DNS server cmdlets call the same thing -ComputerName. $script:PSDefaultParameterValues['*-AD*:Server'] = $Server $script:PSDefaultParameterValues['*-DnsServer*:ComputerName'] = $Server Write-Verbose "Pinned every AD and DNS call to $Server" } |