0

I have a script in Powershell, I would like to run it as a script extension in Azure VM. The script is supposed to download various things, and the configuration would enter it as an object. What can I try next? I have a problem passing an object from a json file to it.

Error:

 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract,
at System.Management.Automation.PipelineOps.InvokePipeline(System.Object, Boolean, System.Management.Automation.CommandParameterInternal[][], System.Management.Automation.Language.CommandBaseAst[], System.Management.Automation.CommandRedirection[][], System.Management.Automation.Language.FunctionContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`6[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.Interpreter.Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.__Canon)
   at System.Management.Automation.PSScriptCmdlet.RunClause(System.Action`1<System.Management.Automation.Language.FunctionContext>, System.Object, System.Object)
   at System.Management.Automation.CommandProcessorBase.Complete()
   at System.Management.Automation.CommandProcessorBase.DoComplete()
   at System.Management.Automation.Internal.PipelineProcessor.DoCompleteCore(System.Management.Automation.CommandProcessorBase)
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(System.Object)
   at System.Management.Automation.PipelineOps.InvokePipeline(System.Object, Boolean, System.Management.Automation.CommandParameterInternal[][], System.Management.Automation.Language.CommandBaseAst[], System.Management.Automation.CommandRedirection[][], System.Management.Automation.Language.FunctionContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`6[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.Interpreter.Run(System.Management.Automation.Interpreter.InterpretedFrame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.__Canon)
   at System.Management.Automation.DlrScriptCommandProcessor.RunClause(System.Action`1<System.Management.Automation.Language.FunctionContext>, System.Object, System.Object)
   at System.Management.Automation.DlrScriptCommandProcessor.Complete()
   at System.Management.Automation.CommandProcessorBase.DoComplete()
   at System.Management.Automation.Internal.PipelineProcessor.DoCompleteCore(System.Management.Automation.CommandProcessorBase)
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(System.Object)
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
   at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()
   at System.Management.Automation.Runspaces.PipelineThread.WorkerProc()
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)

[process exited with code 3221225725 (0xc00000fd)]
You can now close this terminal with Ctrl+D, or press Enter to restart.

Json file:

{
  "parameters": {
    "keyVault": {
      "value": {
        "name": "kv-name",
        "subscriptionId": "00000-0000-0000-0000"
      }
    },
    "certificates": {
      "value": [
        {
          "name": "application-certificate",
          "SaveTo": "C:\\Temp2\\"
        },
        {
          "name": "client-certificate",
          "SaveTo": "C:\\Temp\\"
        }
      ]
    },
    "secrets": {
      "value": [
        {
          "name": "secret1",
          "secretName": "secret1"
        },
        {
          "name": "secret2",
          "secretName": "mysecret2"
        },
        {
          "name": "Save certificate password",
          "secretName": "certificatePassword"
        }
      ]
    },
    "configCentralUri": {
      "value": "https://configcentral.adeo.local"
    }
  }
}

PowerShell script creating VM:

[CmdletBinding()]
param
(
  [Parameter()]
  [string]$VMRGName = 'rg-change-me', 
  $Location = 'westeurope',
  $VMName = 'myvm',
  [Parameter(Mandatory = $false)]
  $Object
)
$blobSasUrl = 'https://....'
$blobName = 'myscript.ps1'

$customScriptParam = @{
  ResourceGroupName  = $VMRGName
  Location           = $Location
  VMName             = $VMName
  Name               = 'ConfigurationScript'
  Publisher          = 'Microsoft.Compute'
  ExtensionType      = 'CustomScriptExtension'
  TypeHandlerVersion = '1.1'
  Settings           = @{
    'scriptBlobSasUri' = $blobSasUrl
    'commandToExecute' = "powershell -ExecutionPolicy Unrestricted -File $blobName -config '$Object'"
  }
}
Set-AzVMExtension @customScriptParam

Last my actions:

$config = gc .\parameters.json | ConvertFrom-Json -Depth 10
$configRAW = ($config |  convertto-json -Depth 10 -Compress).replace('"','\"')
.\createVM.ps1 -Object $configRAW
4
  • Do you want to create a VM extension using myscript.ps1 and a parameter JSON file, both of which need to be accessed from the Azure Storage container in myscript.ps1? Commented Nov 20, 2024 at 10:26
  • parameters.json is passed by those commands: $config = gc .\parameters.json | ConvertFrom-Json -Depth 10 $configRAW = ($config | convertto-json -Depth 10 -Compress).replace('"','\"') I will pass it in the pipeline... Commented Nov 20, 2024 at 10:44
  • Are you expecting the output like this after executing the VM extension? Both myscript.ps1 and parameters.json have been downloaded to the VM from storage, and the VM extension output shows the result Commented Nov 20, 2024 at 10:51
  • The PowerShell script has accessed the JSON file and created a script log file on the VM. Let me know if it's helpful, and I will post the answer in detail Commented Nov 20, 2024 at 11:14

