Добавить из текста в таблицу - Powershell - PullRequest
1 голос
/ 15 февраля 2020

Я пытаюсь создать скрипт, который берет содержимое текстового файла и добавляет его к рабочему листу, но останавливается при первом совпадении. Я хочу, чтобы он go прошел через весь текстовый файл и добавил КАЖДОЕ совпадение к рабочему листу.

Текстовый файл:

Node: ABC
Name: PC
Cluster: HS1
Node: XZZ
Name: CC
Cluster: HS2
Node: XYZ
Name: DD
Cluster: HS3

Как я хочу, чтобы оно было

Node|Name|Cluster
ABC    PC   HS1
XZZ    CC   HS2
XYZ    DD   HS3

Я использую следующий код:

$WorkbookPath = "Destination Path"
$Patterns = "Name"
$Testbestand = get-content "Source Path"
$sheetName = "Sheet1"
$objExcel = New-Object -ComObject Excel.Application
$WorkBook = $objExcel.Workbooks.Open($WorkbookPath)
$WorkSheet = $WorkBook.sheets.item($sheetName)
$usedRange = $WorkSheet.usedRange
$lastCell = $usedRange.SpecialCells(11)
$newRow = $lastCell.row + 1
foreach ($Pattern in $Patterns){
$AlertValue = $Testbestand | Select-string -pattern $Pattern -list -quiet
$AlertValue = ($AlertValue -split " ")[-1]
$col = ($Worksheet.Columns.Find($pattern))
$WorkSheet.cells.item($newRow, $col.Column).value = $AlertValue
}#foreach pattern
$WorkBook.Save()
$objExcel.Quit()

Ответы [ 3 ]

2 голосов
/ 15 февраля 2020

Вы можете преобразовать имеющийся у вас текстовый файл в соответствующий файл CSV и без особых усилий импортировать его в Excel.

# read the file as a single string including newlines
$content = Get-Content -Path 'TheInputFile' -Raw

# create a regex to parse the file
$regex = [regex] '(?i)Node:\s*(?<node>[^\r\n]*)\r?\nName:\s*(?<name>[^\r\n]*)\r?\nCluster:\s*(?<cluster>[^\r\n]*)'
$match = $regex.Match($content)

# collect the resulting PSObjects in variable $result
$result = while ($match.Success) {
    [PsCustomObject]@{
        'Node'    = $match.Groups['node'].Value
        'Name'    = $match.Groups['name'].Value
        'Cluster' = $match.Groups['cluster'].Value
    }
    $match = $match.NextMatch()
} 

# output on screen
$result

# output to CSV file (if you like)
# $result | Export-Csv -Path 'TheOutputFile' -UseCulture -NoTypeInformation

Результат на экране:

Node Name Cluster
---- ---- -------
ABC  PC   HS1    
XZZ  CC   HS2    
XYZ  DD   HS3


Обновление

Этот массив $result можно использовать для вставки данных в файл Excel. Примерно так:

# first use the above code to parse the text file into an array of PSObjects.

# next, insert data from the $result array in the Excel
$WorkbookPath = "Destination Path"
$sheetName    = "Sheet1"
$objExcel     = New-Object -ComObject Excel.Application
$WorkBook     = $objExcel.Workbooks.Open($WorkbookPath)
$WorkSheet    = $WorkBook.sheets.item($sheetName)
$usedRange    = $WorkSheet.usedRange
$lastCell     = $usedRange.SpecialCells(11)

# determine the row and column positions
$row = $lastCell.row + 1
$colNode = ($Worksheet.Columns.Find("Node"))
$colName = ($Worksheet.Columns.Find("Name"))
$colCluster = ($Worksheet.Columns.Find("Cluster"))

# now loop through the parsed $result array
$result | ForEach-Object {
    $WorkSheet.cells.item($row, $colNode.Column).value = $_.Node
    $WorkSheet.cells.item($row, $colName.Column).value = $_.Name
    $WorkSheet.cells.item($row, $colCluster.Column).value = $_.Cluster
    $row++
}

