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

PowerShell日志旧条目自动消失?如何让.log文件永久增长

日志文件旧条目丢失问题排查与解决

问题描述

通过GPO部署PowerShell脚本,用户登录时会在网络共享创建并写入日志(同时映射驱动器)。使用以下两个日志函数,创建时未启用OverWrite和UseDate开关,但日志写入新条目后旧条目会被删除。现有3000+用户,需要日志文件永久保留所有条目。

原函数代码:

# Generates the log
Function New-Log{
  Param(
    [Parameter(Mandatory=$true,Position=0)]
    [string]$Path,
    [Parameter(Position=1)]
    [string]$Folder=$null,
    [Parameter(Mandatory=$true,Position=2)]
    [string]$Name,
    [Parameter(Position=3)]
    [switch]$OverWrite,
    [Parameter(Position=4)]
    [switch]$UseDate,
    [Parameter(Position=5)]
    [int]$MaxDays = 0
  )

  # New folder (Yes/No)
  if($Folder){
    $logPath = Join-Path -ChildPath $Folder -Path $Path
  }
  else{
    $logPath = $Path
  }

  # Add date to log name (Yes/No)
  if($UseDate.IsPresent){
    $logFile = "$(Get-Date -Format 'dd-MM_HH.mm.ss')_$($Name).log"
  }
  else{
    $logFile = "$Name.log"
  }
  
  # Ovewrite existing log
  if($OverWrite.IsPresent){
    $logFinal = (New-Item -Path $logPath -ItemType File -Name $logFile -Force).FullName
  }
  else{
    if(Test-Path -Path "$logPath\$logFile"){
      $logFinal = "$logPath\$logFile"
    }
    else{
      $logFinal = (New-Item -Path $logPath -ItemType File -Name $logFile -Force).FullName
    }
  }

  # Deletion after a quantity of days
  if($MaxDays -gt 0){
    if((Get-ChildItem -Path $logPath | Measure-Object).Count -gt $MaxDays){
      (Get-ChildItem -Path $logPath | Sort-Object LastWriteTime -Descending | Select-Object -Last 1).FullName | Remove-Item -Force
    }
  }
  return $logFinal
}

# Add log events
Function New-LogEvent{
  Param(
    [Parameter(Mandatory=$true,Position=0)]
    [string]$File,
    [Parameter(Mandatory=$true,Position=1)]
    [string]$Event,
    [switch]$UseSemicolon
  )
  $FLG = Get-Date -Format 'dd/MM/yyyy-HH:mm:ss'
  if($UseSemicolon.IsPresent){
    Add-Content $File -Value "$FLG; $Event"
  }
  else{
    Add-Content $File -Value "$FLG - $Event"
  }
}

问题根源分析

  1. 并发竞态条件:多用户同时执行脚本时,Test-Path判断文件不存在后,到New-Item创建文件的间隙,其他用户可能也完成了同样的判断并创建文件,此时New-Item -Force会直接覆盖已存在的文件,导致旧条目丢失。
  2. MaxDays逻辑错误:原代码中MaxDays是按文件数量而非时间删除文件,即使你未主动设置,若后续误设会导致不符合预期的文件删除。
  3. 权限潜在问题:网络共享若未配置正确的读写权限,可能导致写入时文件被意外覆盖或截断。

解决方案

1. 修复日志创建逻辑,避免并发覆盖

将New-Log中创建文件的逻辑替换为更安全的方式,利用Add-Content的特性(文件不存在时自动创建,存在时追加),彻底避免竞态条件。

2. 修正MaxDays逻辑(按时间清理而非数量)

如果需要保留指定天数内的日志,改为删除超过MaxDays的旧文件,而非按文件数量删除。

3. 验证网络共享权限

确保所有用户对日志路径拥有读取、写入、修改权限,无只读或强制覆盖的权限限制。

修改后的函数代码

# Generates the log
Function New-Log{
  Param(
    [Parameter(Mandatory=$true,Position=0)]
    [string]$Path,
    [Parameter(Position=1)]
    [string]$Folder=$null,
    [Parameter(Mandatory=$true,Position=2)]
    [string]$Name,
    [Parameter(Position=3)]
    [switch]$OverWrite,
    [Parameter(Position=4)]
    [switch]$UseDate,
    [Parameter(Position=5)]
    [int]$MaxDays = 0
  )

  # 构建日志目录路径
  $logPath = if ($Folder) { Join-Path -Path $Path -ChildPath $Folder } else { $Path }
  
  # 确保日志目录存在
  if (-not (Test-Path -Path $logPath)) {
    New-Item -Path $logPath -ItemType Directory -Force | Out-Null
  }

  # 构建日志文件名
  $logFile = if ($UseDate.IsPresent) {
    "$(Get-Date -Format 'dd-MM_HH.mm.ss')_$($Name).log"
  } else {
    "$Name.log"
  }

  $logFinal = Join-Path -Path $logPath -ChildPath $logFile

  # 处理覆盖逻辑
  if ($OverWrite.IsPresent) {
    # 清空文件内容而非删除重建,避免并发问题
    Set-Content -Path $logFinal -Value "" -Force
  } else {
    # 如果文件不存在,创建空文件(用Add-Content更安全,自动处理并发)
    if (-not (Test-Path -Path $logFinal)) {
      Add-Content -Path $logFinal -Value "" -Force
    }
  }

  # 按天数清理旧日志(修正逻辑:删除超过MaxDays的文件)
  if ($MaxDays -gt 0) {
    $cutoffDate = (Get-Date).AddDays(-$MaxDays)
    Get-ChildItem -Path $logPath -Filter "*.log" | 
      Where-Object { $_.LastWriteTime -lt $cutoffDate } | 
      Remove-Item -Force
  }

  return $logFinal
}

# Add log events
Function New-LogEvent{
  Param(
    [Parameter(Mandatory=$true,Position=0)]
    [string]$File,
    [Parameter(Mandatory=$true,Position=1)]
    [string]$Event,
    [switch]$UseSemicolon
  )
  $FLG = Get-Date -Format 'dd/MM/yyyy-HH:mm:ss'
  $logEntry = if ($UseSemicolon.IsPresent) {
    "$FLG; $Event"
  } else {
    "$FLG - $Event"
  }
  # 使用Add-Content追加,确保不会覆盖
  Add-Content -Path $File -Value $logEntry -Force
}

修改说明

  • 日志目录预创建:先确保日志目录存在,避免创建文件时因目录不存在报错。
  • 避免并发覆盖:用Add-Content创建空文件(而非New-Item),即使多用户同时执行,Add-Content也只会追加空内容,不会覆盖已有文件;覆盖逻辑改用Set-Content清空,而非删除重建。
  • 修正日志清理逻辑:按文件最后写入时间删除超过指定天数的日志,符合MaxDays的语义。
  • 强化追加逻辑:New-LogEvent中明确使用Add-Content追加条目,确保不会覆盖原有内容。

额外建议

  • 对于3000+用户的高并发场景,建议为每个用户创建独立日志文件(比如在文件名中加入用户名),避免单文件过大导致的性能问题和冲突。如果必须合并到同一文件,可以考虑使用文件锁定机制(如[System.IO.File]::Open指定FileShare.Read)防止并发写入冲突。
  • 定期备份日志文件,防止意外丢失。

内容的提问来源于stack exchange,提问作者Franco Canciani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:04:51