如何在 Powershell 脚本中输出调用命令的所有输出
How can I output all the output of a called command in Powershell script
我已经修改了现有的 Powershell 脚本,以使用 quser /server:{servername}
查询服务器列表以获取登录(或断开连接)的用户会话,并将结果输出到 CSV 文件中。它确实会输出任何已登录的用户,但它不会捕获具有 0 个用户或不可访问的服务器(服务器离线、rpc 不可用等)。我假设这是因为这些其他条件是 "errors" 而不是命令输出。
因此,如果它访问没有用户的服务器,它会在控制台 运行 中输出 "No User exists for *" 脚本。如果它命中无法到达的服务器,则输出 "Error 0x000006BA enumerating sessionnames" 并在控制台的第二行 "Error [1722]:The RPC server is unavailable." 运行 脚本。所以这些条件都没有显示在 output.csv 文件中。
我想知道是否有人可以建议我如何在 CSV 中捕获这些条件,如“$Computer 没有用户”和“$Computer Unreachable”
这是脚本
$ServerList = Read-Host 'Path to Server List?'
$ComputerName = Get-Content -Path $ServerList
foreach ($Computer in $ComputerName) {
quser /server:$Computer | Select-Object -Skip 1 | ForEach-Object {
$CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'
$HashProps = @{
UserName = $CurrentLine[0]
ServerName = $Computer
}
# If session is disconnected different fields will be selected
if ($CurrentLine[2] -eq 'Disc') {
$HashProps.SessionName = $null
$HashProps.Id = $CurrentLine[1]
$HashProps.State = $CurrentLine[2]
$HashProps.IdleTime = $CurrentLine[3]
$HashProps.LogonTime = $CurrentLine[4..6] -join ' '
} else {
$HashProps.SessionName = $CurrentLine[1]
$HashProps.Id = $CurrentLine[2]
$HashProps.State = $CurrentLine[3]
$HashProps.IdleTime = $CurrentLine[4]
$HashProps.LogonTime = $CurrentLine[5..7] -join ' '
}
New-Object -TypeName PSCustomObject -Property $HashProps |
Select-Object -Property ServerName,UserName,State,LogonTime |
ConvertTo-Csv -NoTypeInformation | select -Skip 1 | Out-File -Append .\output.csv
}
}
任何人都好奇为什么我使用 ConvertTo-CSV
而不是 Export-CSV
这会更干净,因为我 运行 来自的服务器是 运行 Powershell 2.0 其中 Export-CSV 不支持 -Append。我不担心输出能满足我的需要,但如果有人对此有更好的建议,请随时发表评论。
所以我们对脚本进行了一些更新。如果使用 quser
时出现任何错误,我们会将其捕获为一个特殊条目,其中服务器名称将显示为 "Error contacting $computer"
和其他提供错误上下文的文本..
$ServerList = Read-Host 'Path to Server List?'
$ComputerNames = Get-Content -Path $ServerList
$ComputerNames | ForEach-Object{
$computer = $_
$results = quser /server:$Computer 2>&1 | Write-Output
If($LASTEXITCODE -ne 0){
$HashProps = @{
UserName = ""
ServerName = "Error contacting $computer"
SessionName = ""
Id = ""
State = $results | Select-String -Pattern '\[.+?\]' | Select -ExpandProperty Matches | Select -ExpandProperty Value
IdleTime = ""
LogonTime = ""
}
switch -Wildcard ($results){
'*[1722]*'{$HashProps.UserName = "RPC server is unavailable"}
'*[5]*'{$HashProps.UserName = "Access is denied"}
default{$HashProps.UserName = "Something else"}
}
} Else {
$results | Select-Object -Skip 1 | ForEach-Object {
$CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'
$HashProps = @{
UserName = $CurrentLine[0]
ServerName = $Computer
}
# If session is disconnected different fields will be selected
if ($CurrentLine[2] -eq 'Disc') {
$HashProps.SessionName = $null
$HashProps.Id = $CurrentLine[1]
$HashProps.State = $CurrentLine[2]
$HashProps.IdleTime = $CurrentLine[3]
$HashProps.LogonTime = $CurrentLine[4..6] -join ' '
} else {
$HashProps.SessionName = $CurrentLine[1]
$HashProps.Id = $CurrentLine[2]
$HashProps.State = $CurrentLine[3]
$HashProps.IdleTime = $CurrentLine[4]
$HashProps.LogonTime = $CurrentLine[5..7] -join ' '
}
}
}
New-Object -TypeName PSCustomObject -Property $HashProps
} | Select-Object -Property ServerName,UserName,State,LogonTime |
Export-Csv -NoTypeInformation .\output.csv
部分问题在于,由于这不是捕获 stderr 以便解析的 PowerShell cmdlet,因此需要以不同的方式工作。使用 $erroractionpreference
也是一种选择,但这是初稿。我们使用 2>&1
将错误捕获到 $results
以隐藏屏幕上的消息。然后我们使用 If
来查看最后一个命令是否成功。
如果出现错误
我使用了带有错误文本的 switch 语句。因此,您可以根据 $results
中返回的文本定制输出
一些小改动
您的其余大部分代码都是相同的。我将 object 创建移到 If
语句之外,以便可以记录错误并将其更改为 Export-CSV
,因为 PowerShell 将为您计算出详细信息。
除非您打算随着时间的推移对该函数进行多次传递,并将其捕获到同一个文件中。
导出前的控制台输出
ServerName UserName State LogonTime
---------- -------- ----- ---------
serverthing01 bjoe Active 4/9/2015 5:42 PM
Error contacting c4093 RPC server is unavailable [1722]
Error contacting c4094 Access is denied [5]
您可以看到每个服务器都有输出,尽管最后两个服务器有不同的原因没有正确的输出。如果您曾经看到 "Something else"
出现了一个没有附加特定消息的错误。
发生这种情况时,请查看 State
并显示错误编号。然后你只需要相应地更新 Switch
。
重要更新
我不确定为多个用户删除额外线路的问题是什么,但我已经有了一个 dynamic parsing code for positionally delimited text,所以我将其引入此处。
Function ConvertFrom-PositionalText{
param(
[Parameter(Mandatory=$true)]
[string[]]$data
)
$headerString = $data[0]
$headerElements = $headerString -split "\s+" | Where-Object{$_}
$headerIndexes = $headerElements | ForEach-Object{$headerString.IndexOf($_)}
$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
}
New-Object -TypeName PSCustomObject -Property $props
}
}
$ServerList = Read-Host 'Path to Server List?'
$ComputerNames = Get-Content -Path $ServerList
$HashProps = @{}
$exportedprops = "ServerName","UserName","State",@{Label="LogonTime";Expression={$_.Logon}}
$ComputerNames | ForEach-Object{
$computer = $_
$results = quser /server:$Computer 2>&1 | Write-Output
If($LASTEXITCODE -ne 0){
$HashProps = @{
UserName = ""
ServerName = "Error contacting $computer"
SessionName = ""
Id = ""
State = $results | Select-String -Pattern '\[.+?\]' | Select -ExpandProperty Matches | Select -ExpandProperty Value
Idle = ""
Time = ""
Logon = ""
}
switch -Wildcard ($results){
'*[1722]*'{$HashProps.UserName = "RPC server is unavailable"}
'*[5]*'{$HashProps.UserName = "Access is denied"}
default{$HashProps.UserName = "Something else"}
}
New-Object -TypeName PSCustomObject -Property $HashProps
} Else {
ConvertFrom-PositionalText -data $results | Add-Member -MemberType NoteProperty -Name "ServerName" -Value $computer -PassThru
}
} | Select-Object -Property $exportedprops |
Export-Csv -NoTypeInformation .\output.csv
这里最大的区别是我们使用 ConvertFrom-PositionalText
来解析 quser
的细节。需要将 $HashProps = @{}
归零,这会导致多次运行产生冲突的结果。为了更好地衡量,函数的输出和虚拟错误数据具有相同的参数集。使用了具有计算表达式的 $exportedprops
,以便您可以获得所需的 headers。
新输出
ServerName USERNAME STATE LogonTime
---------- -------- ----- ---------
server01 user1 Disc 3/12/2015 9:38 AM
server01 user2 Active 4/9/2015 5:42 PM
Error contacting 12345 Access is denied [5]
Error contacting 12345 RPC server is unavailable [1722]
svrThg1 user3 Active 4/9/2015 5:28 PM
svrThg1 user4 Active 4/9/2015 5:58 PM
svrThg1 user-1 Active 4/9/2015 9:50 PM
svrThg1 bjoe Active 4/9/2015 10:01 PM
我已经修改了现有的 Powershell 脚本,以使用 quser /server:{servername}
查询服务器列表以获取登录(或断开连接)的用户会话,并将结果输出到 CSV 文件中。它确实会输出任何已登录的用户,但它不会捕获具有 0 个用户或不可访问的服务器(服务器离线、rpc 不可用等)。我假设这是因为这些其他条件是 "errors" 而不是命令输出。
因此,如果它访问没有用户的服务器,它会在控制台 运行 中输出 "No User exists for *" 脚本。如果它命中无法到达的服务器,则输出 "Error 0x000006BA enumerating sessionnames" 并在控制台的第二行 "Error [1722]:The RPC server is unavailable." 运行 脚本。所以这些条件都没有显示在 output.csv 文件中。
我想知道是否有人可以建议我如何在 CSV 中捕获这些条件,如“$Computer 没有用户”和“$Computer Unreachable”
这是脚本
$ServerList = Read-Host 'Path to Server List?'
$ComputerName = Get-Content -Path $ServerList
foreach ($Computer in $ComputerName) {
quser /server:$Computer | Select-Object -Skip 1 | ForEach-Object {
$CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'
$HashProps = @{
UserName = $CurrentLine[0]
ServerName = $Computer
}
# If session is disconnected different fields will be selected
if ($CurrentLine[2] -eq 'Disc') {
$HashProps.SessionName = $null
$HashProps.Id = $CurrentLine[1]
$HashProps.State = $CurrentLine[2]
$HashProps.IdleTime = $CurrentLine[3]
$HashProps.LogonTime = $CurrentLine[4..6] -join ' '
} else {
$HashProps.SessionName = $CurrentLine[1]
$HashProps.Id = $CurrentLine[2]
$HashProps.State = $CurrentLine[3]
$HashProps.IdleTime = $CurrentLine[4]
$HashProps.LogonTime = $CurrentLine[5..7] -join ' '
}
New-Object -TypeName PSCustomObject -Property $HashProps |
Select-Object -Property ServerName,UserName,State,LogonTime |
ConvertTo-Csv -NoTypeInformation | select -Skip 1 | Out-File -Append .\output.csv
}
}
任何人都好奇为什么我使用 ConvertTo-CSV
而不是 Export-CSV
这会更干净,因为我 运行 来自的服务器是 运行 Powershell 2.0 其中 Export-CSV 不支持 -Append。我不担心输出能满足我的需要,但如果有人对此有更好的建议,请随时发表评论。
所以我们对脚本进行了一些更新。如果使用 quser
时出现任何错误,我们会将其捕获为一个特殊条目,其中服务器名称将显示为 "Error contacting $computer"
和其他提供错误上下文的文本..
$ServerList = Read-Host 'Path to Server List?'
$ComputerNames = Get-Content -Path $ServerList
$ComputerNames | ForEach-Object{
$computer = $_
$results = quser /server:$Computer 2>&1 | Write-Output
If($LASTEXITCODE -ne 0){
$HashProps = @{
UserName = ""
ServerName = "Error contacting $computer"
SessionName = ""
Id = ""
State = $results | Select-String -Pattern '\[.+?\]' | Select -ExpandProperty Matches | Select -ExpandProperty Value
IdleTime = ""
LogonTime = ""
}
switch -Wildcard ($results){
'*[1722]*'{$HashProps.UserName = "RPC server is unavailable"}
'*[5]*'{$HashProps.UserName = "Access is denied"}
default{$HashProps.UserName = "Something else"}
}
} Else {
$results | Select-Object -Skip 1 | ForEach-Object {
$CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'
$HashProps = @{
UserName = $CurrentLine[0]
ServerName = $Computer
}
# If session is disconnected different fields will be selected
if ($CurrentLine[2] -eq 'Disc') {
$HashProps.SessionName = $null
$HashProps.Id = $CurrentLine[1]
$HashProps.State = $CurrentLine[2]
$HashProps.IdleTime = $CurrentLine[3]
$HashProps.LogonTime = $CurrentLine[4..6] -join ' '
} else {
$HashProps.SessionName = $CurrentLine[1]
$HashProps.Id = $CurrentLine[2]
$HashProps.State = $CurrentLine[3]
$HashProps.IdleTime = $CurrentLine[4]
$HashProps.LogonTime = $CurrentLine[5..7] -join ' '
}
}
}
New-Object -TypeName PSCustomObject -Property $HashProps
} | Select-Object -Property ServerName,UserName,State,LogonTime |
Export-Csv -NoTypeInformation .\output.csv
部分问题在于,由于这不是捕获 stderr 以便解析的 PowerShell cmdlet,因此需要以不同的方式工作。使用 $erroractionpreference
也是一种选择,但这是初稿。我们使用 2>&1
将错误捕获到 $results
以隐藏屏幕上的消息。然后我们使用 If
来查看最后一个命令是否成功。
如果出现错误
我使用了带有错误文本的 switch 语句。因此,您可以根据 $results
一些小改动
您的其余大部分代码都是相同的。我将 object 创建移到 If
语句之外,以便可以记录错误并将其更改为 Export-CSV
,因为 PowerShell 将为您计算出详细信息。
除非您打算随着时间的推移对该函数进行多次传递,并将其捕获到同一个文件中。
导出前的控制台输出
ServerName UserName State LogonTime
---------- -------- ----- ---------
serverthing01 bjoe Active 4/9/2015 5:42 PM
Error contacting c4093 RPC server is unavailable [1722]
Error contacting c4094 Access is denied [5]
您可以看到每个服务器都有输出,尽管最后两个服务器有不同的原因没有正确的输出。如果您曾经看到 "Something else"
出现了一个没有附加特定消息的错误。
发生这种情况时,请查看 State
并显示错误编号。然后你只需要相应地更新 Switch
。
重要更新
我不确定为多个用户删除额外线路的问题是什么,但我已经有了一个 dynamic parsing code for positionally delimited text,所以我将其引入此处。
Function ConvertFrom-PositionalText{
param(
[Parameter(Mandatory=$true)]
[string[]]$data
)
$headerString = $data[0]
$headerElements = $headerString -split "\s+" | Where-Object{$_}
$headerIndexes = $headerElements | ForEach-Object{$headerString.IndexOf($_)}
$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
}
New-Object -TypeName PSCustomObject -Property $props
}
}
$ServerList = Read-Host 'Path to Server List?'
$ComputerNames = Get-Content -Path $ServerList
$HashProps = @{}
$exportedprops = "ServerName","UserName","State",@{Label="LogonTime";Expression={$_.Logon}}
$ComputerNames | ForEach-Object{
$computer = $_
$results = quser /server:$Computer 2>&1 | Write-Output
If($LASTEXITCODE -ne 0){
$HashProps = @{
UserName = ""
ServerName = "Error contacting $computer"
SessionName = ""
Id = ""
State = $results | Select-String -Pattern '\[.+?\]' | Select -ExpandProperty Matches | Select -ExpandProperty Value
Idle = ""
Time = ""
Logon = ""
}
switch -Wildcard ($results){
'*[1722]*'{$HashProps.UserName = "RPC server is unavailable"}
'*[5]*'{$HashProps.UserName = "Access is denied"}
default{$HashProps.UserName = "Something else"}
}
New-Object -TypeName PSCustomObject -Property $HashProps
} Else {
ConvertFrom-PositionalText -data $results | Add-Member -MemberType NoteProperty -Name "ServerName" -Value $computer -PassThru
}
} | Select-Object -Property $exportedprops |
Export-Csv -NoTypeInformation .\output.csv
这里最大的区别是我们使用 ConvertFrom-PositionalText
来解析 quser
的细节。需要将 $HashProps = @{}
归零,这会导致多次运行产生冲突的结果。为了更好地衡量,函数的输出和虚拟错误数据具有相同的参数集。使用了具有计算表达式的 $exportedprops
,以便您可以获得所需的 headers。
新输出
ServerName USERNAME STATE LogonTime
---------- -------- ----- ---------
server01 user1 Disc 3/12/2015 9:38 AM
server01 user2 Active 4/9/2015 5:42 PM
Error contacting 12345 Access is denied [5]
Error contacting 12345 RPC server is unavailable [1722]
svrThg1 user3 Active 4/9/2015 5:28 PM
svrThg1 user4 Active 4/9/2015 5:58 PM
svrThg1 user-1 Active 4/9/2015 9:50 PM
svrThg1 bjoe Active 4/9/2015 10:01 PM