如何用PowerShell将Azure活动日志文本转为单行JSON?
问题:将Azure活动日志文本转换为单行JSON格式
我是PowerShell脚本开发新手,需要读取存储Azure活动日志的文本文件,该文件包含多组如下结构的信息块:
Authorization : Scope : /subscriptions/XXXXXXXXXXXXXXXXXXXXXXXXXX/resourceGroups/XXXXXXXXXXXXXXXXXX Action : Microsoft.ContainerService/managedClusters/listClusterAdminCredential/action Claims : aud : https://management.core.windows.net/ iss : https://sts.windows.net/XXXXXXXXXXXXXXX/ aio : XXXXXXXXXXXXXXXXXXXXXXXX appidacr : 2 http://schemas.microsoft.com/identity/claims/identityprovider: https://sts.windows.net/XXXXXXXXXXXXXXXXXXXXXXXXXXX/ xms_tcdt : XXXXXXXXXX HttpRequest : ClientId : XXXXXXXXXXXXXXXXXXXXXXXXXXXX Method : POST Url : https://management.azure.com/subscriptions/XXXXXXXXXXXXXXXXXXXXXXX/resourceGroups/XXXXXXXXXXXXXXXX/ ClientIpAddress : XX.XX.XX.XX Properties : statusCode : OK serviceRequestId: eventCategory : Administrative entity : /subscriptions/XXXXXXXXXXXXXXXXXXXXXXX/resourceGroups/XXXXXXXXXXXXXXXXXXXXXX/providers/ Level : Informational EventTimestamp : 8/22/2023 5:59:49 PM SubStatus : OK (HTTP Status Code: 200) Caller : XXXXXXXXXXXXXXXXXXXXXXXXXX Id : /subscriptions/XXXXXX/resourceGroups/XXXXX/providers/Microsoft.ContainerService/managedClusters/XXXXX/events/XXXXX
期望将其转换为如下单行JSON格式并写入新文件,且文件每小时会追加新数据:
{"Authorization":{"scope":"/subscriptions/XXXXXXXXXXXXXXXXXXXXXXXXXX/resourceGroups/XXXXXXXXXXXXXXXXXX","action":"Microsoft.ContainerService/managedClusters/listClusterAdminCredential/action"},"Claims":{"aud":"https://management.core.windows.net/","iss":"https://sts.windows.net/XXXXXXXXXXXXXXX/","aio":"XXXXXXXXXXXXXXXXXXXXXXXX","appidacr":"2","http://schemas.microsoft.com/identity/claims/identityprovider":"https://sts.windows.net/XXXXXXXXXXXXXXXXXXXXXXXXXXX/","xms_tcdt":"XXXXXXXXXX"},"HttpRequest":{"ClientId":"XXXXXXXXXXXXXXXXXXXXXXXXXXXX","Method":"POST","Url":"https://management.azure.com/subscriptions/XXXXXXXXXXXXXXXXXXXXXXX/resourceGroups/XXXXXXXXXXXXXXXX/","ClientIpAddress":"XX.XX.XX.XX"},"Properties":{"statusCode":"OK","serviceRequestId":"","eventCategory":"Administrative","entity":"/subscriptions/XXXXXXXXXXXXXXXXXXXXXXX/resourceGroups/XXXXXXXXXXXXXXXXXXXXXX/providers/"},"Level":"Informational","EventTimestamp":"8/22/2023 5:59:49 PM","SubStatus":"OK (HTTP Status Code: 200)","Caller":"XXXXXXXXXXXXXXXXXXXXXXXX","Id":"/subscriptions/XXXXXX/resourceGroups/XXXXX/providers/Microsoft.ContainerService/managedClusters/XXXXX/events/XXXXX"}
我已编写初步脚本:
Write-Host " ..... " -ForegroundColor Yellow $customlogfile = 'C:\azlogs\customlog.txt' Write-Host "Reading the Activity Log file ..... " -ForegroundColor Yellow $originfile = 'C:\azlogs\activitylogs.txt' $originfilecontent = Get-Content -Path $originfile | Where-Object { $_ -ne '' } Write-Host "Reformatting content of the Activity Log file ..... " -ForegroundColor Yellow $originfilecontent | Select-String -Pattern 'Authorization' -CaseSensitive -SimpleMatch -Context 1 | Add-Content -Path $customlogfile | ConvertTo-Json
但得到的输出不符合预期:
> Authorization : Scope : /subscriptions/XXXXXXXXXXX/resourceGroups/XXXXXXXXX/ TenantId : > Authorization : Scope : /subscriptions/XXXXXXXXXXX/resourceGroups/XXXXXXXXX/
请求指导如何实现正确的格式化,将日志文本转换为目标单行JSON格式。
解决方案
1. 核心思路
原脚本未正确分割独立日志块,也未解析嵌套键值对。需完成以下步骤:
- 按
Authorization开头分割独立日志块 - 解析每个块中的嵌套/顶级键值对,转换为PowerShell对象
- 将对象转为压缩版单行JSON
- 记录已处理行数,避免重复处理新增内容
2. 完整脚本实现
$originFile = 'C:\azlogs\activitylogs.txt' $customLogFile = 'C:\azlogs\customlog.txt' $processedMarkerFile = 'C:\azlogs\processedLineCount.txt' # 读取已处理行数,跳过已处理内容 $processedLines = if (Test-Path $processedMarkerFile) { [int](Get-Content $processedMarkerFile) } else { 0 } $content = Get-Content -Path $originFile | Select-Object -Skip $processedLines | Where-Object { $_ -match '\S' } if (-not $content) { Write-Host "无新内容需要处理。" -ForegroundColor Cyan exit } # 分割日志块:定位所有Authorization行的索引,拆分独立条目 $blockStarts = @(0) + @($content | Select-String -Pattern '^Authorization' -AllMatches | ForEach-Object { $_.LineNumber - 1 }) $blocks = for ($i = 0; $i -lt $blockStarts.Count - 1; $i++) { $start = $blockStarts[$i] $end = $blockStarts[$i+1] - 1 $content[$start..$end] } $blocks += $content[$blockStarts[-1]..($content.Count - 1)] # 解析每个日志块为PSObject $parsedObjects = foreach ($block in $blocks) { $obj = [PSCustomObject]@{} $currentParent = $null foreach ($line in $block) { # 匹配顶级父键(如Authorization、Claims) if ($line -match '^(\w+)\s*:\s*$') { $currentParent = $matches[1] $obj | Add-Member -MemberType NoteProperty -Name $currentParent -Value ([PSCustomObject]@{}) continue } # 匹配嵌套属性或顶级键值对 if ($line -match '^\s+([^:]+)\s*:\s*(.*)$') { $key = $matches[1].Trim() $value = $matches[2].Trim() if ($currentParent) { $obj.$currentParent | Add-Member -MemberType NoteProperty -Name $key -Value $value } else { $obj | Add-Member -MemberType NoteProperty -Name $key -Value $value } } } $obj } # 转换为单行JSON并追加写入 if ($parsedObjects) { $parsedObjects | ConvertTo-Json -Compress | Add-Content -Path $customLogFile # 更新已处理行数标记 $processedLines + $content.Count | Set-Content -Path $processedMarkerFile Write-Host "成功处理 $($parsedObjects.Count) 条日志条目。" -ForegroundColor Green } else { Write-Host "新增内容中未找到有效日志块。" -ForegroundColor Yellow }
3. 脚本说明
- 重复处理规避:通过
processedLineCount.txt记录已处理行数,仅处理新增内容,适配每小时追加的场景。 - 日志块分割:通过定位
Authorization行的位置,将文本拆分为独立的日志条目。 - 嵌套结构解析:识别顶级父键后,将后续缩进行解析为该键的子属性,完整保留原始层级。
- 单行JSON输出:使用
ConvertTo-Json -Compress生成压缩的单行JSON,符合需求格式。
内容的提问来源于stack exchange,提问作者GTGabaaron
相关产品推荐
相关产品推荐

