Variable Scoping for ParameterSetName

Hi,

I started the thread Using param and switch block to set variables which has been answered but off the back of this I’d like to be able to read the $PSCmdlet.ParameterSetName value in order to output which option was selected to a logfile. Calling this variable when not in a function shows this as expected but cannot get it to display outside of this. I’ve tried using variable scoping $Script:$PSCmdlet.ParameterSetName but still nothing is returned. What am I missing?

Cheers
Jamie

Jamie,

Can you explain a little more what you are trying to accomplish. Imagine a script with several functions defined. How would PS know which function you were referencing when trying to access ParameterSetName parameter? If you have parameters defined for the script itself this would work. i.e.

Param
(
    [Parameter(ParameterSetName = "Hello World")]
    $Param1,

    [int]
    $Param2
)

"Paramset is {0}" -f $PSCmdlet.ParameterSetName

Then call the script:

.\myscript.ps1 -Param1 "what"

 

 

Hi Mike,

Ok, so here’s my function:

Function Select-Environment {
[CmdletBinding()]
Param (
[Parameter(ParameterSetName = 'Tier1')]
[switch]$Tier1,

[Parameter(ParameterSetName = 'Tier2')]
[switch]$Tier2
)

switch ($PSCmdlet.ParameterSetName) {
'Tier1' {
$Script:ComTierServers = "Server1","Server2","Server3"
$Script:AppTierServers = "Server4","Server5","Server6"
$Script:WebTierServers = "Server7","Server8","Server9"
}
'Tier2' {
$Script:ComTierServers = "Server10","Serve11","Server13"
$Script:AppTierServers = "Server14","Server15","Server16"
$Script:WebTierServers = "Server17","Server18","Server19"
}
}
}

Select-Environment -Tier1
$PSCmdlet.ParameterSetName

When I call $PSCmdlet.ParameterSetName inside the script as shown above, the value of this is blank. I’ve tried adding $Script:PSCmdlet.ParameterSetName in the function but this made no difference, however, I know does hold the chosen value, as outputs fine when calling no function is used.

The reason it doesn’t work is because $PSCmdlet doesn’t exist beyond line 23. I’m afraid I’m not following the logic in your code. At line 25 you “know” it is “Tier 1” because that is hard coded. Why would you need that value? Also, why are you modifying variables outside the scope inside your function and never returning an object?

I’m being a numpty sorry. I’ve simply added another variable to set the environment string value within each switch section. I have no idea why I didn’t think of this before…Sorry to waste your time.

[quote quote=266501]The reason it doesn’t work is because $PSCmdlet doesn’t exist beyond line 23. I’m afraid I’m not following the logic in your code. At line 25 you “know” it is “Tier 1” because that is hard coded. Why would you need that value? Also, why are you modifying variables outside the scope inside your function and never returning an object?

[/quote]
I want to get the environment the script is working on so I can output it in the logfile also. I knew $PSCmdlet.ParameterSetName held this value so was simply trying to utilize this. I’m not sure what you mean about modifying variables outside of the scope inside the function and never returning an object!?

What do you mean by “the environment the script is working in”? Is this just a sample of the code? Is there more? What I mean by modifying variables outside the scope of your function is that it appears in your code that everything the function does is assign values to variables outside the function scope (they are prefaced with “$script:”). Normally a function accepts arguments, does something with those arguments and returns a results (although not required). Rarely do you see a function modify variables outside it’s scope and when I see that I question the rationale.

Can you explain what the point of this script is? What are your requirements?

This is just a function to allow me to change the global variable values of Com, App & Web Tier servers depending on what switch I provide when calling it. I don’t know of any other way to do what I require in this instance without calling external source files (csv) and knew this would allow me to do what I wanted. It works as intended regardless, even if it’s not normal use for a function.

Once I have the variable values, I’m performing foreach loops on them to get service/AppPool statuses etc.

I’m still a little unclear on what initiates this process. When would you run -Tier 1 or -Tier 2? Based on what I have so far, I would recommend a different solution. I would use a data structure to store the server information and then maybe a function to get service/appPool statuses… Like this:

function Get-ServicesAndApps
{
    [cmdletbinding()]
    param (
    [parameter(ValueFromPipeline=$true)]
    [pscustomobject]$Tier
    )
    
    Process {
        foreach ($server in $Tier.ComTierServers)
        {
            #do stuff and return results
            $server
        }
        # and so on....
    }
    
}

$Tier1 = [pscustomobject]@{
    ComTierServers = "Server1","Server2","Server3"
    AppTierServers = "Server4","Server5","Server6"
    WebTierServers = "Server7","Server8","Server9"
}

