Cmdlets running within function against passed in parameters. :)

Hi,

Hope this is gonna make sense, so here goes. :slight_smile:

I’m trying to execute a function that takes some mandatory parameters that are then passed into the function for a set of additional cmdlets.

For example, I’m deploying an ARM Template, which is wrapped in a function (Deploy-GoldTemplate). I am required to pass the resourceGroupName to the function, I then need to take the value of the resourceGroupName parameter and have it passed to cmdlet with the function?

It doesn’t seem to take the value of resourceGroupName, and returns `resourceGroupName is null`

So it basically looks like its runs before I pass the value in?

Any help would be great!

Thanks

 

 

 

I think it would be helpful for us to see what you’re talking about. :wink: Please show your code.

Hi Olaf,

Here is a very basic version, I can’t paste the script as it contains so much info, it would take me longer to remove some data.

Anyway - as you can see I’m passing the resourceGroupName through

Function testToShowOlaf {

[cmdletbinding()]

param()

#Command to execute
Get-ResourceGroup $resourceGroupName

New-AzureRmResourceGroupDeployment -Name testToShowOlaf `
                                   -TemplateParameterObject .\params.json `
                                   -TemplateFile .\template.json `
                                   -ResourceGroupName $resourceGroupName
}
testToShowOlaf -ResourceGroupName test

Well. This seems like the first ever function you wrote with parameters. You have to mention the parameter in Param() block.
param($ResourceGroupName)
It’s very much required for you to learn the basics. Here is the MVA course which many of has started from

https://www.youtube.com/watch?v=nMn8-BbRsN8&list=PLyJiOytEPs4etH7Ujq7PU7jlOlHL-9RmV

Thanks kvprasoon,

This was a bad example - but what i was trying to say is that if i want to take a value of a param that is passed into the function while executing the function, will it pass the value to a cmdlet outside of the param block but still within the function.

When i do this, the cmdlet returns a error saying the variable is null even tho i passed the value for the variable when executing the function. So maybe i need to add the variable/cmdlet within the param block? The problem with this is i dont want the param to appear available as part of the function.

Ill keep trying, possibly bad syntax when creating the function.

kvprasoon’s comment still stands.

And yes you function is a bad example and it is not syntactically correct, hence his pointer to that MVA training.

You cannot pass a param that isn’t declared / doe snot exist.

Function testToShowOlaf {

[cmdletbinding()]

param
(
    # You have to put your params here in order to be passed in the function call.    
    [string]$resourceGroupName
)

#Command to execute
Get-ResourceGroup $resourceGroupName

New-AzureRmResourceGroupDeployment -Name testToShowOlaf `
                                   -TemplateParameterObject .\params.json `
                                   -TemplateFile .\template.json `
                                   -ResourceGroupName $resourceGroupName
}

If you do not do the param block as the above, you could never do this…

testToShowOlaf -ResourceGroupName test

… as that ResourceGroupName would not be available.

This is why your statement…

When i do this, the cmdlet returns a error saying the variable is null even tho i passed the value for the variable when executing the function.

… is what it is.

So, to eliminate additional frustration, confusions, bad habit, and misconceptions. Please, pleased, please spend the needed time to ramp up. Along with what kvprsdoon pointed you to, see the helpful info here:

https://www.reddit.com/r/PowerShell/comments/ar6cvt/powershell_in_depth_second_edition/egmlpom/?context=3

https://www.reddit.com/r/PowerShell/comments/afqmmw/i_want_to_help_my_husband_advance_his_powershell/ee3k6p6/?context=3

Thanks for the feedback, it’s been really helpful.

So basically, this is my function.

When I pass the value [pre]resourceGroupName $RSG[/pre] I thought that the value would at least contain [pre]-asf-rsg[/pre] but it returns a null value, so I seem to not be able to pass the values through. I suppose it’s because I am specifying the resourceGroupName as $RSG before the value of $RSG is evaluated.

What I would like to do is define the name of the [pre]resourceGroup[/pre] based upon the value of the [pre]clusterName[/pre]

