title: Multiple parameter sets and PowerShell
body: <p>I am building a function which will have three distinct parameter sets, and two of those sets will overlap with the third. The options would look like this:</p>
  
  <pre class="lang-powershell prettyprint-override"><code>A B
  A C
  A (D E F)
  A B (D E F)
  A C (D E F)
  </code></pre>
  
  <p>To make it a little more clear, here is a partially completed version the function:</p>
  
  <pre class="lang-powershell prettyprint-override"><code>function Move-AccountOut {
  
      [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
      Param(
          [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
          [string]$Username,
  
          [Parameter(ParameterSetName='RetainGroups')]
          [switch]$RetainGroups,
  
          [Parameter(ParameterSetName='RemoveFromAllGroups')]
          [switch]$RemoveFromAllGroups,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
          [switch]$TransferHomeDrive,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [string]$OldServer,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [string]$NewServer
      )
  }
  </code></pre>
  
  <p>The purpose of the function is to automate the process of transferring out an AD account to another location within the company. <code>RetainGroups</code> would automatically retain the users groups when set, and <code>RemoveFromAllGroups</code> would automatically remove the user from their groups. The two switches should not be able to be used together. Additionally, if <code>TransferHomeDrive</code> is set, it will call a function to schedule a transfer using an internal tool.</p>
  
  <p>To put it another way, <code>RetainGroups</code> and <code>RemoveFromAllGroups</code> should be a member of all parameter sets (similar to <code>Username</code>), but should not be able to be used together.</p>
  
  <p>I have tried two ways. The first:</p>
  
  <pre class="lang-powershell prettyprint-override"><code>function Move-AccountOut {
  
      [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
      Param(
          [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
          [string]$Username,
  
          [Parameter(ParameterSetName='RetainGroups')]
          [switch]$RetainGroups,
  
          [Parameter(ParameterSetName='RemoveFromAllGroups')]
          [switch]$RemoveFromAllGroups,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
          [Parameter(ParameterSetName='RetainGroups')]
          [Parameter(ParameterSetName='RemoveFromAllGroups')]
          [switch]$TransferHomeDrive,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [Parameter(ParameterSetName='RetainGroups')]
          [Parameter(ParameterSetName='RemoveFromAllGroups')]
          [string]$OldServer,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [Parameter(ParameterSetName='RetainGroups')]
          [Parameter(ParameterSetName='RemoveFromAllGroups')]
          [string]$NewServer
      )
  }
  </code></pre>
  
  <p>Using this technique, retain and remove cannot be used together, but <code>OldServer</code> and <code>NewServer</code> are no longer mandatory. If I change them to:</p>
  
  <pre class="lang-powershell prettyprint-override"><code>        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [Parameter(ParameterSetName='RetainGroups', Mandatory=$True)]
          [string]$OldServer,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [Parameter(ParameterSetName='RetainGroups', Mandatory=$True)]
          [string]$NewServer
  </code></pre>
  
  <p>They will be mandatory, but it no longer cares whether <code>TransferHomeDrive</code> is set.</p>
  
  <p>If I set it up the opposite way:</p>
  
  <pre class="lang-powershell prettyprint-override"><code>function Move-AccountOut {
  
      [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
      Param(
          [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
          [string]$Username,
  
          [Parameter(ParameterSetName='RetainGroups')]
          [Parameter(ParameterSetName='TransferHomeDrive')]
          [switch]$RetainGroups,
  
          [Parameter(ParameterSetName='RemoveFromAllGroups')]
          [Parameter(ParameterSetName='TransferHomeDrive')]
          [switch]$RemoveFromAllGroups,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
          [switch]$TransferHomeDrive,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [string]$OldServer,
  
          [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
          [string]$NewServer
      )
  }
  </code></pre>
  
  <p>Then <code>OldServer</code> and <code>NewServer</code> will be mandatory, but <code>RetainGroups</code> and <code>RemoveFromAllGroups</code> can be used together. Additionally, if I use retain and remove together, then <code>OldServer</code> and <code>NewServer</code> become mandatory, but not when they are used on their own.</p>
  
  <p>How do I make this work?</p>