2016-06-24 2 views
0

У меня есть очень простой текстовый файл, содержащий имена пользователей. Мне нужно иметь возможность искать каждый раздел, который начинается с «User bsmith» (например), скопировать весь текст, который следует, и закончить в строке, предшествующей следующему «Пользователь XXXX» (например, пользователь tford, например, ниже). Затем я вставляю скопированный текст в тело письма. Я уже написал Powershell, чтобы создать электронное письмо и отправить его. Мне просто нужно написать часть, чтобы захватить текст из указанного текстового файла. Все еще нова к программированию, поэтому трудно определить способ поиска и копирования из файла .txt и вставки в тело электронной почты. Файл svnlog.txt - это файл, обрабатываемый. Я могу получить весь контент, но должен иметь возможность искать разделы для каждого «Пользователь XXXX» для следующего «Пользователь XXX».Powershell - нужно разобрать текстовый файл и прошлое по электронной почте

$olComObject = new-object -comobject outlook.application 
$svn = (Get-Content C:\Dev\Powershell\svnlog.txt) -join "`n" 
$NewMail = $olComObject.CreateItem(0) 
$NewMail.Subject = "Testing Voting Options" 
$NewMail.Body = "Please use the attached voting buttons in this email to acknowledge or reject if the following user permissions are correct!" + "`n" + $svn 
$NewMail.To = "[email protected];[email protected]" 
$NewMail.VotingOptions = "Accept;Reject" 
$NewMail.Send() 

Я думал, возможно, в поисках личности «XXX пользователя» группы, используя следующие, но опять же я не уверен, что это правильный путь, чтобы идти или даже работать.

$fullsvn = Get-Content "C:\Dev\Powershell\svnlog.txt" 
Out-File() "C:\Dev\Powershell\svnlogBSmith.txt" 

Формат текстового файла выглядит следующим образом.

BSmith пользователя

РЕПО

[functionalSpecs: /]

@admins = RW

@dba = г

@hca = RW

@businessAnalysts = rw

@qa = RW

@portal = RW

@intercept = RW

@pmo = RW

[restrictedDocs:/softtek]

@restrictedDocs = RW

Группы

BusinessAnalysts = ajones, pjohnson, ssmith, rjackson,

@pmo = lferguson

пользователя tford

ОК. Поэтому я попробовал маршрут ТесселлингаХеклера. Однако, похоже, это не тегирование строк с именем пользователя (в данном случае это TKelems вместо BSmith). Вот мой текущий код и пример вывода, который я получаю в консоли.

Get-Content C:\Dev\Powershell\svnlog.txt | foreach { 
    if ($_ -match '^User (.*)') { 
     $tag = $matches[1] 
     } 

     [Management.Automation.PSObject]@{ 
      Tag=$tag 
      Item=$_ 
     } 
    } 

$TKelems | Where Tag -EQ 'tkelems' 

Out-File "C:\Dev\Powershell\svnlogTKelems.txt" -InputObject $TKelems 

Выход:

Название Значение
---- -----
Tag
товара ------------------ -------------------------------------------------- ------------
Tag
Пункт пользователя
Tag
Предмет tkelems:
Tag
Item
Tag
Пункт Repos
Tag
товара --------------------
Tag
Item [functionalSpecs: /]
@admins Tag
товара = RW
Tag
товара @eclas = RW
Tag
Item @cfis = RW
Метка
товара @transMgmt = RW
Метка
товара @dba = г
Метка
товара @hca = RW
@businessAnalysts Тэг
Предмет = RW
Метка
товара @qa = RW
Код
Продукт @portal = rw
Отмеченный
Пункт @intercept = rw
Тег

Я также забыл добавить содержимое Ou-файла, созданного в последней строке. Не уверен, что с этим делать. В принципе, теги не отображалось в консоли, а выходной файл показывает что-то совершенно другое (смотрите ниже):

IsReadOnly: Ложные

IsFixedSize: Ложные

IsSynchronized: Ложные

Ключи: { Тег, пункт}

Значения: {$ null, ------------------------------------ --------------------------------------------}

SyncRoot: система.Объект

Количество: 2

IsReadOnly: Ложные

IsFixedSize: Ложные

IsSynchronized: Ложные

Ключи: {Tag, Предмет}

значения: {$ нуль, Пользователь}

SyncRoot: System .Object

Количество: 2

+0

пожалуйста, мимо текстового файла –

+0

Вы не присваивающей '$ TKelems' где-нибудь в вашем сценарии ... как это даже любой контент вообще? Сделайте первую строку '$ TKelems = Get-Content ... | Foreach {'и попробуйте. – TessellatingHeckler

+0

Хорошо. Благодарю. Я думал, что в последней строке это будет позаботиться об этом. Я попробую. – ClaySean

