Разделить текст по столбцам в PowerShell

Вопрос:Я новичок в PowerShell (Bash - это моя вещь обычно), кто в настоящее время пытается получить вывод qwinsta, чтобы показать, кто зарегистрирован как пользователь rdpwd (rdesktop), чтобы я мог проверять каждое имя пользователя на список от имени пользователя, и если они не совпадают, выйдите из системы. В настоящее время я работаю над двумя проблемами: Я

Вопрос:

Я новичок в PowerShell (Bash – это моя вещь обычно), кто в настоящее время пытается получить вывод qwinsta, чтобы показать, кто зарегистрирован как пользователь rdpwd (rdesktop), чтобы я мог проверять каждое имя пользователя на список от имени пользователя, и если они не совпадают, выйдите из системы.

В настоящее время я работаю над двумя проблемами:

  • Я не могу разделить вывод qwinsta, оставаясь только с именем пользователя – я пробовал функцию “split”, но до сих пор я получаю либо проблемы синтаксиса, либо странные результаты; Кажется, что одна рука состоит в том, что ‘ s +’ соответствует букве S вместо пробела; в других случаях мне удалось разделить на второй столбец, но появляется только вывод из строки 1
  • Пока я еще не пришел, я чувствую, что у меня также будут проблемы со вторым шагом, а именно: цикл через массив не-log-offable пользователей (которые должны быть получены из локальной группы пользователей)

Сейчас я остановлюсь на проблеме 1!

Текст, который у меня есть:

SESSIONNAME USERNAME ID STATE TYPE DEVICE services 0 Disc console 1 Conn rdp-tcp#0 user.name1 2 Active rdpwd rdp-tcp#1 user.name2 3 Active rdpwd rdp-tcp#1 user.name3 4 Active rdpwd rdp-tcp 65536 Listen

Выход, который я хочу:

user.name1 user.name2 user.name3

(С целью создания цикла, вкратце говорящего, “foreach user in list, если не в localgroup, logoff user”.)

До сих пор я добирался до выбора текста с помощью “rdpwd”, но, используя всевозможные варианты “split”, у меня нет дальнейшего продвижения вперед.

Я рад поделиться тем, что у меня уже есть, но, увы, я не думаю, что это поможет кому угодно!

Любая помощь будет наиболее оценена.:)

Ответ №1

Честно говоря, я бы поискал лучший способ сделать это, но вы можете подделать его с помощью некоторых текстовых манипуляций и командлета ConvertFrom-Csv:

$(qwinsta.exe) -replace «^[s>]» , «» -replace «s+» , «,» | ConvertFrom-Csv | select username

Сначала замените любые ведущие пробелы или > символами ничем, а затем замените любые пробелы запятой. Затем вы можете подключиться к ConvertFrom-Csv и работать с данными как с объектом.

ИЗМЕНИТЬ

На самом деле, у вышеупомянутого есть некоторые проблемы, в основном с s+, потому что если столбец пуст, он не получает корректного распознавания как пустое поле, а следующий текст некорректно продвигается в текущее поле.

Ниже представлен полный анализ синтаксического анализатора для этой команды и, вероятно, будет работать для любого вида табличного вывода из родного окна exe:

$o = @() $op = $(qwinsta.exe) $ma = $op[0] | Select-String «(?:[s](w+))» -AllMatches $ErrorActionPreference = «Stop» for($j=1; $j -lt $op.length; $j++) { $i = 0 $obj = new-object pscustomobject while ($i -lt $ma.matches.count) { $prop = $ma.matches[$i].groups[1].value; $substrStart = $ma.matches[$i].index $substrLen = $ma.matches[$i+1].index — $substrStart try { $obj | Add-Member $prop -notepropertyvalue $op[$j].substring($substrStart,$substrLen).trim() } catch [ArgumentOutOfRangeException] { $substrLen = $op[$j].length — $substrStart if($substrLen -gt 0) { $obj | Add-Member $prop -notepropertyvalue $op[$j].substring($substrStart,$substrLen).trim() } else { $obj | Add-Member $prop -notepropertyvalue «» } } $i++ } $o += ,$obj } $o | ? { $_.type -eq ‘rdpwd’} | select username USERNAME ——— user.name1 user.name2 user.name3 Ответ №2

Не могу точно сказать, но похоже, что вы пытаетесь выполнить разделение регулярных выражений с помощью метода string .split(). Это не работает. Используйте оператор Powershell -split для выполнения разложения регулярных выражений:

