Multiline to Singleline Conversion

This topic contains 6 replies, has 3 voices, and was last updated by Profile photo of Sam Boutros Sam Boutros 1 year, 11 months ago.

  • Author
    Posts
  • #21734
    Profile photo of Paul Goffar
    Paul Goffar
    Participant

    Hey everyone,

    So, I'm looking to take multiline output from an array and present it as a single line, pref comma seperated...

    $i = 0
    $processinfo = @[Get-WmiObject -class win32_process -ComputerName $Computer -EA "Stop"]
    				if [$processinfo]
    				{
    					$processinfo | Foreach-Object { $_.GetOwner[].User } |
    					Where-Object { $_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM" } |
    					Sort-Object -Unique |
    					ForEach-Object { New-Object psobject -Property @{ Computer = $Computer; LoggedOn = $_ } } |
    					Format-Table -wrap LoggedOn -HideTableHeaders| Out-String
                    }

    Output looks like

    User 1
    User 2
    User 3
    User 4

    Which is fine but I need it to look like

    user1,user2,user3,user4

    Any ideas?

    Thanks

  • #21735
    Profile photo of Don Jones
    Don Jones
    Keymaster

    So, the problem right now if that you're moving everything through Format-Table and Out-String. Not sure I'd do that. If, instead, you did...

    Select-Object -Expand LoggedOn

    You should get the same visual result. From there, just use the -join operator.

    ... -join ","

    -Join will take (on the left side) an array (which is what you're getting, that's why it's one piece of info per line) and (on the right side) a delimiter, and "join" the array elements, separating them with the delimiter. So in this case, I'm guessing "$processinfo -join ','" would be roughly what you're after?

    But the Format- commands are more likely to cause you long-term problems if you're using them that way. Once you format something, you should be "done" with it.

  • #21736
    Profile photo of Paul Goffar
    Paul Goffar
    Participant

    Mr. Jones,

    Thank you for the cleanup tips and I like your point about the formatting. I am a little confused about the join operator however. If you execute that function and then try to recall the $processinfo variable, you lose the sort-object unique and return hundreds of results instead of a couple of user names. I understand how to use join but I guess I don't understand where to use it in this case. Do I need to bring the entire array into a diff variable first?

    🙁

    Paul

  • #21737
    Profile photo of Don Jones
    Don Jones
    Keymaster

    I'm not really clear on what-all your code is trying to do – you've got a lot of stuff jammed into a one-liner. End story, the -join operator takes an array on one side, and a delimiter on the other. You'll need to work out where to stick that into your process. I'm not sure I'd have built the command the same way. You're correct in that it isn't $processinfo – but I don't see where you're storing the output otherwise. You can't pipe to the -join operator; it'd be easiest if you assigned your output to a variable, which you could then use with -join.

  • #21739
    Profile photo of Paul Goffar
    Paul Goffar
    Participant

    UPDATE

    Don,

    As usual, your words made me second guess myself....:)

    And as usual, I just threw away what I had and re-wrote in half of the time and now it works 😛

    
    function Get-LoggedOnUser
    {
    	#Requires -Version 2.0
    	[CmdletBinding()]
    	Param
    	(
    		[Parameter(Mandatory = $true)]
    		[String]$computer
    	)#End Param
    	
    		Write-Host "`n Checking Users . . . "
    		$i = 0
     
     $processinfo = @(Get-WmiObject -class win32_process -ComputerName $Computer) | Foreach-Object {$_.GetOwner().User } |
        Where-Object { $_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM" } |
        Sort-Object -Unique
    
    
     $processinfo -join ","
    }
    
    

    The point of all of this is to return users that are currently logged onto a remote machine by finding process owners and returning a unique list.

    Thanks again for the help!

  • #21743
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Yeah, that's definitely a little easier to follow. As a note, the #requires statement needs to go at the top of the script – it's per-file not so much per-function, since the entire file has to be processed by the shell.

    Consider Write-Verbose instead of Write-Host for that "status" information. [CmdletBinding()] gives you a "free" -verbose parameter that controls the output that way.

    Not sure what $i is doing for ya ;).

    You could simplify your comparison: $_ -notin @("NETWORK SERVICE","LOCAL SERVICE","SYSTEM") that'd constrain you to v3 (the -notin operator), though. You could do a v2-compatible version using -contains or -notcontains, if you were of a mind.

    Good work!

  • #21750
    Profile photo of Sam Boutros
    Sam Boutros
    Participant

    You may also consider:

    (Get-WmiObject Win32_LoggedOnUser -ComputerName $env:COMPUTERNAME | Select Antecedent -Unique).Antecedent | % {
        $_.Substring(6+$_.IndexOf('Name'),$_.Length-(7+$_.IndexOf('Name')))
    } | where { $_ -notin 'system','local service','network service' }
    

You must be logged in to reply to this topic.