Passing JSON Parameters into the Azure DevOps Powershell Script - string

I'm trying to pass my variable into my JSON post parameters, however, the below code only works for hardcoding the values, but I need to pass the $var to the principal parameter:
$var="demo"
Write-Host $var
$postParams = #'
{ "scope": "DemoScope","principal": "$($var)" }
'#
So far I tried like $(var) and $($var) in the above script but nothing worked.

Because you use ' ' the variable can't be used, I like this way to create the json:
$postParams = #{
scope = "DemoScope"
principal = $var
} | ConvertTo-Json
# Result:
{
"principal": "demo",
"scope": "DemoScope"
}
Another way it to use " instaed of ':
$postParams = #"
{ "scope": "DemoScope","principal": "$var" }
"#

Related

ARM Template: how to read output result in array format

I posted some question on stackoverflow and would like to thanks those who take time to answer.
Although it exists documentation, i still face an issue related to output feature.
Basically I understand how to retrieve data when format is string.
Unfortunately when data is on array format it looks more difficult for me.
"outputs": {
"keyVaultName": {
"type": "string",
"value": "[variables('keyVaultName')]"
},
"websitesname": {
"type": "array",
"copy": {
"count": "[length(variables('webSitesName'))]",
"input": {
"name": "[variables('webSitesName')[copyIndex()].name]"
}
}
}
}
Then i do this:
$deploymentResult = New-AzResourceGroupDeployment -Name $deploymentName -ResourceGroupName
$ResourceGroupName-TemplateFile $TemplateFile
$vaultName = $deploymentResult.Outputs.keyVaultName.Value
$arrayWebsitesName = $deploymentResult.Outputs.websitesname.Value
I need to extract value from returned array. In powershell i expected to use something like
$arrayWebsitesName[0] to get AppService-Prod-CentralUS
$arrayWebsitesName[\1] to get AppService-Prod-EastUS
I believe there is something related to conversion and I tried convertto-json without success.
Your help is appreciated !
The variable type returned from the deployment for websitesname is a JArray.
PS> $deploymentResult.Outputs.websitesname.Value.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False JArray Newtonsoft.Json.Linq.JContainer
In order to get at the values, you would make the call like:
$arrayWebsitesName = $deploymentResult.Outputs.websitesname.Value
$ids = $arrayWebsitesName.ToString() | ConvertFrom-Json
$ids[0].name
$ids[1].name
Converting the JArray to a JSON string, and then converting the JSON string to a PowerShell array may not be most efficient but I don't typically deal with large arrays and performance is not a concern (gets the job done).

Get all security groups and users associated with a certain build definition[Azure-Devops]

I have looked through the documentation available at -
https://learn.microsoft.com/en-us/rest/api/azure/devops/security/?view=azure-devops-rest-5.1
For a certain build definition, I want to be able to get all the security groups and users associated with it through code/powershell script and output it to a json file for example.
Any help will be appreciated! I have tried curling multiple api's but not getting what I need.
Thanks!
There has one api does not been documented. Try with below:
POST https://dev.azure.com/{org name}/_apis/Contribution/HierarchyQuery/project/{project name}?api-version=5.0-preview.1
Request body:
{
"contributionIds": [
"ms.vss-admin-web.security-view-members-data-provider"
],
"dataProviderContext": {
"properties": {
"permissionSetId": "33344d9c-fc72-4d6f-aba5-fa317101a7e9",
"permissionSetToken": "{token}",
"sourcePage": {
"url": "https://dev.azure.com/{org name}/{project name}/_build?definitionId={build definition id}&_a=summary",
"routeId": "ms.vss-build-web.pipeline-details-route",
"routeValues": {
"project": "{project name}",
"viewname": "details",
"controller": "ContributedPage",
"action": "Execute",
"serviceHost": "{org name}"
}
}
}
}
}
Some key points you should pay attention to:
permissionSetId: Here the 33344d9c-fc72-4d6f-aba5-fa317101a7e9 is
a fixed value which represent the namespaceid of build security.
permissionSetToken: This is the token which can used to get the
security info. You can run below command to get the token(s) you
should used.
az devops security permission list --id
33344d9c-fc72-4d6f-aba5-fa317101a7e9 --subject {your account}
--output table --organization https://dev.azure.com/{org name} --project {project name}
url: Here the url value used to tell the system which specific
build you want to check. Just replace the corresponding org
name/project name/definition id into the URL sample provided.
In addition, I wrote a shot powershell script for you:
$token = "{token}"
$url="https://dev.azure.com/{org name}/_apis/Contribution/HierarchyQuery/project/{project name}?api-version=5.0-preview.1"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$context=#"
{
"contributionIds": [
"ms.vss-admin-web.security-view-members-data-provider"
],
"dataProviderContext": {
"properties": {
"permissionSetId": "33344d9c-fc72-4d6f-aba5-fa317101a7e9",
"permissionSetToken": "{token}",
"sourcePage": {
"url": "https://dev.azure.com/{org name}/{project name}/_build?definitionId={build definition id}&_a=summary",
"routeId": "ms.vss-build-web.pipeline-details-route",
"routeValues": {
"project": "{project name}",
"viewname": "details",
"controller": "ContributedPage",
"action": "Execute",
"serviceHost": "{org name}"
}
}
}
}
}
"#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -Body $context -ContentType "application/json"
Write-Host "results = $($response.dataProviders.'ms.vss-admin-web.security-view-members-data-provider'.identities.displayname| ConvertTo-Json -Depth 100)"

