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

PowerShell Copy-Logs函数通配符使用报错问题求助

解决Copy-Logs函数通配符路径报错问题

问题现象

编写的Copy-Logs函数在指定完整路径(如C:\WINDOWS\logs\Software\)时可正常运行,但使用通配符路径(如C:\WINDOWS\logs\Software\ado*)复制日志时,会报错:

WARNING: Failed to copy 'C:\WINDOWS\logs\Software\ado*': Illegal characters in path.

问题原因

  1. 直接将带通配符的路径传给Copy-Item的Path参数并配合FromSession时,远程端无法正确解析通配符;且Split-Path $log -Leaf会把通配符*当作目标文件名的一部分,而Windows路径不允许包含*字符,导致路径非法。
  2. 原逻辑未先在远程会话中解析通配符、获取实际存在的文件/文件夹路径,直接尝试复制带通配符的路径,引发错误。

解决方案

修改函数逻辑,在远程会话中先解析通配符路径,获取匹配的实际路径后再逐个复制;同时修正目标路径生成逻辑,避免将通配符带入目标路径。

修改后的完整函数代码:

function Copy-Logs {
    [CmdletBinding()]
    param (     
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Specify the name(s) of the computer to run the SCCM actions on, separated by commas ','")]
    [string[]]$TargetComputerName,
        
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Specify the path(s) of logs.")]
    [SupportsWildcards()]
    [string[]]$TargetLogsPaths,
    
    [Parameter(Mandatory=$false, HelpMessage="Specify the folder name for destination.")]
    [ValidateNotNullOrEmpty()]
    [string]$DestName = "logs",
    
    [Parameter(Mandatory=$false, HelpMessage="Specify the Error Action on Copy Item")]
    [ValidateNotNullOrEmpty()]
    [ValidateSet("Continue", "SilentlyContinue", "Stop")]
    [string]$ActionOnError = "Stop",

    [Parameter(Mandatory=$false, HelpMessage="Specifies whether to include verbose output.")]
    [Switch]$WriteVerbose,
    
    [Parameter(Mandatory=$false, HelpMessage="Specify if the function should create a new folder each time it's run.")]
    [switch]$NewFolder,
    
    [Parameter(Mandatory=$false, HelpMessage="Specify the domain controller to use.")]
    [string]$TargetDomainController = ".?.?"
    )
        
    # Convert TargetComputerName to an array if it's a string
    if (-not $TargetComputerName -is [array]) {
        $TargetComputerName = $TargetComputerName -split ","
    }
    
    # Convert TargetLogsPaths to an array if it's a string
    if (-not $TargetLogsPaths -is [array]) {
        $TargetLogsPaths = $TargetLogsPaths -split '\s*,\s*' -split '\s+'
    }
    
    # Gets current user into variable for DestFolder
    $CurrentUser = [System.Environment]::UserName
    
    # Loop through each computer name and copy the specified logs
    foreach($ComputerName in $TargetComputerName) {
        $DateFormat = (Get-Date).ToString('dd-MM-yyyy hh-mm-ss')
        $HostDate = $ComputerName + ' - ' + $DateFormat
        $DestFolder = Join-Path "C:\Temp\$CurrentUser" (Join-Path -Path $HostDate -ChildPath $DestName)
        if ($NewFolder -or (-not(Test-Path $DestFolder))) {
            New-Item -ItemType "directory" -Path $DestFolder -Force | Out-Null
        }
        
        # Create PSSession
        $PC = $ComputerName + $TargetDomainController
        $Session = New-PSSession -ComputerName $PC –UseSSL
                
        foreach ($logPattern in $TargetLogsPaths) { 
            # 在远程会话中解析通配符路径,获取实际存在的文件
            $remotePaths = Invoke-Command -Session $Session -ScriptBlock {
                param($pattern)
                Get-ChildItem -Path $pattern -Recurse -File | Select-Object -ExpandProperty FullName
            } -ArgumentList $logPattern

            if (-not $remotePaths) {
                Write-Warning "No files matched pattern '$logPattern' on computer '$ComputerName'"
                continue
            }

            foreach ($remotePath in $remotePaths) {
                # 保留远程文件的相对目录结构
                $rootDir = Split-Path $logPattern -Parent
                $relativePath = $remotePath -replace [regex]::Escape($rootDir), ''
                $relativePath = $relativePath.TrimStart('\')
                $DestFile = Join-Path $DestFolder $relativePath

                # 创建目标父目录(如果不存在)
                $destDir = Split-Path $DestFile -Parent
                if (-not (Test-Path $destDir)) {
                    New-Item -ItemType Directory -Path $destDir -Force | Out-Null
                }

                $copyParams = @{
                    Path = $remotePath
                    Destination = $DestFile
                    FromSession = $Session
                    ErrorAction = $ActionOnError
                    Verbose = $WriteVerbose
                }
                try {
                    Copy-Item @copyParams -PassThru | ForEach-Object {
                        Write-Progress -Activity "Copying File from $ComputerName" -Status $_.Name -PercentComplete (($_.BytesTransferred / $_.TotalBytes) * 100)
                    }
                } catch {
                    Write-Warning "Failed to copy '$remotePath': $_"
                }
            }
        }
        
        # Close PSSession
        Remove-PSSession $Session
    }
}

关键修改点

  • 修正ActionOnError参数类型:原参数为string[],但Copy-Item的ErrorAction只接受单个字符串值,改为string类型。
  • 在远程会话中用Get-ChildItem解析通配符路径,获取实际存在的文件路径,避免直接复制带通配符的路径。
  • 保留远程文件的相对目录结构,确保复制后的文件层级与远程一致。
  • 自动创建目标文件的父目录,避免因目录不存在导致复制失败。

内容的提问来源于stack exchange,提问作者Matovina Igor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:27:04