You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell脚本上传O365用户照片后遇ConvertTo-Json内存不足异常求助

问题与解决方案:PowerShell上传O365用户照片时的内存溢出异常

问题背景

写了一段PowerShell脚本,功能是检查O365用户是否已存在头像;如果不存在,就检查本地是否有对应用户的照片文件,有则用Set-UserPhoto上传(当前环境没有Set-MgUserPhotoContent权限)。但上传5-6张照片后,会抛出ConvertTo-Json : Exception of type 'System.OutOfMemoryException' was thrown错误,还需要保证脚本末尾能正常生成报告。之前试过用[System.IO.MemoryStream]::new()替代ReadAllBytes,但适配不了Set-UserPhoto命令。

原脚本代码:

foreach ($Object in $PictureStatus) {
    $Name = $Object.DisplayName
    $Picture= Get-MgUserPhoto -UserID $Object.UserPrincipalName -erroraction 'silentlycontinue'
    Write-Progress -Activity 'Processing' -CurrentOperation $name -PercentComplete (($counter / $picturestatus.count) * 100)
    Start-Sleep -Milliseconds 200

        if ($Picture -ne $Null){
              
                        #has a picture in O365.
                        $Properties = [ordered]@{'UserName'=$Name;'Picture Present'='True';'Picture on File'='NA';'Picture Uploaded'='False'}

                        $Output_365Report += New-Object -TypeName PSObject -Property $Properties


                     }Else {

                        $TempVari=Get-ChildItem -Filter "$Name*" -File -Path $PhotoDatabase | where Length -gt 14kb
                        #Write-Output $TempVari                      

                              if ($TempVari -eq $null){
            
                                    #no Picture in Database
                                    $Properties = [ordered]@{'UserName'=$Name;'Picture Present'='False';'Picture on File'='False';'Picture Uploaded'='False'}

                                    $Output_365Report += New-Object -TypeName PSObject -Property $Properties

                              } else{
            
                                    #Photo Upload to 365
                                    Set-UserPhoto -Identity $Object.SamAccountName -PictureData ([System.IO.File]::ReadAllBytes("$PhotoDatabase"+"\$TempVari")) -Confirm:$False
                                    
                                    $Properties = [ordered]@{'UserName'=$Name;'Picture Present'='False';'Picture on File'='True';'Picture Uploaded'='True'}

                                    $Output_365Report += New-Object -TypeName PSObject -Property $Properties
                                }
                                
}

异常原因分析

  1. 数组累加的内存浪费:用$Output_365Report += ...的方式每次都会创建新数组,旧数组不会被及时回收,随着处理用户增多,内存占用持续上涨。
  2. 图片字节数组未及时释放:[System.IO.File]::ReadAllBytes()会把整张图片一次性读进内存,且用完后没有主动释放,多张图片累积后触发内存溢出。
  3. 未清理临时变量:循环中的$Picture、$TempVari等变量在循环结束后仍占用内存,没有及时回收。
  4. 路径拼接错误:原代码中"$PhotoDatabase"+"\$TempVari"的写法,因$TempVari是FileInfo对象,可能生成无效路径,间接引发额外内存开销或错误。

解决方案与优化代码

关键优化点

  • 用System.Collections.ArrayList替代普通数组存储报告数据,避免每次重建数组的内存开销。
  • 读取图片后主动释放字节数组内存,配合垃圾回收减少内存占用。
  • 循环结束后清理临时变量,避免内存泄漏。
  • 修正路径处理逻辑,直接使用文件对象的FullName属性获取有效路径。
  • 增加异常捕获,避免上传失败导致脚本中断,同时记录失败状态。

优化后的脚本

# 初始化ArrayList存储报告,替代原数组(避免每次重建数组的内存浪费)
$Output_365Report = New-Object System.Collections.ArrayList
$counter = 0

foreach ($Object in $PictureStatus) {
    $counter++
    $Name = $Object.DisplayName
    Write-Progress -Activity 'Processing' -CurrentOperation $Name -PercentComplete (($counter / $PictureStatus.Count) * 100)

    # 检查O365头像,先清空变量再赋值,避免残留旧数据
    $Picture = $null
    $Picture = Get-MgUserPhoto -UserID $Object.UserPrincipalName -ErrorAction 'SilentlyContinue'

    if ($Picture) {
        # 用户已有O365头像
        $Properties = [ordered]@{
            'UserName'         = $Name
            'Picture Present'  = 'True'
            'Picture on File'  = 'NA'
            'Picture Uploaded' = 'False'
        }
        # 用[void]抑制Add方法返回的索引值,避免干扰输出
        [void]$Output_365Report.Add((New-Object -TypeName PSObject -Property $Properties))
    }
    else {
        # 查找本地照片,修正过滤逻辑的写法
        $TempVari = Get-ChildItem -Filter "$Name*" -File -Path $PhotoDatabase | Where-Object { $_.Length -gt 14KB }
        if (-not $TempVari) {
            # 本地无对应照片
            $Properties = [ordered]@{
                'UserName'         = $Name
                'Picture Present'  = 'False'
                'Picture on File'  = 'False'
                'Picture Uploaded' = 'False'
            }
            [void]$Output_365Report.Add((New-Object -TypeName PSObject -Property $Properties))
        }
        else {
            # 上传照片,优化内存使用
            $pictureBytes = $null
            $pictureBytes = [System.IO.File]::ReadAllBytes($TempVari.FullName)
            $uploadStatus = 'True'
            try {
                Set-UserPhoto -Identity $Object.SamAccountName -PictureData $pictureBytes -Confirm:$False
            }
            catch {
                $uploadStatus = 'False'
                Write-Warning "上传$Name的照片失败:$_"
            }
            finally {
                # 主动触发垃圾回收,释放图片字节数组占用的内存
                [System.GC]::Collect()
                [System.GC]::WaitForPendingFinalizers()
            }

            $Properties = [ordered]@{
                'UserName'         = $Name
                'Picture Present'  = 'False'
                'Picture on File'  = 'True'
                'Picture Uploaded' = $uploadStatus
            }
            [void]$Output_365Report.Add((New-Object -TypeName PSObject -Property $Properties))
        }
    }

    # 清理当前循环的临时变量,释放内存
    Remove-Variable -Name Picture, TempVari, pictureBytes -ErrorAction SilentlyContinue
    Start-Sleep -Milliseconds 200
}

# 生成最终报告(示例为导出CSV,可根据需求调整格式)
$Output_365Report | Export-Csv -Path ".\O365UserPhotoReport.csv" -NoTypeInformation -Encoding UTF8

内容的提问来源于stack exchange,提问作者IT Analyst UT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:03:15