how to create an azure function key in ARM template?

I have been struggling with this one all day, I am trying to create a Function App function key from an ARM template.
So far I have been able to create my function key on the Host level using the following template:
{
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('appServiceName'), '/default/PortalFunctionKey')]",
"properties": {
"name": "PortalFunctionKey"
}
then I found a couple of articles and link showing it is possible via API:
https://github.com/Azure/azure-functions-host/wiki/Key-management-API
And I was able to generate it via this API posting to:
https://{myfunctionapp}.azurewebsites.net/admin/functions/{MyFunctionName}/keys/{NewKeyName}?code={_masterKey}
But I can't for the sake of me figure out how to do that in my ARM template!
I have tried various combinations of type and name, for example:
{
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('appServiceName'), '/{myfunctionName}/PortalFunctionKey')]",
"properties": {
"name": "PortalFunctionKey"
}
or /functions/{myfunctionName}/PortalFunctionKey
as suggested in some articles, and i just can't get any to work, can't find much documentation on ARM Microsoft.Web/sites/host/functionKeys either.
Did anyone succeed to create a FUNCTION key (not host) in ARM template? I would gladly hear how you got there :)!
Basically:
Many thanks in advance,
Emmanuel
This might solve the problem now: https://learn.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/sites/functions/keys
I was able to create a function key by passing an ARM template resource that looked like this:
{
"type": "Microsoft.Web/sites/functions/keys",
"apiVersion": "2020-06-01",
"name": "{Site Name}/{Function App Name}/{Key Name}",
"properties": {
"value": "(optional)-key-value-can-be-passed-here"
}
}
It seems that even if you don't have 'value' in the properties, then you have to at least pass an empty properties object.
To solve this problem , you could refer to this github issue. First issue and second issue, these issues all have the problem about how to get the function key in the ARM template.
For now the sample to get the key value as the below shows:
"properties": {
"contentType": "text/plain",
"value": "[listkeys(concat(variables('functionAppId'), '/host/default/'),'2016-08-01').functionKeys.default]"
}
or with below to get the key object.
"functionkeys": {
"type": "object",
"value": "[listkeys(concat(variables('functionAppId'), '/host/default'), '2018-11-01')]" }
}
You could have a try, hope this could help you.
So it is not possible to create a Function level Function key in ARM template at the moment.
I therefore created a feature request you can vote on if you are interested in it:
https://feedback.azure.com/forums/169385-web-apps/suggestions/39789043-create-function-level-keys-for-azure-functions-in
For now though, we are creating function level function keys via a powershell deployment task step. here is how.
add output parameter to your ARM template:
"outputs": {
"masterKey": {
"type": "string",
"value": "[listkeys(concat(resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('appServiceName')), '/host/default'), '2018-11-01').masterKey]"
},
"appServiceName": {
"type": "string",
"value": "[parameters('appServiceName')]"
},
"functionKeys": {
"type": "array",
"value": [
{
"functionName": "myFunctionName",
"keys": [ "FunctionKeyName1", "FunctionKeyName2" ]
}
]
}
}
Add the following PS script file to your deploy project:
param (
[Parameter(Mandatory=$true)]
[string]
$armOutputString
)
Write-Host $armOutputString
$armOutputObj = $armOutputString | convertfrom-json
Write-Host $armOutputObj
$masterKey = $armOutputObj.masterKey.value
$appServiceName = $armOutputObj.appServiceName.value
$httpHeaders = #{
"x-functions-key" = $masterKey
}
$contentType = "application/json; charset=utf-8"
foreach($function in $armOutputObj.functionKeys.value){
$retryCount = 5;
while ($true) {
try {
$uriBase = "https://$($appServiceName).azurewebsites.net/admin/functions/$($function.functionName)/keys"
$existingKeys = Invoke-RestMethod -Method Get -Uri $uriBase -Headers $httpHeaders -ContentType $contentType
break;
}
catch {
if ($_.Exception.Response.StatusCode.value__ -eq 502) {
if ($retryCount-- -eq 0) {
throw;
}
else {
Write-Output ("Retry" + ": " + $_.Exception.Response.StatusCode + "; attempts=$retryCount")
[System.Threading.Thread]::Sleep(1000);
continue;
}
}
else {
throw;
}
}
}
foreach ($keyname in $function.keys){
$keyExists = 0
foreach($exstingKey in $existingKeys.keys){
if($exstingKey.name -eq $keyname){
$keyExists = 1
Write-Host "key $($keyname) already exists"
}
}
if($keyExists -eq 0){
$uri = "$($uriBase)/$($keyname)?code=$($masterKey)";
Write-Host "Adding $($keyname) key"
Invoke-RestMethod -Method Post -Uri "$($uriBase)/$($keyname)" -Headers $httpHeaders -ContentType $contentType;
}
}
}
The script ensures that the key will not be overwritten if it already exists, and will retry if it fails (the function MUST exist and be running for the API to work).
In your "Azure resource group deployment" task, under "Advanced" set "Deployment outputs" to "armDeployOutput".
Add a Powershell task, your script path to the powershell file in your deploy project, and set "Arguments" as "-armOutputString '$(armDeployOutput)'".
And that's it.