function deployServiceFabricCluster{

[cmdletbinding()]
param (
$Template=".\template.json",
$location="A location",
$mgmtResourceGroupName="mgmt-rsg",
$nwkResourceGroupName="network-rsg",
[Parameter(Mandatory=$true)]
[ValidateSet('ENV1','ENV2','ENV3')]
[string]$environment,
[Parameter(Mandatory=$true)]
[string]$resourceGroupName,
[Parameter(Mandatory=$true)]
[string]$aadClusterApplicationID,
[Parameter(Mandatory=$true)]
[string]$aadclientApplicationID,
[Parameter(Mandatory=$true)]
[string]$clusterName,
$RSG=("$clusterName-asf-rsg-$environment").ToLower()
)

$commonName = "common"
$tenantID = (Get-AzureRmContext).Tenant.ID
$sourceVaultValueID = (Get-AzureRmKeyVault -ResourceGroupName $mgmtResourceGroupName)
$keyVaultName = $sourceVaultValue.VaultName
$virtualNetWorkID = (Get-AzureRmVirtualNetwork -ResourceGroupName $nwkResourceGroupName).ID
$VirtualNetworkName = (Get-AzureRMVirtualNetwork -ResourceGroupName $nwkResourceGroupName).Name
$certificateName = (Get-AzureKeyVaultCertificate -VaultName $keyVaultName).Name
$certID = (Get-AzureKeyVaultCertificate -VaultName $keyVaultName -Name $certificateName).Version
$certificateThumbprint = (Get-AzureKeyVaultCertificate -VaultName $keyVaultName -Name $certificateName).Thumbprint

Try {
New-AzureRmResourceGroup-Name $rsg-Location $Location-ErrorAction Stop
New-AzureRmResourceGroupDeployment-Name "DeployGoldTemplate"`
-ResourceGroupName $resourceGroupName`
-TemplateParameterFile ".\1nodeType.production.Parameters.json"`
-TemplateFile ".\1nodeType.production.Template.json"`
-commonName $commonName`
-tagEnvironment $environment`
-aadTenantId $tenantID`
-aadClusterApplicationId $aadClusterApplicationID`
-aadclientApplicationID $aadclientApplicationID`
-sourceVaultValue $sourceVaultValueID.ResourceID`
-keyVaultName $keyVaultName`
-certificateName $certificateName`
-certID $certID`
-certificateThumbprint $certificateThumbprint`
-clusterName $clusterName`
-ErrorAction Stop
}

Catch {

Write-Host$_.Exception.Message-ForegroundColor Green

}

}

deployServiceFabricCluster -environment "###############" -resourceGroupName $RSG -clusterName "##########" -aadClusterApplicationId "########################" -aadclientApplicationID "##############################"

Please go easy and if possible without ripping me to shreds suggest a better way?

Thanks

You’re basically creating a wrapper function and based on the above this could be the first function you’re writing. There are some key function concepts that may help, but rather than using a function with like 20 parameters, you should understand how things work with a bit more simplicity. You can use a technique called splatting, which uses a hashtable to pass parameters as key\value pairs. Firstly, using a splat helps you see what you are passing to a command. If you use Get-Service as an example, let say we want to create a wrapper function. We just want to see what is being passed into the function, so we are returning the $PSBoundParameters hashtable:

function Test-It {
    [CmdletBinding()]
    param (
        $Name,
        $Ignore
    )
    begin {}
    process {
        #PSBoundParameters is a hashtable containing everything you passed
        #into the function.  This allows you do standard hashtable operations,
        #such as Add...
        $PSBoundParameters.Add('ComputerName', $env:COMPUTERNAME)
        #or Remove (we are removing the Ignore as an example)
        $PSBoundParameters.Remove('Ignore')
        #Return the hashtable
        $PSBoundParameters
        #Get-Service @PSBoundParameters
    }
    end {}
}

Test-It -Name "Winmgmt" -Ignore "Foo"

Output:

Key          Value          
---          -----          
Name         Winmgmt        
ComputerName DESKTOP123

So, we’ve manipulated what was passed using Add and Remove. Keep in mind, ComputerName would be a parameter, but it’s important to just understand the concepts that you can manipulate the hashtable easily in the function. Now, in order to pass this information directly into Get-Service, we use an ampersand (@) in place of $:

function Test-It {
    [CmdletBinding()]
    param (
        $Name,
        $ComputerName,
        $Ignore
    )
    begin {}
    process {
        $PSBoundParameters.Remove('Ignore')

        Get-Service @PSBoundParameters
    }
    end {}
}

Test-It -Name "Winmgmt" -Ignore "Foo"

Output:

Status   Name               DisplayName                           
------   ----               -----------                           
Running  Winmgmt            Windows Management Instrumentation    

We are now passing params directly from our function to our command to return a service. If you are using a splat of some sort to pass all of these parameters, you can return the hashtable to see exactly what you are passing. As far as the $RSG, that would be better to be in begin{}, not as a parameter, like this:

function Test-It {
    [CmdletBinding()]
    param (
        $FirstName,
        $LastName
    )
    begin {
        #concantenate First and Last Name as DisplayName
        $Displayname = '{0} {1}' -f $FirstName, $LastName
        $PSBoundParameters.Add('DisplayName', $Displayname)
    }
    process {

        $PSBoundParameters

    }
    end {}
}

Test-It -FirstName "John" -LastName "Smith"

Output:

Key         Value     
---         -----     
FirstName   John      
LastName    Smith     
DisplayName John Smith

Lastly, it is a bit confusing why you have a parameter to your function (e.g. $Template=".\template.json") and then you are statically defining a path again (-TemplateFile “.\1nodeType.production.Template.json”) in your command parameters. Consider naming it TemplateFile for splatting simplicity and you should pass -Template file in your deployServiceFabricCluster function call.

Thank you Rob. Splatting looks perfect, ill see if i can get this working. Really appreciate your help.

Oh and the [pre]$Template=".\template.json") [/pre] was just left over from testing, well spotted :slight_smile:

Cheers