Есть ли способ включить пути к файлам с диакритическими знаками в скрипт robocopy?

У меня есть сценарий, который извлекает метаданные из каждого файла в каталоге. Если путь к файлу не содержит диакритических знаков, сценарий создает файл csv, который выглядит следующим образом:

Если путь к файлу включает диакритический знак (например, "TéstMé.txt"), в файле CSV есть пробелы в поле filehash:

У меня вопрос: как заставить этот скрипт работать независимо от диакритических знаков в пути к файлу?

  • Я определил, что проблема не в Get-FileHash часть скрипта (когда я запускаю единственную строку Get-FileHash "C:\Temp\New\TéstMé.txt" создается хэш.)
  • Я также определил, что замена FileHash = Get-FileHash -Path с FileHash = Get-FileHash -LiteralPath не является решением, так как также производит пробел.
  • Я попытался изменить регулярное выражение в строке ($_.Trim() -match "^(?<Children>\d+)\s+(?<FullName>.*)") { в случае, если он блокировал диакритические знаки, но любое изменение вызовет WARNING: parsing [unique parsing error here].
  • Я тоже пытался изменить ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True из $true к $false (в случае, если конвейер менял значение пути к файлу), но это не повлияло.
  • Я подумал, что, возможно, Robocopy (который используется в сценарии) не может обрабатывать файлы с диакритическими знаками, но Robocopy C:\Temp\New C:\Temp\star перемещает файлы нормально.
  • У меня есть регулярное выражение для определения недопустимых символов (полученное отсюда), но я не знаю, как включить его в сценарий.
  • К вашему сведению: я не могу изменить фактические имена файлов. Хотел бы найти и заменить любую букву с диакритическим знаком, но этот вариант мне недоступен.
      Function Get-FolderItem {
    
        [cmdletbinding(DefaultParameterSetName='Filter')]
        Param (
            [parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
            [Alias('FullName')]
            [string[]]$Path = $PWD,
            [parameter(ParameterSetName='Filter')]
            [string[]]$Filter = '*.*',    
            [parameter(ParameterSetName='Exclude')]
            [string[]]$ExcludeFile,              
            [parameter()]
            [int]$MaxAge,
            [parameter()]
            [int]$MinAge
        )
        Begin {
            $params = New-Object System.Collections.Arraylist
            $params.AddRange(@("/L","/E","/NJH","/BYTES","/FP","/NC","/XJ","/R:0","/W:0","T:W"))
            If ($PSBoundParameters['MaxAge']) {
                $params.Add("/MaxAge:$MaxAge") | Out-Null
            }
            If ($PSBoundParameters['MinAge']) {
                $params.Add("/MinAge:$MinAge") | Out-Null
            }
        }
        Process {
            ForEach ($item in $Path) {
                Try {
                    $item = (Resolve-Path -LiteralPath $item -ErrorAction Stop).ProviderPath
                    If (-Not (Test-Path -LiteralPath $item -Type Container -ErrorAction Stop)) {
                        Write-Warning ("{0} is not a directory and will be skipped" -f $item)
                        Return
                    }
                    If ($PSBoundParameters['ExcludeFile']) {
                        $Script = "robocopy `"$item`" NULL $Filter $params /XF $($ExcludeFile  -join ',')"
                    } Else {
                        $Script = "robocopy `"$item`" NULL $Filter $params"
                    }
                    Write-Verbose ("Scanning {0}" -f $item)
                    Invoke-Expression $Script | ForEach {
                        Try {
                            If ($_.Trim() -match "^(?<Children>\d+)\s(?<FullName>.*)") {
                               $object = New-Object PSObject -Property @{
                                    FullName = $matches.FullName
                                    Extension = $matches.fullname -replace '.*\.(.*)','$1'
                                    FullPathLength = [int] $matches.FullName.Length
                                    FileHash = Get-FileHash -LiteralPath "\\?\$($matches.FullName)" |Select -Expand Hash
                                    Created = ([System.IO.FileInfo] $matches.FullName).creationtime
                                    LastWriteTime = ([System.IO.FileInfo] $matches.FullName).LastWriteTime
                                    
                                } 
                                $object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo')
                                Write-Output $object
                            } Else {
                                Write-Verbose ("Not matched: {0}" -f $_)
                            }
                        } Catch {
                            Write-Warning ("{0}" -f $_.Exception.Message)
                            Return
                        }
                    }
                } Catch {
                    Write-Warning ("{0}" -f $_.Exception.Message)
                    Return
                }
            }
        }
    }
    
 Get-FolderItem "C:\Temp\New" | Export-Csv -Path C:\Temp\testesting.csv


1 ответ

Вот решение, я вывожу вывод RoboCopy в журнал Unicode, используя /UNILOG:c:\temp\test.txt params, а затем используйте тот же код

      Function Get-FolderItem {
    
        [cmdletbinding(DefaultParameterSetName='Filter')]
        Param (
            [parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
            [Alias('FullName')]
            [string[]]$Path = $PWD,
            [parameter(ParameterSetName='Filter')]
            [string[]]$Filter = '*.*',    
            [parameter(ParameterSetName='Exclude')]
            [string[]]$ExcludeFile,              
            [parameter()]
            [int]$MaxAge,
            [parameter()]
            [int]$MinAge
        )
        Begin {
            $params = New-Object System.Collections.Arraylist
            $params.AddRange(@("/L","/E","/NJH","/BYTES","/FP","/NC","/XJ","/R:0","/W:0","T:W","/UNILOG:c:\temp\test.txt"))
            If ($PSBoundParameters['MaxAge']) {
                $params.Add("/MaxAge:$MaxAge") | Out-Null
            }
            If ($PSBoundParameters['MinAge']) {
                $params.Add("/MinAge:$MinAge") | Out-Null
            }
        }
        Process {
            ForEach ($item in $Path) {
                Try {
                    $item = (Resolve-Path -LiteralPath $item -ErrorAction Stop).ProviderPath
                    If (-Not (Test-Path -LiteralPath $item -Type Container -ErrorAction Stop)) {
                        Write-Warning ("{0} is not a directory and will be skipped" -f $item)
                        Return
                    }
                    If ($PSBoundParameters['ExcludeFile']) {
                        $Script = "robocopy `"$item`" NULL $Filter $params /XF $($ExcludeFile  -join ',')"
                    } Else {
                        $Script = "robocopy `"$item`" NULL $Filter $params"
                    }
                    Write-Verbose ("Scanning {0}" -f $item)
                    Invoke-Expression $Script | Out-Null
                    get-content "c:\temp\test.txt" | ForEach {
                        Try {
                            If ($_.Trim() -match "^(?<Children>\d+)\s(?<FullName>.*)") {
                               $object = New-Object PSObject -Property @{
                                    FullName = $matches.FullName
                                    Extension = $matches.fullname -replace '.*\.(.*)','$1'
                                    FullPathLength = [int] $matches.FullName.Length
                                    FileHash = Get-FileHash -LiteralPath "\\?\$($matches.FullName)" |Select -Expand Hash
                                    Created = ([System.IO.FileInfo] $matches.FullName).creationtime
                                    LastWriteTime = ([System.IO.FileInfo] $matches.FullName).LastWriteTime
                                    
                                } 
                                $object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo')
                                Write-Output $object
                            } Else {
                                Write-Verbose ("Not matched: {0}" -f $_)
                            }
                        } Catch {
                            Write-Warning ("{0}" -f $_.Exception.Message)
                            Return
                        }
                    }
                } Catch {
                    Write-Warning ("{0}" -f $_.Exception.Message)
                    Return
                }
            }
        }
    }
    
 $a = Get-FolderItem "C:\Temp\New" | Export-Csv -Path C:\Temp\testtete.csv -Encoding Unicode
Другие вопросы по тегам