我是PowerShell新手(Bash通常是我的东西)谁正在尝试获取qwinsta输出以显示谁以“rdpwd”(rdesktop)用户身份登录,以便我可以根据用户名列表检查每个用户名,如果它们不匹配,请将其注销。
我目前正在解决两个问题:
我现在专注于问题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
(目的是创建一个循环,简单地说,“在列表中预告用户,如果不在本地组中,则注销用户”。)
到目前为止,我已经选择了带有'rdpwd'的文字,但是对于“拆分”使用了各种各样的变化,我还没有比这更进一步。
我很高兴分享我已经拥有的东西,但是我觉得它不会对任何人有所帮助!
非常感谢任何帮助。 :)
答案 0 :(得分:4)
老实说,我会查找更好的方法来执行此操作,但您可以通过一些文本操作和ConvertFrom-Csv
cmdlet来捏造它:
$(qwinsta.exe) -replace "^[\s>]" , "" -replace "\s+" , "," | ConvertFrom-Csv | select username
首先用任何内容替换任何前导空格或>
字符,然后用逗号替换任何空格。然后,您可以管道到ConvertFrom-Csv
并将数据作为对象使用。
实际上,上面有一些问题,主要是\s+
,因为如果列为空,则无法将其正确识别为空白字段,并且下一个文本被错误地提升为当前字段。
以下是此命令的完整解析器,可能适用于本机Windows 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
答案 1 :(得分:2)
无法确定,但听起来您正在尝试使用字符串.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
答案 2 :(得分:1)
我对基于位置的分隔符的看法。所有其他答案都可以获得您正在寻找的信息,但很像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
答案 3 :(得分:1)
在第二栏中打印第4,5和6栏。
awk 'NR>3&&NR<7{print $2}' file
user.name1
user.name2
user.name3
答案 4 :(得分:0)
看起来有一些答案,但这是另一个答案。
你可以根据这样的位置从每一行中提取子串。
$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 :(得分:0)
如果你的shell是bash,那就完全一样了:
$ awk '$NF=="rdpwd"{print $2}' file
user.name1
user.name2
user.name3
警告:我不知道“powershell”是什么,但你用awk标记了这个问题所以我认为“powershell”是某种shell并且从中调用awk是一种选择。
答案 6 :(得分:0)
[编辑:我喜欢Matt关于动态确定列名称的想法,所以我更新了我对更强大解决方案的回答。]
以这种方式:
# 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 :(得分:0)
如何使用正在运行的进程为登录用户查找资源管理器实例? (或者您知道您的用户正在运行的其他一些过程):
Get-WmiObject -ComputerName "Machine" -Class win32_process | Where-Object {$_.Name -match "explorer"} | ForEach-Object {($_.GetOwner()).User}
将提供与运行资源管理器进程相关联的所有用户名。
答案 8 :(得分:0)
我喜欢Matt's answer,但它在列标题中存在空格问题(一般来说它们都有问题,但有时候你做不了多少)。这是一个经过调整的功能化版本,可以提供帮助。请注意,您可以调整preproc以包括例如制表符或其他分隔符,但仍然依赖于每行索引不变。
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 :(得分:0)
这里的一些答案值得称道地尝试将输入解析为对象,然而,这是(a)非常重要的努力和(b)以牺牲性能为代价。
作为替代方案,考虑使用PowerShell的-split
运算符进行文本解析,以其一元形式将行分隔为类似于标准{{{ Unix平台上的1}}实用程序:
在Windows上,如果您首先安装awk
端口awk
,则可以直接调用awk
,如Gawk for Windows所示。在Unix上(使用PowerShell Core ),默认情况下可以使用awk
下面的解决方案类似于Ed,但它不会表现良好。
qwinsta | % { if (($fields = -split $_)[4] -eq 'rdpwd') { $fields[1] } }
-split $_
通过空格运行将输入行($_
)拆分为字段数组,忽略前导和尾随空格。
(...)[4] -eq 'rdpwd'
测试第五个字段(通常情况下,索引为0
- 基于)感兴趣的值。
如果匹配,$fields[1]
则输出第二个字段,(假设为非空)用户名。
答案 10 :(得分:0)
我写了一个可重用的ConvertFrom-SourceTable
cmdlet,可以从PowerShell Gallery下载,也可以从GitHub iRon7/ConvertFrom-SourceTable
存储库下载。
$Object = ConvertFrom-SourceTable '
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
'
它非常灵活,能够读取很多表格格式,包括读取结果的输出。或者即使例如ID
列右对齐意味着它将涉及整数而不是字符串:
$Object = ConvertFrom-SourceTable '
ID TYPE USERNAME STATE DEVICE SESSIONNAME
-- ---- -------- ----- ------ -----------
0 Disc services
1 Conn console
2 rdpwd user.name1 Active rdp-tcp#0
3 rdpwd user.name2 Active rdp-tcp#1
4 rdpwd user.name3 Active rdp-tcp#1
65536 Listen rdp-tcp
'
详见:ConvertFrom-SourceTable -?
答案 11 :(得分:-1)
一种简单的方法
仅获取活跃用户列表
$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
然后将列出所有活跃用户。