0

Everything in this script I wrote works with if and ifelse statements but not the else statements. Could someone please review the following and help me figure out why? The desired outcome is if I type aconda, a conda environment launches, aconda -d deactivates conda and alters the path, aconda -a activates conda and alters the path . Is there a way to specify the outcome of no parameter?

function aconda {
  param(    
  [Alias('d')]
  [Parameter(ParameterSetName='Deactivate')]
  [switch] $Deactivate
  ,
  [Alias('a')]
  [Parameter(ParameterSetName='Activate')]
  [switch] $Activate
  ,
  [Alias("h")]
  [Parameter(ParameterSetName='help')]
  [switch] $help
  )
  
  if ($Activate) {
      $Environment = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
      foreach ($path in ($Environment).Split(";"))
      {
          if ($path -like "C:\Program Files\Python310\Scripts\")
          {
          $Environment = $Environment.Replace($Path ,"")
          }
          if ($path -like "C:\Program Files\Python310\")
          {
          $Environment = $Environment.Replace($Path ,"")
          }
      }
      $env:PATH = $Environment
      . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda activate 'C:\Anaconda3'
  } 
  elseif ($Deactivate) 
  {
      . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3'
      $env:PATH = [Environment]::GetEnvironmentVariable('Path', 'Machine'),
                  [Environment]::GetEnvironmentVariable('Path', 'User') -join ';'    
  }
  elseif ($help)
   { Write-Output "
  -a    activate conda
  -d    deactivate conda
  -?    Help. This is the same as not typing any options"
   }
  
  else { . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3'
  }

}
EDIT: This works, but still ignores the else statement:

function aconda {
[CmdletBinding(DefaultParameterSetName = 'Activate')]
  param( 
  [Alias('d')]
  [Parameter(ParameterSetName='Deactivate')]
  [switch] $Deactivate
  ,
  [Alias('a')]
  [Parameter(ParameterSetName='Activate')]
  [switch] $Activate
  ,
  [Alias("h")]
  [Parameter(ParameterSetName='help')]
  [switch] $help
  
  )
    $noInput = !$Deactivate -and !$Activate

  if ($PSBoundParameters.ContainsKey('Activate') -or $noInput ) {
      $Environment = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
      foreach ($path in ($Environment).Split(";"))
      {
          if ($path -like "C:\Program Files\Python310\Scripts\")
          {
          $Environment = $Environment.Replace($Path ,"")
          }
          if ($path -like "C:\Program Files\Python310\")
          {
          $Environment = $Environment.Replace($Path ,"")
          }
      }
      $env:PATH = $Environment
      . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda activate 'C:\Anaconda3'
  } 
  elseif ($Deactivate) 
  {
      . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3'
      $env:PATH = [Environment]::GetEnvironmentVariable('Path', 'Machine'),
                  [Environment]::GetEnvironmentVariable('Path', 'User') -join ';'    
  }
  elseif ($help)
   { Write-Output "
  -a    activate conda
  -d    deactivate conda
  -?    Help. This is the same as not typing any options"
   }
  
  else { . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3'
  }

}

This does not, the only difference being if ($PSBoundParameters.ContainsKey('Activate') -or $noInput ) vs elseif ($noInput) { . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3' }:

function aconda {
[CmdletBinding(DefaultParameterSetName = 'Activate')]
  param( 
  [Alias('d')]
  [Parameter(ParameterSetName='Deactivate')]
  [switch] $Deactivate
  ,
  [Alias('a')]
  [Parameter(ParameterSetName='Activate')]
  [switch] $Activate
  ,
  [Alias("h")]
  [Parameter(ParameterSetName='help')]
  [switch] $help
  
  )
    $noInput = !$Deactivate -and !$Activate

  if ($PSBoundParameters.ContainsKey('Activate') ) {
      $Environment = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
      foreach ($path in ($Environment).Split(";"))
      {
          if ($path -like "C:\Program Files\Python310\Scripts\")
          {
          $Environment = $Environment.Replace($Path ,"")
          }
          if ($path -like "C:\Program Files\Python310\")
          {
          $Environment = $Environment.Replace($Path ,"")
          }
      }
      $env:PATH = $Environment
      . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda activate 'C:\Anaconda3'
  } 
  elseif ($Deactivate) 
  {
      . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3'
      $env:PATH = [Environment]::GetEnvironmentVariable('Path', 'Machine'),
                  [Environment]::GetEnvironmentVariable('Path', 'User') -join ';'    
  }
  elseif ($help)
   { Write-Output "
  -a    activate conda
  -d    deactivate conda
  -?    Help. This is the same as not typing any options"
   }
  
  elseif ($noInput) { . C:\Anaconda3\shell\condabin\conda-hook.ps1 ; conda deactivate 'C:\Anaconda3'
  }

}

7
  • your if cascade looks like it otta work. have you tried commenting out the current content of each block and adding a Write-Host with the name of the current block to see what happens with each possible value? ///// also, the switch structure is a handy alternative for an if/elseif/else cascade. it has a default section for "no matches found" ... [grin] Commented May 1, 2022 at 8:06
  • 1
    I can't post a full answer right now but essentially your function is invalid. It produces an error aconda : Parameter set cannot be resolved using the specified named parameters. If you don't see that, your $ErrorActionPreference might be set to SilentlyContinue, which is bad for debugging. To fix your function, you need to identify a default parameter set so Powershell know what to do if it can't meet the requirements of any of the 3 parameter set defined. This can be accomplished by adding [CmdletBinding(DefaultParameterSetName = 'Activate')] before the param block of your func. Commented May 1, 2022 at 9:27
  • Everything should work relatively fine after that... except if you start doing aconda -a:$false, which would end up in the Else block too because of the way your code is structured. to account for that, you'd need to replace the if($Activate) by if ($PSBoundParameters.ContainsKey('Activate') and then, in your condition, you deal with $Activate but know that it could be set to $false if you did aconda -a:$false, which is a very valid way of working with switch parameters. Commented May 1, 2022 at 9:29
  • May be stating the obvious, but after adding the cmdletbinding per @Sage's instruction it's probably easier to just make a final param to be the default e.g. "[Parameter(ParameterSetName='default')] [switch] $default" Commented May 1, 2022 at 9:43
  • 1
    @MikeAnthony I would personally not do it that way because while you might not have to differentiate to determine whether you want to do the activate or default block (which my solution implies), you would get that extra switch parameter default showing up in the auto completion. Commented May 1, 2022 at 11:00

1 Answer 1

1

Answering your question

Switch parameters are inherently $False, unless the user specifies that param. Since you want to do an operation if both switch params are false, you can add a check for that condition.


$noInput = !$Deactivate -and !$Activate
#...
  elseif ($help -or $noInput){
  #your Code here
}

Note: You will need to remove your CmdletParamSet attributes to use this technique.

If you want to ensure your users aren't running the function with both -Activate -Deactivate specified, then just add a check to see if both are true and if so Write-Error "You may only specify one activation selection"

Easier Alternative

Or better yet, change the switch statements to [switch]$ActivationStatus and remove the second switch, then users will use the function like this:

aconda -ActivationStatus $true

aconda -ActivationStatus $false
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, that worked for the help statement, but if I define the last else statement as elseif ($noInput) , I still get no response. I'm not sure why the final statement is ignored
see the recent edit
Frankly I think you're making this much harder on yourself than you need to. Try the easier alternative approach I provided.
To use that elseif, just change the $noInput code to this. Since you're declaring the input as a SwitchParameter, we have access to the helpful IsPresent autoproperty which we can use. ` $noInput = !$Deactivate.IsPresent -and !$Activate.IsPresent`

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.