ответ

0

что-то подобное может быть отправной точкой

$usernameregex = 'bsmith' 

$found = $false 
Get-Content "C:\Dev\Powershell\svnlog.txt" | % { 
    if (!$found -and $_ -match "^user $username$") { 
     $found = $true 
     Write-Output '' 
     Write-Output $_ 
    } elseif ($found -and $_ -match '^user ') { 
     if (!($_ -match "^user $username$")) { 
      $found = $false 
     } elseif ($_ -match "^user $username$") { 
      Write-Output '' 
      Write-Output $_ 
     } else { 
      Write-Output '' 
     } 
    } elseif ($found) { 
     Write-Output $_ 
    } 
} | select -skip 1 | Set-Content "C:\Dev\Powershell\svnlogBSmith.txt" 

проверить несколько имен, изменить $ usernameregex этот вариант

$usernameregex = (bsmith|tford) 
2

One:

$textfile = 'c:\testfiles\test.txt' 

$Search = 'BSmith' 

$Found = (Get-Content $textfile -Raw) -split '(?ms)^(?=User)' -like "User $Search*" 

Это будет читать текстовый файл в виде одной строки, а затем разделить его на строки, начинающиеся с «Пользователь», и отфильтровать те, которые не совпадают с именем пользователя в $ Search.

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

+0

Я всегда с нетерпением жду ваших ответов. я склоняюсь к чрезмерному размытию регулярных выражений. –

+0

. Снова. Многопользовательское регулярное выражение может быть пугающим сначала (главным образом потому, что вы не видите много примеров), но, кажется, всегда обеспечивает более простое решение для разбора многострочного текста, как только вы получите ручка на нем. – mjolinor

0

Я видел это «Я хочу строки в файл из [раздела заголовка] к следующему [заголовку раздела]» раньше, и ответ mjolinor с многострочным регулярным выражением является коротким и эффективным, но я не думаю, что это очень ясно, что это делает и почему. И он не будет работать так же хорошо на общем массиве строк без -join.

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

gc .\log.txt | foreach { 
    if ($_ -match '^User (.*)') { 
     $tag = $matches[1] 
    } 

    [pscustomobject]@{ 
     Tag=$tag 
     Item=$_ 
    } 
} 

Что он делает с вашим файлом заключается в следующем:

Tag     Item              
----     ----              
BSmith     User BSmith            
BSmith     repos              
BSmith     [functionalSpecs:/]          
BSmith     @admins = rw            
BSmith     @dba = r             
BSmith     @hca = rw             
BSmith     @businessAnalysts = rw         
BSmith     @qa = rw             
BSmith     @portal = rw            
BSmith     @intercept = rw           
BSmith     @pmo = rw             
BSmith     [restrictedDocs:/softtek]         
BSmith     @restrictedDocs = rw          
BSmith     Groups             
BSmith     BusinessAnalysts = ajones, pjohnson, ssmith, rjackson, 
BSmith     @pmo = lferguson           
tford     User tford            
tford        

Тогда вы можете легко:

$that | Where Tag -eq 'BSmith' 

или

$that | group Tag 

Он может маркировать линию s с любым регулярным выражением для разделителей разделов.

[Edit: Добавлен ^ в регулярное выражение, предложенный @mjolinor]

+0

Это решение тоже будет работать, но оно может не очень хорошо масштабироваться, если вы имеете дело с большим количеством строк. Я бы посоветовал включить начало линейного якоря (^) в этом регулярном выражении. В его нынешнем виде он имеет большой потенциал для непредвиденных последствий. Строковый «пользователь» может легко появиться в произвольных данных, следующих за заголовком раздела, а затем вы получите неожиданные результаты. ИМХО. – mjolinor

+0

@mjolinor Я согласен с обоими пунктами (но будет ли масштаб GC-Raw для большого количества строк? Это не обязательно читать их все, прежде чем он сможет начать работать), и якорь начала строки сделает его более надежным. Я думаю, что общее решение для такого рода «* извлечь строки из X в Y *» может быть разумным дополнением к Select-String, поэтому я предложил его в сервисе PowerShell: https://windowsserver.uservoice.com/forums/301869-powershell/ideas/14951235-add-parameters-to-select-string-for-matching-all-l – TessellatingHeckler

+0

Либо один из них начнет страдать от исчерпания памяти, учитывая достаточно большой входной файл, но преобразуя каждую строку в объект PS будет делать это намного быстрее. Я экстраполировал опубликованные данные на 5000 пользователей и провел их через оба решения. Для разбиения на многострочные строки потребовалось около 12 МБ памяти. Оказание каждой линии в качестве объекта PS занимало почти половину концерта. – mjolinor

Смежные вопросы