Powershell 无法将变量解析到ForEach($Servers中的服务器)循环中?

Powershell 无法将变量解析到ForEach($Servers中的服务器)循环中?,powershell,Powershell,我正在尝试更正下面的脚本,以便使用Qwinsta查询服务器登录会话 此服务器的目标是显示当前登录的用户 脚本主要部分: $queryResults=(qwinsta/server:$ServerName |选择对象-跳过1| ForEach对象{($u33; trim()-replace“\s+”,“,”)}从csv转换 -错误(操作停止) 工作正常吗 PS C:\WINDOWS\system32> $queryResults services 0 Disc ---

我正在尝试更正下面的脚本,以便使用Qwinsta查询服务器登录会话

此服务器的目标是显示当前登录的用户

脚本主要部分:

$queryResults=(qwinsta/server:$ServerName |选择对象-跳过1| ForEach对象{($u33; trim()-replace“\s+”,“,”)}从csv转换 -错误(操作停止)

工作正常吗

PS C:\WINDOWS\system32> $queryResults

services      0     Disc  
--------      -     ----  
console       1     Conn  
Administrator 3     Disc  
rdp-tcp       65536 Listen
脚本:

$HtmlHead = @"
<style>
    body {
        font-family: Arial;
    }
    table {
        width: 100%;
        border-collapse: collapse;
        border: 1px solid;
    }
    th {
        background-color: green;
        border: 1px solid;
        padding: 1px;
    }
    td {
        border: 1px solid;
        padding: 1px;
    }
</style>
"@

$Today = Get-Date -Format 'F'
$SessionList = "`n`nRDP Session List - " + $Today + "`n`n"
$CurrentSN = 0

# Get a list of servers from Active Directory
write-progress -activity "Getting list of servers from Active Directory" -status "... please wait ..."

$Servers = Get-ADComputer -Filter { Enabled -eq $True -and OperatingSystem -like "*Server*" } -SearchBase "OU=Servers,DC=Company,DC=com," | Where-Object { Test-Connection $_.Name -Count 1 -Quiet } | Select-Object -ExpandProperty Name

$NumberOfServers = $Servers.Count

# Iterate through the retrieved list to check RDP sessions on each machine
ForEach ($Server in $Servers) {

    $ServerName = $Server.Name
    Write-Host "Processing $($Server.Name) ..." -ForegroundColor Yellow
    Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN / $NumberOfServers) * 100)

    # Run qwinsta and grab the output
    try {
        $queryResults = (qwinsta /server:$ServerName | Select-Object -Skip 1 | ForEach-Object { (($_.trim() -replace "\s+", ",")) } | convertfrom-csv -ErrorAction Stop)

        # get session info from the instance
        ForEach ($QueryResult in $QueryResults) {

            $RDPUser = $($QueryResult.substring(19, 22)).trim()
            $SessionType = $($QueryResult.substring(1, 18)).trim()
            $SessionID = $($QueryResult.substring(41, 5)).trim()
            $ReturnedCurrentState = $($QueryResult.substring(48, 8)).trim()

            $RDPUser = $QueryResult.USERNAME
            $SessionType = $QueryResult.SESSIONNAME
            $SessionID = $QueryResult.ID
            $ReturnedCurrentState = $QueryResult.State

            If ($ReturnedCurrentState -eq $null) { $CurrentState = "Disconnected" } Else { $CurrentState = "Active" }

            # filter out the irrelevant information
            If (($RDPUser -ne $null) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
                $SessionList = $SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " on " + $SessionType + ", session id $SessionID $CurrentState"
            }
        }

    }
    catch {
        $SessionList = $SessionList + "`n Unable to query " + $ServerName
        write-host "Unable to query $ServerName!" -foregroundcolor Red
    }

    $CurrentSN++
}

# Send the output the screen.
$SessionList + "`n`n"

$sendMailArgs = @{
    From       = "$env:USERNAME@$env:userdnsdomain"
    To         = 'SOC@domain.com'
    SmtpServer = 'SMTP.domain.com'
    Priority   = 'High'
    BodyAsHtml = $true
    Body       = ($SessionList | ConvertTo-Html -Head $HtmlHead) -join "`r`n"
    Subject    = "$($SessionList.Count) Logged On users from $($NumberOfServers) online servers as at $($Today)"
}

Send-MailMessage @sendMailArgs
电子邮件结果通常如下所示:

*
424
这是什么意思?

最有可能的是Substring()方法引发异常,因为startIndex参数值41和48似乎很大。如果$QueryResult字符串变短,您将得到该异常并立即移动到catch语句

我建议将查询服务器和构建会话列表的错误处理分开

