7

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
}
Techknow
  • 161
  • 1
  • 3
  • 11
  • 1
    Maybe something [here](https://stackoverflow.com/questions/3896258/how-do-i-output-text-without-a-newline-in-powershell) will help – techguy1029 Aug 27 '19 at 20:10

3 Answers3

7

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 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. – mklement0 Aug 29 '19 at 17:06
4

I realize this is an old question, but it might help someone who's looking for a simple solution. This syntax to me is much simpler:

Write-Output "$($var1) $($var2)"
naveed
  • 1,395
  • 2
  • 15
  • 29
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
}
Techknow
  • 161
  • 1
  • 3
  • 11
  • 1
    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. – Lee_Dailey Aug 27 '19 at 21:50
  • 1
    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... – Techknow Aug 28 '19 at 17:19
  • 1
    ha! [*grin*] still, your solution is ... fragile. plus, you were only a short way from building objects to send to the CSV. – Lee_Dailey Aug 28 '19 at 17:24
  • 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 – Techknow Aug 28 '19 at 17:30
  • 1
    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 ... – Lee_Dailey Aug 28 '19 at 17:40
  • I have noticed that most of my solutions are ... fragile... – Techknow Oct 12 '20 at 20:17
  • everyone seems to start out on the fragile side when it comes to coding ... [*grin*] – Lee_Dailey Oct 12 '20 at 20:52
  • Lolz, I seem to have been starting out for a long time, sigh. Thanks for the input on the output [grin] . I struggle with the finer points. – Techknow Apr 15 '21 at 20:45