• 【Azure 应用服务】Azure Function App 执行PowerShell指令[Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt]错误


    问题描述

    使用PowerShell脚本执行获取Azure订阅列表的指令(Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt)。在本地调试后,指令成功运行。

    但是当指令并运行在Azure Function时,则出现了异常:详细的异常信息为

    完成的错误信息为: "Error getting value from 'Tags' on 'Microsoft.Azure.Commands.Profile.Models.PSAzureSubscription'."

    Microsoft.Azure.WebJobs.Script.Workers.Rpc.RpcException : Result: ERROR: Error getting value from 'Tags' on 'Microsoft.Azure.Commands.Profile.Models.PSAzureSubscription'.
    
    Exception             : 
        Type           : Newtonsoft.Json.JsonSerializationException
        TargetSite     : 
            Name          : GetValue
            DeclaringType : Newtonsoft.Json.Serialization.ExpressionValueProvider
            MemberType    : Method
            Module        : Newtonsoft.Json.dll
        StackTrace     : 
       at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
       at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
       at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
       at Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
       at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, Formatting formatting, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting, JsonConverter[] converters)
       at Microsoft.Azure.Commands.Common.Authentication.Models.AzureRmProfile.ToString(Boolean serializeCache)
       at Microsoft.Azure.Commands.Common.Authentication.Models.AzureRmProfile.ToString()
       at System.Management.Automation.ParameterBinderBase.CoerceTypeAsNeeded(CommandParameterInternal argument, String parameterName, Type toType, ParameterCollectionTypeInformation collectionTypeInfo, Object currentValue)
       at System.Management.Automation.ParameterBinderBase.BindParameter(CommandParameterInternal parameter, CompiledCommandParameter parameterMetadata, ParameterBindingFlags flags)
       at System.Management.Automation.CmdletParameterBinderController.BindParameter(CommandParameterInternal argument, MergedCompiledCommandParameter parameter, ParameterBindingFlags flags)
       at System.Management.Automation.CmdletParameterBinderController.BindParameter(UInt32 parameterSets, CommandParameterInternal argument, MergedCompiledCommandParameter parameter, ParameterBindingFlags flags)
       at System.Management.Automation.CmdletParameterBinderController.BindParameters(UInt32 parameterSets, Collection`1 arguments)
       at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParametersNoValidation(Collection`1 arguments)
       at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParameters(Collection`1 arguments)
       at System.Management.Automation.CommandProcessor.BindCommandLineParameters()
       at System.Management.Automation.CommandProcessor.Prepare(IDictionary psDefaultParameterValues)
       at System.Management.Automation.CommandProcessorBase.DoPrepare(IDictionary psDefaultParameterValues)
       at System.Management.Automation.Internal.PipelineProcessor.Start(Boolean incomingStream)
       at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
       at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput, CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][] commandRedirections, FunctionContext funcContext)
       at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
       at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
       at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
        Message        : Error getting value from 'Tags' on 'Microsoft.Azure.Commands.Profile.Models.PSAzureSubscription'.
        Data           : System.Collections.ListDictionaryInternal
        InnerException : 
            Type       : System.ArgumentNullException
            Message    : Value cannot be null. (Parameter 'value')
            ParamName  : value
            TargetSite : 
                Name          : ArgumentNotNull
                DeclaringType : Newtonsoft.Json.Utilities.ValidationUtils, Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
                MemberType    : Method
                Module        : Newtonsoft.Json.dll
            StackTrace : 
       at Newtonsoft.Json.Utilities.ValidationUtils.ArgumentNotNull(Object value, String parameterName)
       at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
       at Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureSubscriptionExtensions.GetTags(IAzureSubscription subscription)
       at lambda_method(Closure , Object )
       at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
            Source     : Newtonsoft.Json
            HResult    : -2147467261
        Source         : Newtonsoft.Json
        HResult        : -2146233088
    CategoryInfo          : OperationStopped: (:) [], JsonSerializationException
    FullyQualifiedErrorId : Newtonsoft.Json.JsonSerializationException
    InvocationInfo        : 
        ScriptLineNumber : 26
        OffsetInLine     : 1
        HistoryId        : -1
        ScriptName       : D:homesitewwwrootHttpTrigger1
    un.ps1
        Line             : $subs = Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt
                           
        PositionMessage  : At D:homesitewwwrootHttpTrigger1
    un.ps1:26 char:1
                           + $subs = Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt
                           + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        PSScriptRoot     : D:homesitewwwrootHttpTrigger1
        PSCommandPath    : D:homesitewwwrootHttpTrigger1
    un.ps1
        CommandOrigin    : Internal
    ScriptStackTrace      : at <ScriptBlock>, D:homesitewwwrootHttpTrigger1
    un.ps1: line 26

    问题分析及临时解决方案

    对比以上本地可以成功运行,而在Azure Function中确出现JSON格式解析错误,所以排查PowerShell脚本错误问题。 那么就定位在运行脚本的环境问题。

    第一步:排查PowerShell版本,及az 模块的版本

    通过 $PSVersionTable 打出PowerShell版本,通过 Get-InstalledModule -name az 和 Get-InstalledModule -name az.* 打印出当前环境的版本号。

     经过对比,发现本地VM与Azure Function中Powershell和az 模块的版本都不同.  

    第二步:寻找临时的解决方案

    由于Azure Function中PowerShell的版本从平台级别无法更改(可以修改PS脚本中所使用的az模块版本,修改方式见附件一)。所以主要的寻找发向为:基于现在的版本,从Get-Azsubscription指令本身来寻找Workaround呢?查看Get-Azsubscription指令,发现它使用的是当前登录用户的权限去获取所有的订阅号,指定TenantID是表明只获取当前TenantID下的所有订阅号。而参数DefaultProfile也是只携带用户认证信息,与当前登录的用户所有的认证信息重复。

    Get-AzSubscription

    Get subscriptions that the current account can access

    -TenantId

    Specifies the ID of the tenant that contains subscriptions to get

    -DefaultProfile

    The credentials, tenant and subscription used for communication with azure

    如果不添加-DefaultProfile参数,是否同样由异常呢? 经过验证执行成功并返回结果正确。所以作为Workaround的代码为:

    # Write to the Azure Functions log stream.
    Write-Host "PowerShell HTTP trigger function processed a request."
    
    $User = "XXXXXXXXXXXXXxxxxxxxx"
    $PWord = ConvertTo-SecureString -String "XXXXXXXXXXXXXxxxxxxxx" -AsPlainText -Force
    $Credential = New-Object System.Management.Automation.PSCredential($User, $PWord)
    
    Connect-AzAccount -Environment AzureChinaCloud -Credential $Credential
    
    Write-Host "login successfully"
    
    $tenantID = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    $cxt = Set-AzContext -Tenant $tenantID
    write-host $cxt
    
    
    write-host "no defaultprofile"
    Write-Host "Get-Azsubscription -TenantId $tenantID"
    #$subs = Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt
    Get-Azsubscription -TenantId $tenantID
    write-host "========================="
    write-host $subs

    附件一:在Azure Funciton中修改az的版本号为5.2.0, 问题也得到解决。

    在Azure Function 门户页面,点击“App Service Editor (Preview)” 目录,进入Editor页面,在文件requirements.psd1文件中,修改az的版本号为5.2.0. 保存后,回到Azure Function页面。重启Function. 修改页面如下:

    结论: 解决办法有两种

    1. 修改az的版本号为5.2.0,修改办法见附件一
    2. 修改Get-Azsubscription指令,去掉参数 -DefaultProfile $cxt

    参考资料

    Get-AzSubscription : https://docs.microsoft.com/en-us/powershell/module/az.accounts/get-azsubscription?view=azps-6.2.0

    当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!

  • 相关阅读:
    Java 反射机制分析指南
    git将本地代码提交到远程仓库
    git提交本地分支到远程分支
    git分支branch合并到主分支master
    git分支学习笔记2-解决合并的冲突
    MySQL EXPLAIN 详解
    MySQL show processlist说明
    MySQL ibdata1文件太大的解决办法
    Linux如何安装PHPMyAdmin
    Linux-makefile命令后面的-j4 -j8是什么意思?
  • 原文地址:https://www.cnblogs.com/lulight/p/14993273.html
Copyright © 2020-2023  润新知