(@’ SESSIONNAME USERNAME ID STATE TYPE DEVICE services 0 Disc console 1 Conn rdp-tcp#0 user.name1 2 Active rdpwd rdp-tcp#1 user.name2 3 Active rdpwd rdp-tcp#1 user.name3 4 Active rdpwd rdp-tcp 65536 Liste ‘@).split(«`n») | foreach {$_.trim()} | sv x $x -match ‘rdpwd’ | foreach { ($_ -split ‘s+’)[1] } user.name1 user.name2 user.name3 Ответ №3

Мой выбор разделителя позиции. Все остальные ответы дают вам информацию, которую вы ищете, но, как и Arco, я искал ответ на объект PowerShell. Это предполагает, что $data заполняется новым текстовым разделителем текста, который вы могли бы получить из get-content, который мог бы легко разделить результат от qwinsta.exe ($data = (qwinsta.exe) -split «`r`n», например)

$headerString = $data[0] $headerElements = $headerString -split «s+» | Where-Object{$_} $headerIndexes = $headerElements | ForEach-Object{$headerString.IndexOf($_)} $results = $data | Select-Object -Skip 1 | ForEach-Object{ $props = @{} $line = $_ For($indexStep = 0; $indexStep -le $headerIndexes.Count — 1; $indexStep++){ $value = $null # Assume a null value $valueLength = $headerIndexes[$indexStep + 1] — $headerIndexes[$indexStep] $valueStart = $headerIndexes[$indexStep] If(($valueLength -gt 0) -and (($valueStart + $valueLength) -lt $line.Length)){ $value = ($line.Substring($valueStart,$valueLength)).Trim() } ElseIf ($valueStart -lt $line.Length){ $value = ($line.Substring($valueStart)).Trim() } $props.($headerElements[$indexStep]) = $value } [pscustomobject]$props } $results | Select-Object sessionname,username,id,state,type,device | Format-Table -auto

Этот подход основан на позиции полей заголовка. Ничто не жестко закодировано, и все это настраивается на основе этих индексов и имен полей. Используя те $headerIndexes, мы вырезаем каждую строку и помещаем результаты, если они есть, в соответствующий столбец. Существует логика для того, чтобы мы не пытались захватить и часть строки, которая может отсутствовать, и обрабатывать последнее специальное поле.

$results не будет содержать ваш текст как пользовательский psobject. Теперь вы можете делать фильтрацию, как и любую другую коллекцию объектов.

Выход из вышеприведенного образца

SESSIONNAME USERNAME ID STATE TYPE DEVICE ———— ——— — —— —- —— services 0 Disc console 1 Conn rdp-tcp#0 user.name1 2 Active rdpwd rdp-tcp#1 user.name2 3 Active rdpwd rdp-tcp#1 user.name3 4 Active rdpwd rdp-tcp 65536 Listen

Теперь мы покажем все имена пользователей, где type – rdpwd

$results | Where-Object{$_.type -eq «rdpwd»} | Select-Object -ExpandProperty username Ответ №4

Похоже, есть несколько ответов на это, но вот еще один.

Вы можете извлечь подстроку из каждой строки в соответствии с этой позицией.

$Sessions=qwinsta.exe $SessionCount=$Sessions.count [int]$x=1 do {$x++ if(($Sessions[$x]) -ne $null){$Sessions[$x].subString(19,21).Trim()} }until($x -eq $SessionCount) Ответ №5

Сделайте это точно так же, как если бы ваша оболочка была bash:

$ awk ‘$NF==»rdpwd»{print $2}’ file user.name1 user.name2 user.name3

Предостережение: я понятия не имею, что такое “powershell”, но вы отметили вопрос с awk, поэтому я предполагаю, что “powershell” – это своего рода оболочка, а вызов awk из нее – это вариант.

Ответ №6

[Редактировать: мне понравилась идея Мэтта о динамическом определении имен столбцов, поэтому я обновил свой ответ на более надежное решение.]

Здесь один из способов:

# Get-SessionData.ps1 $sessionData = qwinsta $headerRow = $sessionData | select-object -first 1 # Get column names $colNames = $headerRow.Split(‘ ‘,[StringSplitOptions]::RemoveEmptyEntries) # First column position is zero $colPositions = @(0) # Get remainder of column positions $colPositions += $colNames | select-object -skip 1 | foreach-object { $headerRow.IndexOf($_) } $sessionData | select-object -skip 1 | foreach-object { # Create output object $output = new-object PSCustomObject # Create and populate properties for all except last column for ( $i = 0; $i -lt $colNames.Count — 1; $i++ ) { $output | add-member NoteProperty $colNames[$i] ($_[$($colPositions[$i])..$($colPositions[$i + 1] — 1)] -join «»).Trim() } # Create property for last column $output | add-member NoteProperty $colNames[$colNames.Count — 1] «» # Remainder of text on line, if any, is last property if ( ($_.Length — 1) -gt ($colPositions[$colPositions.Count — 1]) ) { $output.$($colNames[$colNames.Count — 1]) = $_.Substring($colPositions[$colPositions.Count — 1]).Trim() } $output }

Это преобразует вывод команды в пользовательские объекты, которые вы можете фильтровать, сортировать и т.д.

Это означает, что вы можете запустить следующую команду, чтобы получить только имена пользователей, где столбец TYPE rdpwd:

Get-SessionData | where-object { $_.TYPE -eq «rdpwd» } | select-object -expandproperty USERNAME

Вывод:

user.name1 user.name2 user.name3 Ответ №7

Как использовать запущенные процессы для поиска экземпляров explorer для зарегистрированных пользователей? (Или какой-либо другой процесс, который вы знаете, что ваши пользователи будут работать):

Get-WmiObject -ComputerName «Machine» -Class win32_process | Where-Object {$_.Name -match «explorer»} | ForEach-Object {($_.GetOwner()).User}

Предоставляет все имена пользователей, связанные с запуском процессов проводника.

Ответ №8

Мне нравится Matt answer для этого, однако у него есть проблемы с пробелами в заголовках столбцов (они вообще проблематичны, но иногда вы не можете много сделать). Здесь есть исправленная, функциональная версия, которая поможет. Обратите внимание, что вы, вероятно, можете настроить препрок, чтобы включить, например, вкладки или другие разделители, но по-прежнему полагаются на постоянные индексы.

function Convert-TextColumnsToObject([String]$data) { $splitLinesOn=[Environment]::NewLine $columnPreproc=»s{2,}» $headerString = $data.Split($splitLinesOn) | select -f 1 #Preprocess to handle headings with spaces $headerElements = ($headerString -replace «$columnPreproc», «|») -split «|» | Where-Object{$_} $headerIndexes = $headerElements | ForEach-Object{$headerString.IndexOf($_)} $results = $data.Split($splitLinesOn) | Select-Object -Skip 1 | ForEach-Object{ $props = @{} $line = $_ For($indexStep = 0; $indexStep -le $headerIndexes.Count — 1; $indexStep++){ $value = $null # Assume a null value $valueLength = $headerIndexes[$indexStep + 1] — $headerIndexes[$indexStep] $valueStart = $headerIndexes[$indexStep] If(($valueLength -gt 0) -and (($valueStart + $valueLength) -lt $line.Length)){ $value = ($line.Substring($valueStart,$valueLength)).Trim() } ElseIf ($valueStart -lt $line.Length){ $value = ($line.Substring($valueStart)).Trim() } $props.($headerElements[$indexStep]) = $value } [pscustomobject]$props } return $results }

Пример:

$data= @» DRIVER VOLUME NAME local 004e9c5f2ecf96345297965d3f98e24f7a6a69f5c848096e81f3d5ba4cb60f1e local 081211bd5d09c23f8ed60fe63386291a0cf452261b8be86fc154b431280c0c11 local 112be82400a10456da2e721a07389f21b4e88744f64d9a1bd8ff2379f54a0d28 «@ $obj=Convert-TextColumnsToObject $data $obj | ?{ $_.»VOLUME NAME» -match «112be» } Ответ №9

Поле печати 4,5 и 6 во второй колонке.

awk ‘NR>3&&NR<7{print $2}’ file user.name1 user.name2 user.name3 Ответ №10

Некоторые из ответов здесь похвально пытаются проанализировать входные данные в объекты, что, однако, является (а) нетривиальным усилием и (б) происходит за счет производительности.

В качестве альтернативы рассмотрим синтаксический анализ текста с использованием оператора PowerShell -split, который в своей унарной форме разбивает строки на поля по пробелам, аналогичным стандартной утилите awk на платформах Unix:

В Windows, если вы сначала установите порт awk, например Gawk для Windows, вы можете вызвать awk непосредственно, как показано в Эд Мортоне. В Unix (с использованием ядра PowerShell) по умолчанию доступна awk.
Решение ниже похоже на Ed’s, за исключением того, что оно не будет работать также.

qwinsta | % { if (($fields = -split $_)[4] -eq ‘rdpwd’) { $fields[1] } }

  • -split $_ разделяет входную строку под рукой ($_) в массив полей пробелами пробелов, игнорируя начальные и конечные пробелы.

  • (…)[4] -eq ‘rdpwd’ проверяет пятое поле (как обычно, индексы 0) для интересующего значения.

  • В случае соответствия $fields[1] затем выводит второе поле, (предполагается, что это непустое) имя пользователя.

Ответ №11

простой способ

получить список активных пользователей

$logonusers = qwinsta /server:ts33 | Out-String -Stream | Select-String «Active»

очищает всю информацию вверх, кроме пользователей, с помощью команды -replace

$logonusers = $logonusers -replace(«rdp-tcp») -replace(«Active») — replace(«rdpwd») -replace(«#») -replace ‘s+’, ‘ ‘ -replace ‘[0-9]’,’ ‘ $logonusers

затем перечислит всех активных пользователей.

Оцените статью
Добавить комментарий