Passing values to a PowerShell script in a TeamCity metarunner - powershell

I've got a metarunner defined like so:
<?xml version="1.0" encoding="UTF-8"?>
<meta-runner name="Fancy Pancy">
[...]
<build-runners>
<runner name="Fancy Pancy" type="jetbrains_powershell">
<parameters>
[...]
<param name="jetbrains_powershell_scriptArguments"><![CDATA-Optional:%SomeOptMetarunnerParam%
-Required:%SomeReqMetarunnerParam%]]></param>
<param name="jetbrains_powershell_script_code"><![CDATA[#Requires -Version 7
[CmdletBinding()]
param (
[string] $Optional,
[string] $Required
)
[...]
My problem is the following: if the user keeps the optional parameter empty, the PowerShell execution thinks that "-Required:%SomeReqMetarunnerParam" is the argument value for the "Optional" parameter and finally fails because a value for the "Required" parameter is missing. If the user does give a value for the optional parameter, everything works as intended.
I've worked around it by redefining the parameters as follows (note the quotes):
<param name="jetbrains_powershell_scriptArguments"><![CDATA-Optional:'%SomeOptMetarunnerParam%'
-Required:'%SomeReqMetarunnerParam%']]></param>
This works, however, the quotes become part of the value. So I have to trim them at the beginning of the PowerShell script which is clearly bad style and not clean code at all.
Is there a trick on how to overcome this problem?

I found a way to overcome my problem. I removed the scriptArguments XML, the CmdletBinding and the param declaration completely. Instead I simply access the variables at the beginning of the jetbrains_powershell_script_code XML:
$Optional = "%Optional%"
$Required = "%Required%"
The required check is done by TeamCity's validationMode property further up the XML.

Related

Param in CmdletBinding not mandatory and error/misspelled checking

Hey all I have a powershell script that I need to send some parameters to. However, sometimes I do not need to send any or maybe one out of the two.
[CmdletBinding()]
param (
[Parameter(ParameterSetName='SkipAutoLoader')][switch]$SkipAutoLoader,
[Parameter(ParameterSetName='AppPool')][switch]$AppPool
)
[more code here....]
if (-not $SkipAutoLoader) {
$services += "Auto Loader Service"
}
[more code here....]
The above works just fine as long as I have either:
.\Start-AkkServides.ps1 -SkipAutoLoader
or
.\Start-AllServices -AppPool
If I have both together:
.\Start-AllServices -SkipAutoLoader -AppPool
It errors out.
C:\src\Start-AllServices.ps1 : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ .\Start-AllServices.ps1 -SkipAutoLoader -AppPool
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-AllServices.ps1], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Start-AllServices.ps1
I also want to be able to determine if the param has the valid -SkipAutoLoader and/or -AppPool but with something else tagged like -SkipAutoLoader43
I would like to say that -SkipAutoLoaderbob is an invalid param. But do not show an error if either param is not present.
Loads Fine:
.\Start-AllServides.ps1 -SkipAutoLoader
Loads Fine:
.\Start-AllServides.ps1 -AppPool
Does Not Load Fine/causes error:
.\Start-AllServides.ps1 -SkipAutoLoader -AppPool
Does Not Load Fine/casues error:
.\Start-AllServides.ps1
Does not say param is not valid:
.\Start-AllServides.ps1 -SkipAutoLoaderbob
Does not say param is not valid:
.\Start-AllServides.ps1 -AppPool7
Possible to do with powershell?
Your parameters are in separate parameter sets (only[1]), so by design they cannot be used together.
If your parameters can be freely combined, you don't need to define parameter sets at all.
Since your script is an advanced one, thanks to [CmdletBinding()] and/or [Parameter()] attributes, calling with non-declared parameter names is automatically prevented.
However, the lack of a default parameter-set designation in the [CmdletBinding()] attribute causes a more fundamental error if you only specify an unsupported parameter name (such as -SkipAutoLoaderbob): PowerShell then doesn't know which of the two defined parameter sets to select, because no declared parameter can be bound (before even considering whether the parameter name given is valid, perhaps surprisingly)
Use [CmdletBinding(DefaultParameterSetName='AppPool')], for instance, to designate the default parameter set.
Assuming that your two parameters can be freely combined and neither is mandatory (which [switch] parameters shouldn't be anyway), your code can be simplified to:
[CmdletBinding()]
param (
[switch] $SkipAutoLoader,
[switch] $AppPool
)
# Output the name of the active parameter set.
$PSCmdlet.ParameterSetName
Note that non-mandatory parameters without explicit parameter-set membership (and other non-default parameter properties) do not require [Parameter()] attributes.
When you invoke the script, you'll see that PowerShell implicitly defines a parameter set in the absence of explicitly declared ones, named __AllParameterSets.
[1] Note that a parameter can belong to multiple explicitly specified parameter sets, via multiple [Parameter(ParameterSetName= '...')] attributes. Any parameter without an explicit parameter-set membership is implicitly part of all parameter sets.

Powershell Parameter passing issue

I have a strange one I have searched the existing Q&A and haven't found a match.
I have written my functions using parameter validation using the basic format
function FunctioName
{
[CmdletBinding()]
Param(
[parameter(Mandatory)]
[String]$VariableName
)
When I set the parameter to Mandatory as above I get a parameter binding exception indicating a null value was passed. Running the script in debug I can see the function parameter being passed is not null and is a valid string.
When I run the script in the exact same way without the mandatory flag the string is passed into the function and it executes correctly.
Has anyone got any ideas, what could be the issue. This problem is affecting a number of functions in my application interestingly it appears that the affected functions all have only a single parameter functions with multiple parameters do not appear to be affected.
Ok thanks guys for your feedback its much appreciated. BTW i am using powershell 5 .
Further to the issue, looking into it further I found that the variable was being passed to the function as an array of strings, however an empty string value was being appended into the array which I believe was the cause for the issue. This is where it starts to get interesting, I will need to give a bit more background.
The script I am running queries active directory for user attributes meeting specific conditions, those that match I create an array of strings with each value a delimited value of the user,hostname and other attribute properties.
To ensure that I am getting the latest values I use the ASDI GetInfo method,which seems to trigger the odd behavior.
At a high level the functions are
Function GetuserAttr
{
$inscopeusers = New-Object System.Collections.ArrayList
$accountlist = (Get-ADUser -Filter { attribute1 -eq "value"} -Properties attribute1).SamAccountName
foreach ($user in $accountlist)
{
$DN = getDN($user) # basically a funtion I wrote to create ASDI object for user account.
$DN.GetInfo() # this method call appears to cause issues
$attr1 = $DN.Get("Attribute1")
$attr2 = $DN.Get("Attribute2")
$hoststring = "$($user)|$($attr1)|$($attr2)"
$inscopeusers.Add($hoststring) > null
}
return $inscopeusers
}
The string array returned in this function is fed into a number of other functions, one of which is the one that was giving the error that I originally brought up.
The thing is when I use the GetInfo method the array returned by this function contains several null values in the array, when I remove the command the array has no null strings.
Even more strange when I am operating on the array in other functions it appears that the array looses some of its properties when the GetInfo method is used. So for instance I am able to use the foreach loop to iterate through array values but I cannot access an array value by index such as $array[1].
By simply commenting out the GetInfo method call in the function the array returned seems to function normally and you can access array values by index.
I have another function that also uses GetInfo and returns a hash table, when I try to operate on the returned hashtable I cannot access values using a key value such as $hashtable['key'], but I can access them using $hashtable.key. I know this is really weird and can't really think what it could be
Has any one else experienced a similar problem.
You're missing an argument.
Function Test
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[String]
$Variable
)
Write "$Variable"
}