更新: 下面是如何在脚本示例中分离错误处理。基本上,您需要了解一些方法或cmdlet,这些方法或cmdlet理论上可以使用您提供的输入参数引发异常,并涵盖这些情况

ForEach ($Server in $Servers) {

    $ServerName = $Server.Name
    Write-Host "Processing $ServerName ..." -ForegroundColor Yellow
    Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN / $NumberOfServers) * 100)

    # Run qwinsta and grab the output
    try {
        $queryResults = (qwinsta /server:$ServerName | Select-Object -Skip 1 | ForEach-Object { (($_.trim() -replace "\s+", ",")) } | convertfrom-csv )
    }
    catch {
        # Error handling for failed server connection here
        $SessionList += "`n Unable to query " + $ServerName
        write-host "Unable to query $ServerName!" -foregroundcolor Red
        continue # Skip to next $Server
    }
    # get session info from the instance
    ForEach ($QueryResult in $QueryResults) {
        try {
            # Do something about this
            $RDPUser = $($QueryResult.substring(19, 22)).trim()
            $SessionType = $($QueryResult.substring(1, 18)).trim()
            $SessionID = $($QueryResult.substring(41, 5)).trim()
            $ReturnedCurrentState = $($QueryResult.substring(48, 8)).trim()
    
            $RDPUser = $QueryResult.USERNAME
            $SessionType = $QueryResult.SESSIONNAME
            $SessionID = $QueryResult.ID
            $ReturnedCurrentState = $QueryResult.State
        }
        catch {
            # Insert your error handling here
            # Write-Host "Failed to process query result from $ServerName!" -foregroundcolor Red
             
            Write-Host $Error[0].Exception # If you want to get the exception message. A shorter way to do it below
            # Write-Host $_
        }

        If ($null -eq $ReturnedCurrentState) { $CurrentState = "Disconnected" } Else { $CurrentState = "Active" }

        # filter out the irrelevant information
        If (($null -ne $RDPUser) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
            $SessionList = $SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " on " + $SessionType + ", session id $SessionID $CurrentState"
        }
    }
    $CurrentSN++
} 

我真正关心的是代码块,在代码块中,您为变量赋值,如
$RDPUser
$SessionType
,等等。我会告诉您,我不知道您的环境,但逻辑看起来非常奇怪。如果
$QueryResult
是一个具有多个属性的对象,为什么要使用子字符串?对象没有此方法。如果它只是一个在某些字符位置具有值的长字符串,为什么要尝试获取它的属性值,如
$QueryResult.ID
-它没有任何。

根据请求进行更新。添加以查看异常错误消息。是的,我已经包含了try/CatchSure,但catch块对异常没有任何作用。了解如何查看异常的实际情况。感谢您的建议,您能告诉我如何在多个Try/Catch嵌套上执行此操作吗?当然,我已经用一个示例更新了我的原始答案。太好了,非常感谢您对思考过程的详细解释和分享,这对我回答这个问题很有帮助。
ForEach ($Server in $Servers) {

    $ServerName = $Server.Name
    Write-Host "Processing $ServerName ..." -ForegroundColor Yellow
    Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN / $NumberOfServers) * 100)

    # Run qwinsta and grab the output
    try {
        $queryResults = (qwinsta /server:$ServerName | Select-Object -Skip 1 | ForEach-Object { (($_.trim() -replace "\s+", ",")) } | convertfrom-csv )
    }
    catch {
        # Error handling for failed server connection here
        $SessionList += "`n Unable to query " + $ServerName
        write-host "Unable to query $ServerName!" -foregroundcolor Red
        continue # Skip to next $Server
    }
    # get session info from the instance
    ForEach ($QueryResult in $QueryResults) {
        try {
            # Do something about this
            $RDPUser = $($QueryResult.substring(19, 22)).trim()
            $SessionType = $($QueryResult.substring(1, 18)).trim()
            $SessionID = $($QueryResult.substring(41, 5)).trim()
            $ReturnedCurrentState = $($QueryResult.substring(48, 8)).trim()
    
            $RDPUser = $QueryResult.USERNAME
            $SessionType = $QueryResult.SESSIONNAME
            $SessionID = $QueryResult.ID
            $ReturnedCurrentState = $QueryResult.State
        }
        catch {
            # Insert your error handling here
            # Write-Host "Failed to process query result from $ServerName!" -foregroundcolor Red
             
            Write-Host $Error[0].Exception # If you want to get the exception message. A shorter way to do it below
            # Write-Host $_
        }

        If ($null -eq $ReturnedCurrentState) { $CurrentState = "Disconnected" } Else { $CurrentState = "Active" }

        # filter out the irrelevant information
        If (($null -ne $RDPUser) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
            $SessionList = $SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " on " + $SessionType + ", session id $SessionID $CurrentState"
        }
    }
    $CurrentSN++
}