$Tier2 = [pscustomobject]@{
    ComTierServers = "Server10","Serve11","Server13"
    AppTierServers = "Server14","Server15","Server16"
    WebTierServers = "Server17","Server18","Server19"
}

#Function call 
Get-ServicesAndApps -Tier $Tier1
#Function call using the pipeline
$Tier1 | Get-ServicesAndApps

 

Another way to do it like below.

Function Select-Environment {
    [CmdletBinding()]
    Param (
        [Parameter(ParameterSetName = 'Tier1')]
        [switch]$Tier1,

        [Parameter(ParameterSetName = 'Tier2')]
        [switch]$Tier2
    )

    switch ($PSCmdlet.ParameterSetName) {
        'Tier1' {
            $ComTierServers = "Server1", "Server2", "Server3"
            $AppTierServers = "Server4", "Server5", "Server6"
            $WebTierServers = "Server7", "Server8", "Server9"
        }
        'Tier2' {
            $ComTierServers = "Server10", "Serve11", "Server13"
            $AppTierServers = "Server14", "Server15", "Server16"
            $WebTierServers = "Server17", "Server18", "Server19"
        }
    }
    
    $Return = @{
        ComTierServers = $ComTierServers
        AppTierServers = $AppTierServers
        WebTierServers = $WebTierServers
        Tier           = $PSCmdlet.ParameterSetName
    }
    $Return
}

$EnvironmentDetail = Select-Environment -Tier1
$EnvironmentDetail.ComTierServers
$EnvironmentDetail.AppTierServers
$EnvironmentDetail.WebTierServers
$EnvironmentDetail.Tier

[quote quote=266744]I’m still a little unclear on what initiates this process. When would you run -Tier 1 or -Tier 2? Based on what I have so far, I would recommend a different solution. I would use a data structure to store the server information and then maybe a function to get service/appPool statuses… Like this:

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
function Get-ServicesAndApps
{
[cmdletbinding()]
param (
[parameter(ValueFromPipeline=$true)]
[pscustomobject]$Tier
)
Process {
foreach ($server in $Tier.ComTierServers)
{
#do stuff and return results
$server
}
# and so on....
}
}
$Tier1 = [pscustomobject]@{
ComTierServers = "Server1","Server2","Server3"
AppTierServers = "Server4","Server5","Server6"
WebTierServers = "Server7","Server8","Server9"
}
$Tier2 = [pscustomobject]@{
ComTierServers = "Server10","Serve11","Server13"
AppTierServers = "Server14","Server15","Server16"
WebTierServers = "Server17","Server18","Server19"
}
#Function call
Get-ServicesAndApps -Tier $Tier1
#Function call using the pipeline
$Tier1 | Get-ServicesAndApps
[/quote]

I would simply call the switch outside the function. I appreciate it’s not probably not the best way of doing this but does work as intended regardless. Thanks both to you and kvprasoon for the alternative solutions though. I’ll probably change what I have to one of these.

Ok, I still need a little help as although what I have works fine within the script, does not when called from the command line outside of it. I’ve tried the above options but they don’t quite present the variables as intended. Let me explain.

This is my function:

Function Select-Environment {
[CmdletBinding()]
Param (
[Parameter(ParameterSetName = 'Tier1')]
[switch]$Tier1,

[Parameter(ParameterSetName = 'Tier2')]
[switch]$Tier2
)

switch ($PSCmdlet.ParameterSetName) {
'Tier1' {
$Script:ComTierServers = "Server1","Server2","Server3"
$Script:AppTierServers = "Server4","Server5","Server6"
$Script:WebTierServers = "Server7","Server8","Server9"
}
'Tier2' {
$Script:ComTierServers = "Server10","Serve11","Server13"
$Script:AppTierServers = "Server14","Server15","Server16"
$Script:WebTierServers = "Server17","Server18","Server19"
}
}
}

Currently I’m running the following command within the script to select which variable set to use Select-Environment -Tier1. The idea behind this is that I need to use the same variable names to run against some other functions I have in place like the following:

Check-Services -Tier $ComTierServers -Service "blah|deblah" -AppPool "blah|deblah"

I need to be able to isolate and call the individual tier variables with different criteria like above rather than the same against the whole tier.

As mentioned, this works fine when called within the script but when I run the following externally it complains that the ComputerName is null or empty and so doesn’t work: . .\powershellscript.ps1 -Select-Environment -Tier1

I guess I need to change the function to require a value rather than just a switch?

Hopefully that makes more sense and gives you more of an idea of what I’m trying to do.

I realize this has moved on from the subject for this thread so maybe I should start another one?

I’ve started a new thread that’s relevant to this requirement: https://powershell.org/forums/topic/function-to-change-variable-values/