12

I am attempting to determine if users in a CSV are active or not, additionally, I want to know if they are service accounts, user accounts, or machine accounts based on OU.

Everything is swell, until I try to output it... The output is on several lines (one for each var).

I would like the output to be on one line (with commas between so I will have a CSV when I am done)... I have tried this twenty different ways with forty different results O_o.

Bonus: add a message for any names that produce errors (i.e. user doesn't exist...) I am thinking of an if/else for that, but have not been able to get the basic output to behave.

I have tried enclosing in parenthesis, concatenating variables, nesting variables... beating my computer with a stick... quietly contemplating my life choices...

$Users = Get-Content C:\ActiveUsers.txt

ForEach ($User in $Users){
$properties = Get-ADUser -Identity $User | select SamAccountName,Enabled,DistinguishedName 
if (Select-String -Pattern "UserMgt" -InputObject $properties) { $base = "User" }
if (Select-String -Pattern "ApplSec" -InputObject $properties) { $base = "Service Account" }
if (Select-String -Pattern "WkstnMgt" -InputObject $properties) { $base = "Machine Account" }
write-output $properties.SamAccountName $properties.Enabled $base
#$Output = Write-Output $properties.SamAccountName $properties.Enabled $base 
#$Output #| out-file  C:\UserStatus-OU2.csv -append
}
1
  • 1
    Maybe something here will help Commented Aug 27, 2019 at 20:10

3 Answers 3

11

This syntax to me is much simpler:

Write-Output "$($var1) $($var2)"
Sign up to request clarification or add additional context in comments.

1 Comment

This answers the question for me. Maybe not for CSV, but it does what the question headline asked, output multiple variables on one single line (instead of one line per each variable).
9

To focus on the general title of your question (see the bottom for the optimal solution in your specific case):

Given multiple variables, say $a, $b, $c, how can I output them as a single-line string, with a configurable separator, say ,?

In the following examples, assume values 'foo', 'bar', 'baz' as the values of variables $a, $b, and $c, respectively, which you can create with the following (destructuring) assignment: $a, $b, $c = 'foo', 'bar', 'baz'.

  • Using the -join operator:
PS> $a, $b, $c -join ','
foo,bar,baz

This approach has the advantage of working with arrays of any size as the LHS.

  • Using an expandable string ("...", string interpolation), as in your own solution:
PS> "$a,$b,$c"
foo,bar,baz
  • Using -f, the string-formatting operator:
PS> '{0},{1},{2}' -f $a, $b, $c
foo,bar,baz

As for what you tried:

Write-Output $properties.SamAccountName $properties.Enabled $base

Passing multiple arguments to Write-Output writes them to the pipeline one by one; if these arguments are strings, each string prints on its own line, which also applies if you send the output to Out-File / > or Set-Content.


That said, since you're creating rows for a CSV file, it's much better to create custom objects to represent the rows and serialize them to a file with Export-Csv (based on the code in your question, not your answer:

Get-Content C:\ActiveUsers.txt | 
  ForEach-Object {
    $properties = Get-ADUser -Identity $_ | Select-Object SamAccountName, Enabled, DistinguishedName 

    # Consider using `elseif` here, unless you really want to evaluate
    # all conditions every time.
    # Also, it's better to check a specific property value rather than
    # searching the string representation of the entire object, e.g.
    #   if ($properties.DistinguishedName -match 'UserMgmt') ...
    if (Select-String -Pattern "UserMgt" -InputObject $properties) { $base = "User" }
    if (Select-String -Pattern "ApplSec" -InputObject $properties) { $base = "Service Account" }
    if (Select-String -Pattern "WkstnMgt" -InputObject $properties) { $base = "Machine Account" }

    # For each user, output a custom object.
    # The custom objects' property names becomes the CSV column headers
    # when Export-Csv processes the outputs.
    [pscustomobject] @{
      SamAccountName = $properties.SamAccountName
      Enabled = $properties.SamAccountName
      Base = $base
    }

  } | Export-Csv -NoTypeInformation C:\UserStatus-OU2.csv

Note the use of a single pipeline.

1 Comment

Glad to hear it, @MarcEverlove. An error inside the loop would only be a problem if it's a terminating error, which you can handle with try { ... } catch { ... }. Treating a foreach loop as an expressions whose multiple outputs are automatically collected in an array is much more efficient than building up an array with += inside the loop. Similarly, calling Export-Csv on all outputs once, outside the loop is much faster than using Export-Csv -Append inside the loop.
0

Ok, I solved it, it would be better as an array but here it is (complete with the 'error handling'):

$Users = Get-Content C:\ActiveUsers.txt

ForEach ($User in $Users){
$properties = $null

$properties = Get-ADUser -Identity $User | select 
SamAccountName,Enabled,DistinguishedName 

If($Properties){

if (Select-String -Pattern "UserMgt" -InputObject $properties) { $base = "User" }
if (Select-String -Pattern "ApplSec" -InputObject $properties) { $base = 
"Service Account" }
if (Select-String -Pattern "WkstnMgt" -InputObject $properties) { $base =   
Machine Account" }


$Sammy = $Properties.SamAccountName
$Enabled = $properties.Enabled

"$Sammy, $Enabled, $base" | out-file =  C:\User_Status_OU.csv -Append

}
Else {

$Sammy = "No Record"
$Enabled = "No Record"
$base = "No Record"


"$Sammy, $Enabled, $base" | out-file =  C:\User_Status_OU.csv -Append
}

8 Comments

is there some reason to NOT use an object? you are building your CSV file manually ... and the Export-CSV cmdlet will handle that for you if you hand it structured objects instead of strings.
Well, most likely; a loose nut behind the keyboard... I know there are better ways, that was just the most expedient that I could muster...
ha! [grin] still, your solution is ... fragile. plus, you were only a short way from building objects to send to the CSV.
right before I tried this bit, but it didn't work properly, the output was the same objects over and over... Dunno what I did wrong, or if it wrote the array everytime there was an error, but the output was over a gig, vs a few mb... :$Poop = @{ Name = $properties.SamAccountName Status = $properties.Enabled Type = $base} $results += New-Object psobject -Property $Poop $Results | Export-Csv C:\UserStatus-OU3.csv -Append
the places where you send out "$Sammy, $Enabled, $base" could easily become an object with those values assigned to properties. then you could either send each out to a CSV, OR gather them into a collection and send that out in one step. that 2nd method would be faster since file writes tend to be rather slow ...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.