bourne
bourne

Reputation: 259

powershell: populate custom object from variable contents

I am in the process of writing a script that takes the output from the sysinternals command: psloggedon.exe and outputs the computer name and what users are signed in.

I currently have the script producing the following possibilities depending upon what output is given by each computer when queried.

DOMAIN\computer-name01
DOMAIN\user-name

DOMAIN\computer-name02
DOMAIN\user-name
DOMAIN\user-name

DOMAIN\computer-name03
Error connecting

DOMAIN\computer-name04
No user is signed in

Each chunk of data will always have a computer name followed by either the list of users signed in, an error, or a message saying that no one is signed in.

I would like to assign the data to a custom object so that I can output it to a CSV. As I understand this is the best way to generate a proper CSV.

Where I am getting confused with the custom object is how do I deal with a situation where the incoming data is changing in amount? So for instance, I may have a computer that has 4 people signed into it. I also don't understand how I can create the column headers. Most of the examples I have found the data that is being fed into the custom object already has it's own column headers or properties.

I am looking to output the data so that it looks something like below

DOMAIN\computer-name, DOMAIN\user-name, DOMAIN\user-name
DOMAIN\computer-name, Error Message
DOMAIN\computer-name, No one signed in

The column header over the computer name would be "Computer Name" and the header of the signed in user/error message/no one signed in would be "Status".

Microsoft has this pretty well documented it seems: https://technet.microsoft.com/en-us/library/ff730946.aspx

In this example I don't understand where "$objBatter.Name" comes from. How does the script know the property or column header from the input? Does the data being inputted already have that defined?

Sorry for being so confusing, I am having a hard time wrapping my brain around it so explaining it is hard.

Here is what I have tried. But basically the custom object just outputs the properties/column headers (sorry I am not really sure what this is called). The rest is blank.

$Computers = @(
,"computer-name01"
)

Foreach ( $Computer in $Computers)
{
    $loggedon = $null
    If ( Test-Connection -ComputerName $Computer -Quiet -Count 1 )
    {
        $loggedon = (PsLoggedon.exe -x -l \\$Computer | Where-Object { ($_ -like "*DOMAIN\*" -or $_ -like "*No one*" -or $_ -like "*$Computer\*" -or $_ -like "*Error opening*")}).trim()

        if ( $loggedon -like "*Error Opening*" )
        {
            Write-Output "Error occurred while attempting to connect. This computer is online."
            Continue
        } else {

            $loggedon = ,"$Computer" + $loggedon

            $colComputerAndUser = @()

            foreach ($item in $loggedon)
            {
                $ObjComputerAndUser = New-Object System.Object
                $ObjComputerAndUser | Add-Member -Type NoteProperty -Name Computer -Value $item.Computer
                $ObjComputerAndUser | Add-Member -Type NoteProperty -Name User -Value $item.User
                $colComputerAndUser += $ObjComputerAndUser
            }

            $colComputerAndUser
        }
    }
 }

UPDATE 01

I attempted to use the code you provided. It worked as intended, but I get a strange behavior if a computer returns more than just one person signed in. Inside the custom object, the computer will be displayed multiple times.

$Computers = @(
,"computer01"
,"computer02"
)

$colComputerAndUser = @()

Foreach ( $Computer in $Computers)
{
    $loggedon = $null
    If ( Test-Connection -ComputerName $Computer -Quiet -Count 1 )
    {
        $loggedon = (PsLoggedon.exe -x -l \\$Computer | Where-Object { ($_ -like "*DOMAIN\*" -or $_ -like "*No one*" -or $_ -like "*$Computer\*" -or $_ -like "*Error opening*")}).trim()
        $loggedon = [string]$loggedon
        $ObjComputerAndUser = New-Object PSObject
        $ObjComputerAndUser | Add-Member -Type NoteProperty -Name Computer -Value $Computer
        $ObjComputerAndUser | Add-Member -Type NoteProperty -Name User -Value $loggedon
        $colComputerAndUser += $ObjComputerAndUser     
    }

    $colComputerAndUser
}