Applying an attribute to all parameters

I've got the following list of parameters for a SQL script. They're all mandatory, as you can see.
param(
[Parameter(Mandatory)][string]$dropLoc,
[Parameter(Mandatory)][string]$manifest,
[Parameter(Mandatory)][string]$accountName,
[Parameter(Mandatory)][string]$appSqlServer,
[Parameter(Mandatory)][string]$appDatabaseName,
[Parameter(Mandatory)][string]$oltpDatabaseName,
[Parameter(Mandatory)][string]$oltpSqlServerName,
[Parameter(Mandatory)][string]$appRootURL,
[Parameter(Mandatory)][string]$AppServiceDBKey,
[Parameter(Mandatory)][string]$reportDBSqlServerName,
[Parameter(Mandatory)][string]$udmInstanceName,
[Parameter(Mandatory)][string]$reportDBDataPath,
[Parameter(Mandatory)][string]$reportDBLogPath,
[Parameter(Mandatory)][string]$maxETL
)
But this is really lengthy and I don't like how I set each one mandatory individually. Does Powershell have a way to set an attribute to all parameters?

Teamcity not printing built-in parameters using Powershell

I'm trying to print TeamCity parameters using Powershell. The Teamcity parameter is formed at run-time, by assigning it values elsewhere. The problem is that Teamcity only prints the string thus formed and not the value that is stored within the parameter. Please see a sample code where I need to print the build id, here the words "teamcity" and "build.id" are formed during run time. However, upon running Teamcity prints the string %teamcity.build.id%, and not the actual build id.
NOTE:
The type of TeamCity build in parameters that I need to print are agent parameters and not system parameters or environment parameters
$per = "%"
$t = "teamcity"
$b = ".build.id"
$indirect = $per+$t+$b+$per
Write-Output $indirect
PowerShell can't interpret the TeamCity variable at runtime.
The variable is injected into the script prior to it being run, thus the only way to do this would be to reference the variable as a whole.
e.g.
$buildId = "%teamcity.build.id%"
Write-Output $buildId

Powershell Add XmlElement As the first child

This is a variation of the following question at:
PowerShell: How to add XmlElement to a non-root element
So I'll run with the data the OP used in that question. Given the following XML snippet:
<clubs>
</clubs>
or
<clubs />
What I'm trying to do is add the first element so that my resulting XML looks like:
<clubs>
<club name="barracas" rating="awesome" />
</clubs>
So far, I have tried: Append, InsertAfter (although I'm not 100% sure how that works)
$newNode = $xml.CreateElement("club")
$newNode.SetAttribute("name", "barracas");
$newnode.SetAttribute("rating", "awesome");
$xml.clubs.Append($newnode)
$xml.clubs.InsertAfter($newNode, $xml.clubs)
$xml.clubs is a string in this scenario and not an XmlNode. Try this instead:
$xml.FirstChild.AppendChild($newNode)
Of course, if the element is further down the tree, you'd probably be better off using the SelectSingleNode() method