【Azure 應用服務】Azure Function App 執(zhí)行PowerShell指令[Get-Azsubscription -TenantId $tenantID -DefaultProf...

問題描述

使用PowerShell腳本執(zhí)行獲取Azure訂閱列表的指令(Get-Azsubscription -TenantId tenantID -DefaultProfilecxt)。在本地調(diào)試后,指令成功運行。

No alt text provided for this image

但是當指令并運行在Azure Function時,則出現(xiàn)了異常:


No alt text provided for this image

完成的錯誤信息為: "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:\home\site\wwwroot\HttpTrigger1\run.ps1
    Line             : $subs = Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt

    PositionMessage  : At D:\home\site\wwwroot\HttpTrigger1\run.ps1:26 char:1
                       + $subs = Get-Azsubscription -TenantId $tenantID -DefaultProfile $cxt
                       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    PSScriptRoot     : D:\home\site\wwwroot\HttpTrigger1
    PSCommandPath    : D:\home\site\wwwroot\HttpTrigger1\run.ps1
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, D:\home\site\wwwroot\HttpTrigger1\run.ps1: line 26

問題分析及臨時解決方案

對比以上本地可以成功運行,而在Azure Function中確出現(xiàn)JSON格式解析錯誤,所以排查PowerShell腳本錯誤問題。 那么就定位在運行腳本的環(huán)境問題。

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

通過 $PSVersionTable 打出PowerShell版本,通過 Get-InstalledModule -name az 和 Get-InstalledModule -name az.* 打印出當前環(huán)境的版本號。


No alt text provided for this image

經(jīng)過對比,發(fā)現(xiàn)本地VM與Azure Function中Powershell和az 模塊的版本都不同.

第二步:尋找臨時的解決方案

由于Azure Function中PowerShell的版本從平臺級別無法更改(可以修改PS腳本中所使用的az模塊版本,修改方式見附件一)。所以主要的尋找發(fā)向為:基于現(xiàn)在的版本,從Get-Azsubscription指令本身來尋找Workaround呢?查看Get-Azsubscription指令,發(fā)現(xiàn)它使用的是當前登錄用戶的權限去獲取所有的訂閱號,指定TenantID是表明只獲取當前TenantID下的所有訂閱號。而參數(shù)DefaultProfile也是只攜帶用戶認證信息,與當前登錄的用戶所有的認證信息重復。

No alt text provided for this image

如果不添加-DefaultProfile參數(shù),是否同樣由異常呢? 經(jīng)過驗證執(zhí)行成功并返回結果正確。所以作為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. 修改頁面如下:


No alt text provided for this image

結論: 解決辦法有兩種

  1. 修改az的版本號為5.2.0,修改辦法見附件一
  2. 修改Get-Azsubscription指令,去掉參數(shù) -DefaultProfile $cxt

參考資料

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

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容