1 Answer 1

1

Azure VM, extension script in powershell, how to pass as a parameter json object

The error you are getting is due to the JSON object being serialized and passed to the PowerShell script.

You can use the below PowerShell script and JSON file to pass the JSON object into the script from the Azure storage account

myscript.ps1

[CmdletBinding()]
param (
    [string]$configFile
)

$logFile = "C:\Temp\script.log"
if (-not (Test-Path "C:\Temp")) { New-Item -ItemType Directory -Path "C:\Temp" }

function Log {
    param([string]$message)
    Add-Content -Path $logFile -Value "$(Get-Date) - $message"
}

try {
    Log "Starting script execution."
    $config = Get-Content $configFile | ConvertFrom-Json
    Log "Config loaded successfully: $(ConvertTo-Json $config -Depth 10)"
} catch {
    Log "Error: $_"
}

parameters.json

{
  "parameters": {
    "keyVault": {
      "value": {
        "name": "kv-name",
        "subscriptionId": "00000-0000-0000-0000"
      }
    },
    "certificates": {
      "value": [
        {
          "name": "application-certificate",
          "SaveTo": "C:\\Temp2\\"
        },
        {
          "name": "client-certificate",
          "SaveTo": "C:\\Temp\\"
        }
      ]
    },
    "secrets": {
      "value": [
        {
          "name": "secret1",
          "secretName": "secret1"
        },
        {
          "name": "secret2",
          "secretName": "mysecret2"
        },
        {
          "name": "Save certificate password",
          "secretName": "certificatePassword"
        }
      ]
    },
    "configCentralUri": {
      "value": "https://configcentral.adeo.local"
    }
  }
}

Make sure to upload the parameters.json and myscript.ps1 files to Azure Storage and fetch the SAS URL from the particular blob

enter image description here

Generate a SAS URL for parameters.json from the blob, just like you generate one for the myscript.ps1* blob.

enter image description here

blobSasUrl generation

enter image description here

VM Extension Script

$blobSasUrl = "https://venkatstoragetestdemo.blob.core.windows.net/venkat?sp=racwdli&st=2024-11-20T10:30:05Z&fffffffffffdjfjf:30:05Z&sv=2022-11-02&sr=c&sig=ghghghghggOpN6sqEYvpW17sUe0jA50JGP4bauvJkok%3D"

$jsonSasUrl = "https://venkatstoragetestdemo.blob.core.windows.net/venkat/parameters.json?sp=racwdyt&st=2024-11-20T10:32:0221102&sr=b&sig=FSXGWjNLSgOWTzrsi8lkSDvCp9fTp0s%3D"

$scriptSasUrl = "https://venkatstoragetestdemo.blob.core.windows.net/venkat/myscript.ps1?sp=racwdyt&st=2024-11-20T10:31:43Z&sefKSPprtjI%3D"

Set-AzVMExtension -ResourceGroupName "container-RG" -VMName "Container-VM" -Name "ConfigurationScript" `
    -Publisher "Microsoft.Compute" -ExtensionType "CustomScriptExtension" -TypeHandlerVersion "1.10" `
    -Settings @{
        "scriptBlobSasUri" = $blobSasUrl
        "commandToExecute" = "powershell -ExecutionPolicy Unrestricted -File myscript.ps1 -configFile parameters.json"
    } `
    -ProtectedSettings @{
        "fileUris" = @($scriptSasUrl, $jsonSasUrl) 
    }

Output

enter image description here

After running the script, both myscript.ps1 and parameters.json files have been downloaded to the VM from the storage account

enter image description here

The script log file has been created on the VM after the VM extension created.

enter image description here

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you. But even when I have those files on VM, still I need permission to access to the KV. I added User Managed Identity to VM, this Identity is also assigned to the KV. But I'm receiving an error that I'm not authorized to connect to Azure Subscription. My I doing something wrong?
Have you assigned a role such as Keyvault Administrator to the user-managed identity? If not, please assign the role and check the same again.
I solved whole my issues. Thank you for your help and inspiration. My solution: ADO pipeline has access to ADO KV and fetches AppRegistration and password. Script which creates VM is taking parameters from json file and merging with values from ADO KV. All parameters are sending as parameters to the script as Base64. Inside the VM custom script decoding base64 to the object, where I have Connect-AzAccount with appRegistration data from outside KV and then script has access to all resources that AppRegistration has.
Does my solution help to resolve the problem?
Unfortunately no. I went in a different direction so I wouldn't have to download as many files. But it would definitely work. I liked the login and will use it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.