$WorkBook.Save()
$objExcel.Quit()

# release COM objects from memory
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($WorkBook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($objExcel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()

Regex Подробности:

(?i)               Make the Match work case-insensitive
Node:              Match the characters “Node:” literally
\s                 Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
(?<node>           Match the regular expression below and capture its match into backreference with name “node”
   .               Match any single character that is not a line break character
      *            Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
\r                 Match a carriage return character
   ?               Between zero and one times, as many times as possible, giving back as needed (greedy)
\n                 Match a line feed character
Name:              Match the characters “Name:” literally
\s                 Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
(?<name>           Match the regular expression below and capture its match into backreference with name “name”
   .               Match any single character that is not a line break character
      *            Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
\r                 Match a carriage return character
   ?               Between zero and one times, as many times as possible, giving back as needed (greedy)
\n                 Match a line feed character
Cluster:           Match the characters “Cluster:” literally
\s                 Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
(?<cluster>        Match the regular expression below and capture its match into backreference with name “cluster”
   .               Match any single character that is not a line break character
      *            Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
0 голосов
/ 17 февраля 2020

Если я вас понимаю, голландский комментарий Гибкость необходима, потому что она включает в себя различные выходные данные с разными целевыми файлами (и столбцами) при отличном Ответ Тео : вот мой старый -школа подход:

$fileContent = @'
Node: ABC
Name: PC
Cluster: HS1
FooBar: x11
Node: XZZ
Name: CC
Cluster: HS2
FooBar: x12
Node: XYZ
Name: DD
Cluster: HS3
FooBar: x13
'@
$Testbestand = $fileContent.Split( [System.Environment]::NewLine,
          [System.StringSplitOptions]::RemoveEmptyEntries )
### all code above substitutes $Testbestand = Get-Content "Source Path"

# compute properties from given file
$linieIdLast = ''
$linieTemplate = [ordered]@{}
foreach ( $linie in $Testbestand ) {
    $linieId, $linieVal = $linie -split ":\s*",2
    if ( $linieId -in $linieTemplate.Keys ) {
        break
    } else {
        $linieIdLast = $linieId
        $linieTemplate.Add( $linieId, $Null )
    }
}

# apply computed properties to de-serialize given file
$linieComb = New-Object -TypeName PSCustomObject -Property $linieTemplate
$liniesAll = foreach ( $linie in $Testbestand ) {
    $linieId, $linieVal = $linie -split ":\s*",2
    $linieComb."$linieId" = $linieVal.Trim()
    if ( $linieId -eq $linieIdLast ) {
        $linieComb
        $linieComb = New-Object -TypeName PSCustomObject -Property $linieTemplate
    }
}

$liniesAll   # debugging output
''           # dtto

###########################################################
#                                                         #
# the following code snippet is stolen from Theo's answer #
#                                                         #
###########################################################
$row = 33        # an example instead of $row = $lastCell.row + 1

# now loop through the parsed $liniesAll array
$liniesAll | ForEach-Object {
    # and loop through the properties
    foreach ( $linieKey in $linieTemplate.Keys ) {
       # the next line is merely displayed; 
       # remove all "Quotation Marks" and `Grave Accents` to make it operational
       "`$WorkSheet.cells.item($row, (`$Worksheet.Columns.Find($linieKey))).value = `$_.$linieKey"
    }
    $row++
}
# end of stolen code snippet

Выход : .\SO\60233929a.ps1

Node Name Cluster FooBar
---- ---- ------- ------
ABC  PC   HS1     x11   
XZZ  CC   HS2     x12   
XYZ  DD   HS3     x13   

$WorkSheet.cells.item(33, ($Worksheet.Columns.Find(Node))).value = $_.Node
$WorkSheet.cells.item(33, ($Worksheet.Columns.Find(Name))).value = $_.Name
$WorkSheet.cells.item(33, ($Worksheet.Columns.Find(Cluster))).value = $_.Cluster
$WorkSheet.cells.item(33, ($Worksheet.Columns.Find(FooBar))).value = $_.FooBar
$WorkSheet.cells.item(34, ($Worksheet.Columns.Find(Node))).value = $_.Node
$WorkSheet.cells.item(34, ($Worksheet.Columns.Find(Name))).value = $_.Name
$WorkSheet.cells.item(34, ($Worksheet.Columns.Find(Cluster))).value = $_.Cluster
$WorkSheet.cells.item(34, ($Worksheet.Columns.Find(FooBar))).value = $_.FooBar
$WorkSheet.cells.item(35, ($Worksheet.Columns.Find(Node))).value = $_.Node
$WorkSheet.cells.item(35, ($Worksheet.Columns.Find(Name))).value = $_.Name
$WorkSheet.cells.item(35, ($Worksheet.Columns.Find(Cluster))).value = $_.Cluster
$WorkSheet.cells.item(35, ($Worksheet.Columns.Find(FooBar))).value = $_.FooBar
0 голосов
/ 16 февраля 2020

Что касается этого ...

Спасибо за ваш ответ. Разве нельзя провести через шаблоны и добавить текстовые файлы? -

... конечно, есть несколько способов преобразовать это во что-то более удобное для использования ...

Тем не менее, вам действительно нужно поразить людей, чтобы исправить файл при экспорте из независимо от того, из какого инструмента это получилось, до правильного формата файла, который вы можете использовать до того, как получите его. Экономия каждому драгоценного времени. Тем не менее, иногда нам приходится иметь дело с тем, что мы получаем.

@'
Node: ABC
Name: PC
Cluster: HS1
Node: XZZ
Name: CC
Cluster: HS2
Node: XYZ
Name: DD
Cluster: HS3
'@ | Out-File -FilePath 'D:\Temp\TextData.txt'


$FileContent = Get-Content -Path 'D:\Temp\TextData.txt'
0..(($FileContent -match '^Node' -replace '^Node: ' ).Count -1) | 
Select-Object @{Name = "Node";Expression = {($FileContent -match '^Node' -replace '^Node: ')[$PSitem]}},
@{Name = "Name";Expression = {($FileContent -match '^Name' -replace '^Name: ')[$PSitem]}},
@{Name = "Cluster";Expression = {($FileContent -match '^Cluster' -replace '^Cluster: ')[$PSitem]}} | 
Export-Csv -Path 'D:\Temp\TextData.csv' -NoTypeInformation

Get-Content -Path 'D:\Temp\TextData.csv'
Import-Csv -Path 'D:\Temp\TextData.csv'

<#
Node Name Cluster
---- ---- -------
ABC  PC   HS1    
XZZ  CC   HS2    
XYZ  DD   HS3    
#>


# Or this way
$FileContent = Get-Content -Path 'D:\Temp\TextData.txt'
0..(($FileContent -match '^Node' -replace '^Node: ' ).Count -1) | 
ForEach{ 
    [PSCustomObject]@{
        Node = (($FileContent -match '^Node' -replace '^Node: ')[$_] )
        Name = (($FileContent -match '^Name' -replace '^Name: ')[$_] )
        Cluster = (($FileContent -match '^Cluster' -replace '^Cluster: ')[$_])
    }
} | 
Export-Csv -Path 'D:\Temp\TextData.csv' -NoTypeInformation

Get-Content -Path 'D:\Temp\TextData.csv'
Import-Csv -Path 'D:\Temp\TextData.csv'

<#
Node Name Cluster
---- ---- -------
ABC  PC   HS1    
XZZ  CC   HS2    
XYZ  DD   HS3    
#>

После того, как у вас есть вышеперечисленное, добавляйте, как вам нужно.

Всегда есть способы. некоторые из них более элегантны, чем другие, но вам нужно изучить это и решить, что подходит для вашего варианта использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...