How to reference a parameter within a parameter in an ARM template?

I can't seem to find any way to use the value of a parameter as part of another parameter in a parameter file for ARM templates:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"someCustomParam": {
"value": "desired value"
},
"tags": {
"value": {
"tag1": "[parameters('someCustomParam')]",
"tag2": "some tag value"
}
},
}
}
Notice how I want to use the value of a previous parameter for the value of another.
The value for "tag1" is simply the string and the value does not get substituted in from the parameter() function. I've tested this by using the Test-AzResourceGroupDeployment PowerShell cmdlet.
Is there any way I can do this?
You can do this using PowerShell. Before calling Test-AzResourceGroupDeployment you can get content of parameter file in PowerShell variable/object using
$ParameterObject = Get-Content ./ParameterFileName.json
Update required value like:
$ParameterObject.parameters.tags.value.tag1 = #Value to assign
Pass $parameterObject to -TemplateParameterObject parameter of Test-AzResourceGroupDeployment
------OR------
Convert $parameterObject to JSON using ConvertTo-Json and Save as temp.json and pass temp.json to -TemplateParameterFile [reference below]
$TempParameterFile = ( $ParametersObject | ConvertTo-Json -Depth 20 ) -replace "\\u0027", "'" -replace "\\u0026", "&" | Out-File $tmp -Force
and use $TempParameterFile for -TemplateParameterFile
You need to use variables.
In variables, you can use "[parameters('parameterName')]".
And you can use variables in a similar way as parameters : "[variables('variableName')]"
Update:
Here is a sample:
"parameters": {
"someCustomParam": {
"type": "string"
}
},
"variables": {
"tags": {
"tag1": "[parameters('someCustomParam')]",
"tag2": "some tag value"
}
}
And then you can use the variable in the resource of your template.
You can do this just like what you normally do when you reference a parameter, an example as following:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"paramOne": {
"value": "hello"
},
"paramTwo": {
"value": "[concat(parameters('paramOne'), '-', 'world)]"
}
}
}
the output value of 'paramTwo' will be 'hello-world'.
Hope this helps whoever wants to utilize referencing a parameter in a parameter in a parameter file.

Passing credentials to DSC script from arm template

I am trying to deploy a VM with a DSC extension from an ARM template. According to various sources, and even this SO question, I am following the correct way to pass a credential object to my script:
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.19",
"autoUpgradeMinorVersion": true,
"settings": {
"modulesUrl": "[concat(parameters('_artifactsLocation'), '/', variables('ConfigureRSArchiveFolder'), '/', variables('ConfigureRSArchiveFileName'), '/', parameters('_artifactsLocationSasToken'))]",
"configurationFunction": "[variables('rsConfigurationConfigurationFunction')]",
"properties": {
"SQLSAAdminAuthCreds": {
"UserName": "[parameters('SSRSvmAdminUsername')]",
"Password": "PrivateSettingsRef:SAPassword"
}
}
},
"protectedSettings": {
"Items": {
"SAPassword": "[parameters('SSRSvmAdminPassword')]"
}
}
}
However, when I deploy it, I get this error message:
Error message: "The DSC Extension received an incorrect input: The password element of
argument 'SQLSAAdminAuthCreds' to configuration 'PrepareSSRSServer' does not
match the required format. It should be as follows
{
"UserName" : "MyUserName",
"Password" : "PrivateSettingsRef:MyPassword"
}.
Please correct the input and retry executing the extension.".
As far as I can see, my format is correct. What am I missing? Thanks
It seems that function try to use the paramters that cause the issue. So please have try a check the function in the ps1 file where use the SQLSAAdminAuthCreds. I can't repro the issue that your mentioned. I do a demo for it, the following is my detail steps.
1.Prepare a ps1 file, I get the demo code from article
configuration Main
{
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[PSCredential]
$SQLSAAdminAuthCreds
)
Node localhost {
User LocalUserAccount
{
Username = $SQLSAAdminAuthCreds.UserName
Password = $SQLSAAdminAuthCreds
Disabled = $false
Ensure = "Present"
FullName = "Local User Account"
Description = "Local User Account"
PasswordNeverExpires = $true
}
}
}
2.Zip the ps1 file
3.Download the ARM template and parameters from the Azure portal.
4.Edit the template and parameter file
Try to deploy the ARM template with VS or Powershell
Check it from the Azure portal or output.

Resources