Reputation: 1
I have a powershell script like that:
Param(
[Parameter(Mandatory=$True)]
[String]
$NEWPARAMVALUE,
[Parameter(Mandatory=$True)]
[String]
$PARAM_NAME
)
$FILEPATH = “arm_template.json”
$JSON = Get-Content $FILEPATH | Out-String | ConvertFrom-Json
$JSON.$PARAM_NAME = $NEWPARAMVALUE
$JSON | ConvertTo-Json -Depth 10 | Set-Content $FILEPATH
When I used this script without $PARAM_NAME variable (I just put a parameter as a plain text, example: $JSON.resources.properties.parameters.daasServiceBaseUrl.defaultValue
) - it worked.
I tried different ways:
$JSON.resources.$PARAM_NAME
(where $PARAM_NAME = 'properties.parameters.daasServiceBaseUrl.defaultValue'
)
$JSON"."$PARAM_NAME"
I think that's because of the point between two env variables. Could please someone help with it?
Update:
Error that I get from Azure DevOps:
The property | 'properties.parameters.parametername.defaultValue' cannot | be found on this object. Verify that the property exists and | can be set.
How I tried it manually:
$env:PARAM_NAME="resources.properties.parameters.daasServiceBaseUrl.defaultValue"
./test.ps1 -NEWPARAMVALUE "[parameters('DaaS_Contract_Daily_Trigger_properties_Daas-UI-to-Contract_parameters_daasServiceBaseUrl')]" -PARAM_NAME $env:PARAM_NAME
What I got:
Line |
12 | $JSON.$PARAM_NAME = $NEWPARAMVALUE
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception setting "resources.properties.parameters.daasServiceBaseUrl.defaultValue": "The property
| 'resources.properties.parameters.daasServiceBaseUrl.defaultValue' cannot be found on this object. Verify that the property exists and can be
| set."
My JSON:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"dataFactoryName": {
"type": "string",
"defaultValue": ""
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Data Factory location matches Resource group location"
}
},
"project": {
"type": "string",
"defaultValue": "ct",
"metadata": {
"description": "Azure Tag used to track projects"
}
},
"environment": {
"type": "string",
"defaultValue": "default",
"metadata": {
"description": "Azure Tag used to track environments"
}
},
"sleepTime": {
"type": "int",
"defaultValue": "1"
},
"DaaS_Contract_Daily_Trigger_properties_Daas-UI-to-Contract_parameters_daasServiceBaseUrl": {
"type": "string",
"defaultValue": "http://digital-daas-service-om-sqa.nplabsusk8s.com/daas"
}
},
"resources": [
{
"apiVersion": "2018-06-01",
"name": "[parameters('dataFactoryName')]",
"location": "[parameters('location')]",
"tags": {
"project": "[parameters('project')]",
"environment": "[parameters('environment')]"
},
"type": "Microsoft.DataFactory/factories",
"identity": {
"type": "SystemAssigned"
},
"properties": {}
},
{
"name": "[concat(parameters('dataFactoryName'), '/pipeline1')]",
"type": "Microsoft.DataFactory/factories/pipelines",
"apiVersion": "2018-06-01",
"properties": {
"activities": [
{
"name": "Wait1",
"type": "Wait",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"waitTimeInSeconds": "[parameters('sleepTime')]"
}
},
{
"name": "Copy Delivery Request",
"type": "Copy",
"dependsOn": [
{
"activity": "Delete old Req File",
"dependencyConditions": [
"Succeeded"
]
}
],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "RestSource",
"httpRequestTimeout": "00:01:40",
"requestInterval": "00.00:00:00.010",
"requestMethod": "GET"
},
"sink": {
"type": "JsonSink",
"storeSettings": {
"type": "AzureBlobFSWriteSettings"
},
"formatSettings": {
"type": "JsonWriteSettings",
"quoteAllText": true
}
},
"enableStaging": false
},
"inputs": [
{
"referenceName": "Rest_Json_File",
"type": "DatasetReference",
"parameters": {
"relativeURL": {
"value": "@{pipeline().parameters.daasServiceRelURL}/@{variables('createdDate')}",
"type": "Expression"
},
"BaseUrl": {
"value": "@pipeline().parameters.daasServiceBaseUrl",
"type": "Expression"
}
}
}
]
}
],
"parameters": {
"deliveryReqFileName": {
"type": "string",
"defaultValue": "delivery_request.json"
},
"daasServiceBaseUrl": {
"type": "string",
"defaultValue": "http://digital-daas-service-om-sqa.nplabsusk8s.com/daas"
}
},
"annotations": []
},
"dependsOn": []
}
]
}
Upvotes: 0
Views: 99
Reputation: 174835
When you pass a string "a.b.c.d"
as the right-hand operand of the .
member access operator, PowerShell will attempt to resolve the exact member name a.b.c.d
, not "a
, then b
, then c
, then d
".
While this could be solved by executing Invoke-Expression
against "${JSON}.${PARAM_NAME}"
, that also opens your script up to arbitrary execution of whatever the user might pass in as $PARAM_NAME
.
To avoid that, you'll need to manually:
$PARAM_NAME
into individual member names, like $names = $PARAM_NAME.Split('.')
, then$resolvedObject."$last"
Here's how that might look in a generic helper function that takes care of step 2 and 3:
function Set-PropertyChained
{
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[ValidateScript({$_ -isnot [ValueType]})]
[object]$RootObject,
[Parameter(Mandatory = $true, Position = 1)]
[string[]]$MemberChain,
[Parameter(Mandatory = $true, Position = 2)]
[object]$Value,
[switch]$PassThru
)
begin {
$resolutionChain = @($MemberChain |Select -SkipLast 1)
$terminalMember = $($MemberChain |Select -Last 1)
}
process {
$obj = $RootObject
# Member resolution up until the parent of the last property
foreach($memberName in $resolutionChain){
Write-Vebose "Resolving $memberName on $obj"
$obj = $obj.$memberName
}
# Set the value of the last property on its parent
Write-Vebose "Setting $memberName on $obj to $Value"
$obj.$terminalMember = $Value
if($PassThru){
# Write modified object back if requested
Write-Output $RootObject -NoEnumerate
}
}
}
Then in your script:
Param(
[Parameter(Mandatory=$True)]
[String]
$NEWPARAMVALUE,
[Parameter(Mandatory=$True)]
[String]
$PARAM_NAME
)
$FILEPATH = “arm_template.json”
$JSON = Get-Content $FILEPATH | Out-String | ConvertFrom-Json
# Step 1, split the resolution chain into individual components
$MemberNames = $PARAM_NAME.Split('.')
# Step 2 + 3, resolve n-2 members in chain, then assign to n-1
$JSON | Set-PropertyChained -MemberChain $MemberNames -Value $NEWPARAMVALUE
$JSON | ConvertTo-Json -Depth 10 | Set-Content $FILEPATH
Upvotes: 2