Computer User
-------- ----
computer01 DOMAIN\user01 DOMAIN\user02
computer01 DOMAIN\user01 DOMAIN\user02
computer02 DOMAIN\user03

Update 02

Sample 01 out from the PsLoggedon.exe - unedited

PsLoggedon v1.35 - See who's logged on  
Copyright (C) 2000-2016 Mark Russinovich  
Sysinternals - www.sysinternals.com  

Users logged on locally:  
        DOMAIN\user.name01  
        DOMAIN\user.name02

Sample 02 out from the PsLoggedon.exe - unedited

PsLoggedon v1.35 - See who's logged on  
Copyright (C) 2000-2016 Mark Russinovich  
Sysinternals - www.sysinternals.com  

Users logged on locally:  
        LOCALMACHINE\local.user01
        LOCALMACHINE\local.user04
        DOMAIN\user.name15  
        DOMAIN\user.name17

UPDATE 03 This code was actually working, but I had placed the out in the wrong part of the code.

$Computers = @(
,"computer01"
,"computer02"
,"computer03"
,"computer04"
,"computer05"
)

$colComputerAndUser = @()

Foreach ( $Computer in $Computers)
{
    $loggedon = $null
    If ( Test-Connection -ComputerName $Computer -Quiet -Count 1 )
    {
        $loggedon = (PsLoggedon.exe -x -l \\$Computer | Where-Object { ($_ -like "*DOMAIN\*" -or $_ -like "*No one*" -or $_ -like "*$Computer\*" -or $_ -like "*Error opening*")}).trim()
        $loggedon = [string]$loggedon
        $ObjComputerAndUser = New-Object PSObject
        $ObjComputerAndUser | Add-Member -Type NoteProperty -Name Computer -Value $Computer
        $ObjComputerAndUser | Add-Member -Type NoteProperty -Name User -Value $loggedon
        $colComputerAndUser += $ObjComputerAndUser     
    }
}
$colComputerAndUser

Where this code is different is where the final $colComputerNameUser is placed. originally I had it contained within the foreach loop, which caused the output to duplicate. It now comes after the loop, and the output is working correctly.

Upvotes: 0

Views: 1659

Answers (1)

Arluin
Arluin

Reputation: 594

Make an object with two properties: ComputerName, Users. Concatenate all of the values after the ComputerName into a string and assign the string to the Users attribute.

$Computers = @(,"computername")

Foreach ($Computer in $Computers)
{
$loggedon = $null
if (Test-Connection -ComputerName $Computer -Quiet -Count 1){
    $loggedon = (.\PsLoggedon.exe -x -l \\$Computer)

    if ($loggedon -like "*Error Opening*"){
        Write-Output "Error occurred while attempting to connect. This computer is online."
        Continue
    } else {
        $loggedon = ,"$Computer" + $loggedon

        $colComputerAndUser = @()

        $UserString = ""
        for($Cnt = 9;$Cnt -lt $loggedon.Count;$Cnt++)
        {
            $UserString += ($loggedon[$Cnt]).Trim() + "`n"
        }
        $ObjComputerAndUser = New-Object System.Object
        $ObjComputerAndUser | Add-Member -Type NoteProperty -Name Computer -Value $Computer
        $ObjComputerAndUser | Add-Member -Type NoteProperty -Name User -Value $UserString
        $colComputerAndUser += $ObjComputerAndUser
     }
   }
 }
$colComputerAndUser | format-table -wrap

Not my most elegant work, but it works. I don't like hard-coding the start of the array count to 9. I tried to split on the colon but it just split on each `n in the output from PsLoggedon. I might try to refine this later. I also tried a global regex to match on [regex]'(?[^\])\(?.*)' but that didn't work out either. I got the results out, but couldn't enumerate the results.

Upvotes: 1

Related Questions