none
TerminateADUser – Get-ADPrincipalGroupMembership – MemberOf und CSV Export RRS feed

  • Frage

  • Hallo Zusammen,

    ich möchte mittels einem PS Skript AD Benutzerkonten geregelt terminieren.
    Hierzu habe eine PS-Skript Function erstellt, die mit einem Parameter -AccountToTerminate 'SamAccountName' gestartet werden soll.
    Innerhalb des Skripts sollen zum AD-Object und seinen Funktionen  wichtige Informationen in "eine" CSV-Datei zum entsprechenden Job (Job-ID) ablegt werden.

    Einzelne Attributen und Werten stellen kein Problem dar, jedoch stoße ich bei der Verarbeitung von String-Arrays oder Typ "System.Array" immer wieder auf Probleme, was auch an meinem Verständnis liegen mag. :-(

    Ich möchte für den ausgewählten Benutzer, eine CSV-Tabelle erstellen, mit Spalten:
    DisplayName, SamAccountName, SID, etc.

    sowie z.B. eine Spalte für die aktuellen Gruppenmitgliedschaften
    MemberOf, MemberOfSID

    oder die benutzen ActiveSync Geräte:
    MobileDevices, etc.

    Folgender Code (nur Teile) nutze ich zum sammeln der Informationen und dem Export ($efile):

    CODE:
    # Auswahl SamAccountName
    $AccountToTerminate      = 'mustermann.max'
    # Auslesen AD-Attribute und Funktionen
    $ADUser                  = Get-ADUser -Identity $AccountToTerminate -Property * | Sort-Object
    $UserMemberOf            = Get-ADPrincipalGroupMembership -Identity $AccountToTerminate | Select-Object  SamAccountName, SID
    IF ($ADUser.'msExchMailboxGuid' -eq $Null){
        [String]$UserMailboxEnabled    = "Disabled"
        [String]$UserEmailAddress      = "NotSet"
        }
    ELSE {
        [String]$UserMailboxEnabled   = "Enabled"
        [String]$UserEmailAddress     = $ADUser.'mail'
        $UserMailbox                  = Get-Mailbox $AccountToTerminate
        $UserCASMailbox               = Get-CASMailbox $AccountToTerminate
        $UserMobileDevices            = Get-MobileDeviceStatistics -Mailbox $AccountToTerminate
        }
    # Ergebnisse zusammenbauen
    [Array]$Result           = @()
    $Object                  = New-Object PSObject
        Add-Member -InputObject $Object -memberType NoteProperty -Name DisplayName        -Value $ADUser.'DisplayName'
        Add-Member -InputObject $Object -memberType NoteProperty -Name SamAccountName     -Value $ADUser.'SamAccountName'
        Add-Member -InputObject $Object -memberType NoteProperty -Name SID                -Value $ADUser.'objectSID'.Value
        Add-Member -InputObject $Object -memberType NoteProperty -Name MailboxEnabled     -Value $UserMailboxEnabled
        Add-Member -InputObject $Object -memberType NoteProperty -Name EmailAddress       -Value $UserEmailAddress
        #
    	Add-Member -InputObject $Object -memberType NoteProperty -Name MemberOf           -Value $UserMemberOf.SamAccountName
        Add-Member -InputObject $Object -memberType NoteProperty -Name MemberOfSID        -Value $UserMemberOf.SID.Value	
    $Result += $Object
    # Ergebnisse in eine CSV Datei exportieren und diese öffnen
    $Result                  | Export-Csv -Path $efile -Delimiter ";" -Encoding UTF8 -NoTypeInformation -ErrorAction $ErrorActionPreference
    & $efile
    Nun die Frage!

    1. Wie bekommt man es hin, die Mehrfach Werte (wie zum Beispiel 'MemberOf' oder 'MemberOfSID' in NUR eine "Spalte 'MemberOfSID'" in das $Result Array zu bringen und auch zu exportieren? 

    Also zum Benutzer und seine Werte NUR eine Spalte "MemberOf" und darunter alle Gruppenmitgliedschaften?

    Jeder Ansatz von mir, mit Schleifen oder 'System.Collections.ArrayList' führten zu keinem Ergbenis.
    Der direkte CSV-Export der Variable '$UserMemberOf' in eine weitere Datei stellt kein Problem dar!?
    Möchte jedoch zum Vorgang (Job-ID) nur eine Datei erstellen...

    Vielen Dank im Voraus für jede Art der Zusammenarbeit.

    Manfred Schüler

    Montag, 28. September 2015 08:21

Antworten

  • Hi Manfred,

    • Wenn du die Werte einzeln zufügst kommen die nicht untereinander sondern nebeneinander an.
    • Alternativ zu csv kannst du auch direkte xlsx bauen, indem du Excel als ComObject angräbst
    • Schleife ... schwierig ... hm.......
    $Result = @()
    $n = 0
    
    while ($n -lt $UsermemberOf.Count)
    {
    if ($n -eq 0)
    {
    $props = @{
    	DisplayName = $ADUser.DisplayName
    	SamAccountName = $ADUser.SamAccountName
    	SID = $ADUser.objectSID.Value
    	MailboxEnabled = $UserMailboxEnabled
    	EmailAddress = $UserEmailAddress
    	MemberOf = $UserMemberOf[$n].SamAccountName
    	MemberOfSID = $UserMemberOf[$n].SID.Value
    }
    $Result += New-Object PSObject -Property $props
    }
    
    else
    {
    $props = @{
    	DisplayName = ""
    	SamAccountName = ""
    	SID = ""
    	MailboxEnabled = ""
    	EmailAddress = ""
    	MemberOf = $UserMemberOf[$n].SamAccountName
    	MemberOfSID = $UserMemberOf[$n].SID.Value
    }
    $Result += New-Object PSObject -Property $props
    }
    $n++
    }

    :)

    Grüße,
    Friedrich


    There's no place like 127.0.0.1


    • Als Antwort markiert MSchueler Dienstag, 6. Oktober 2015 15:10
    • Bearbeitet FWN Dienstag, 6. Oktober 2015 15:26 Implementierung kleine Korrektur (siehe Post unten)
    Mittwoch, 30. September 2015 15:17

Alle Antworten

  • Hi Manfred,

    aaaalso, erstmal, dein Objekt kann man einfacher und übersichtlicher bauen:

    $props = @{
    	DisplayName = $ADUser.DisplayName
    	SamAccountName = $ADUser.SamAccountName
    	SID = $ADUser.objectSID.Value
    	MailboxEnabled = $UserMailboxEnabled
    	EmailAddress = $UserEmailAddress
    	MemberOf = $UserMemberOf.SamAccountName
    	MemberOfSID = $UserMemberOf.SID.Value
    }
    New-Object PSObject -Property $props

    dann, passt man das noch im gleichen Zug an, indem man die verschiedenen Werte während der Zuweisung zusammenfügt (ich verwende hier ", " zum Zusammenfügen, jeder andere String funktioniert aber ähnlich gut):

    $props = @{
    	DisplayName = $ADUser.DisplayName
    	SamAccountName = $ADUser.SamAccountName
    	SID = $ADUser.objectSID.Value
    	MailboxEnabled = $UserMailboxEnabled
    	EmailAddress = $UserEmailAddress
    	MemberOf = $UserMemberOf.SamAccountName -join ", "
    	MemberOfSID = $UserMemberOf.SID.Value -join ", "
    }
    New-Object PSObject -Property $props

    Und schon passt das alles :)

    Dann noch zu deinem Export-Csv Aufruf:

    • Encoding: Für das lokal übliche Encoding - grade für Sonderzeichen - empfehle ich encoding typ "Default" zu verwenden. Falls das ganze über verschiedene Regionen hinweg verwendet werden soll ist was Festes natürlich erforderlich.
    • ErrorAction: Explizit ErrorAction $ErrorActionPreference anzugeben ist redundant - diese wird standardmäßig sowieso verwendet.
    • Es ist nicht erforderlich explizit einen Array zu bauen, um diesen an Export-Csv zu übergeben, du kannst auch ein einzelnes Objekt übergeben.

    Grüße,
    Friedrich


    There's no place like 127.0.0.1


    • Bearbeitet FWN Dienstag, 29. September 2015 15:17
    Dienstag, 29. September 2015 15:15
  • Hallo Friedrich,

    danke für deine Unterstützung.

    Grundsätzlich "gibt es viele Wege nach Rom" ;-)
    Mit meiner PS Erfahrung von ein paar Monaten, suche ich, wie viele andere aber auch, nach dem goldenen Weg nach Rom :-)

    zu Results:

    Dein Vorschlag mit dem "Props" Array habe ich schon öfter genutzt, jedoch dabei festgestellt das dann keine Sortierung der Spaltenüberschrift im CSV-Export erfolgt (Höchstens mit $ResultSort = $Result |  sort)

    Mit Add-Member kann ich deinen Vorschlag auch realisieren:

    $Object                  = New-Object PSObject -Property Test, Test2
            Add-Member -InputObject $Object -memberType NoteProperty -Name DisplayName        -Value $ADUser.'DisplayName'
            Add-Member -InputObject $Object -memberType NoteProperty -Name SamAccountName     -Value $ADUser.'SamAccountName'
            Add-Member -InputObject $Object -memberType NoteProperty -Name SID                -Value $ADUser.'objectSID'.Value
            Add-Member -InputObject $Object -memberType NoteProperty -Name MailboxEnabled     -Value $UserMailboxEnabled
            Add-Member -InputObject $Object -memberType NoteProperty -Name EmailAddress       -Value $UserEmailAddress
            Add-Member -InputObject $Object -memberType NoteProperty -Name LyncEnabled        -Value $UserLyncEnabled
            Add-Member -InputObject $Object -memberType NoteProperty -Name SIPAddress         -Value $UserLyncSIP
            Add-Member -InputObject $Object -memberType NoteProperty -Name MemberOf           -Value ($UserMemberOf.SamAccountName -join ", ")
            Add-Member -InputObject $Object -memberType NoteProperty -Name MemberOfSID        -Value ($UserMemberOf.SID.Value -join ", ")
            #

    Ziel (weiß halt nicht ob das überhaupt funktioniert) ist jedoch das die Ergebnisse zum Attribute "MemberOf" in der entsprechende Spalte untereinander ausgelistet werden, was bei einer hohen Anzahl in Excel auch sinnvoll erscheint!?

    So wie hier:

    Zum Export-CSV

    • Ich nutze gerade wegen unseren Umlauten und den internationalen Akzente-Zeichen das UTF8 Format. Ist dies nicht zu empfehlen?
    • Die Variable $ErrorActionPreference habe ich im Script (war nicht vollständig aufgeführt) vorab deklariert um diese global bei bedarf ändern zu können.

    LG


    Manfred Schüler

    Mittwoch, 30. September 2015 11:15
  • Hi Manfred,

    Results
    Da hast du natürlich Recht mit der Eigenschaftssortierung, aber erfahrungsgemäß ist das dafür deutlich härter zu warten im Script. Reihenfolge und Darstellung ist in meinen Augen eine Sache, die nur direkt vor Darstellung / Output implementiert werden sollte. Das lässt sich über Select-Object direkt vor dem Export realisieren. Beispiel:

    $Results | Select DisplayName, SamAccountName, SID, MailboxEnabled, EmailAddress, LyncEnabled, SIPAddress, MemberOf, MemberOfSID | Export-Csv ...

    Export-Csv Encoding
    "Default" berücksichtigt alle lokalen Gegebenheiten. UTF8 kann zwar auch Umlaute korrekt darstellen, aber dritt-Anwendungen arbeiten oft besser mit den lokalen Encodings. Default funktioniert auch bei Usern mit komplett anderen Schriftsätzen (zb. könntest du das Skript dann einem Chinesischen Kollegen weitergeben).

    Wie aber gesagt funktioniert es nur innerhalb eines Kulturkreises. Für einen Transfer der Daten von Deutschland - China müsste dann vorraussichtlich explizit ein Encoding gewählt werden (wie UTF8).

    ErrorActionPreference
    Die Variable existiert bereits beim Start der Konsole. Überschreibst du diese in deinem Script berücksichtigen diese alle Funktionen in der Scope in der das geschieht und in allen Unterscopes. Daher sind diese beiden Befehlsaufrufe synonym:

    #region Version 1
    # Anfang des Scripts
    $ErrorActionPreference = "SilentlyContinue"
    
    # ...
    # ...
    # ...
    
    # Funktionsaufruf
    $Results | Export-Csv file.csv -ErrorAction $ErrorActionPreference
    #endregion Version 1
    
    
    #region Version 2
    # Anfang des Scripts
    $ErrorActionPreference = "SilentlyContinue"
    
    # ...
    # ...
    # ...
    
    # Funktionsaufruf
    $Results | Export-Csv file.csv
    #endregion Version 2

    Grüße,
    Friedrich


    There's no place like 127.0.0.1

    Mittwoch, 30. September 2015 13:03
  • Hi Friedrich,

    wiederum danke für dein Feedback.

    Das Thema Error Handling steht noch auf meiner "learning agenda"! :-) 

    Hast du auch noch eine Idee wie ich die Ausgabe wie oben gezeigt hin bekomme?
    Ich weiß, ich bin Anspruchsvoll , aber es reizt mich ...



    Manfred Schüler

    Mittwoch, 30. September 2015 14:41
  • Ach ja, da war ja noch was.

    In Csv geht das nur auf eine Weiße:
    Du erstellst leere Dummy-Objekte mit allen Eigenschaften leer außer den beiden.

    Du brauchst also die Anzahl an Zeilen die du benötigst (Länge Gruppenmitgliedschaften). Dann machst du eine Schleife die X-mal läuft, beim ersten mal schreibst du die vollen Werte und die erste Gruppe rein, in allen weiteren Durchläufen dann jeweils leere Strings plus die entsprechend näcshte Gruppe.

    Grüße,
    Friedrich


    There's no place like 127.0.0.1

    Mittwoch, 30. September 2015 14:45
  • Herrje, das klingt kompliziert ... !

    Kann man dem PSCustomObject nicht durch eine Schleife in die Spalte 'MemberOf' (Property) die Werte als Schleife hinzufügen?
    Schließlich kann ich die Spalte doch auch direkt ansprechen? $Result.'MemberOf'

    1. "In Csv geht das nur auf eine Weiße"
      Was würdest du sonst als Ausgabe nutzen?
    2. Schleife
      Der Gedanke mit der Schleife ist auch mein Ansatz,  jedoch müsste ich bei verschiedenen Werte.Counts den höchsten erst einmal ermitteln und das scheint mir nun doch zu schwierig :-(
    $InterimResults = ForEach ($obj in $UserMemberOf) {
        New-Object -TypeName PSObject -Property @{
                            'DisplayName' = $ADUser.'DisplayName'
                            'SamAccountName' = $ADUser.'SamAccountName'
                            'MailboxEnabled' = $UserMailboxEnabled
                            'EmailAddress' = $UserEmailAddress
                            'MemberOf' = $obj.SamAccountName
                            'MemberOfSID' = $obj.SID.Value
            }
        }


    Manfred Schüler

    Mittwoch, 30. September 2015 15:03
  • Hi Manfred,

    • Wenn du die Werte einzeln zufügst kommen die nicht untereinander sondern nebeneinander an.
    • Alternativ zu csv kannst du auch direkte xlsx bauen, indem du Excel als ComObject angräbst
    • Schleife ... schwierig ... hm.......
    $Result = @()
    $n = 0
    
    while ($n -lt $UsermemberOf.Count)
    {
    if ($n -eq 0)
    {
    $props = @{
    	DisplayName = $ADUser.DisplayName
    	SamAccountName = $ADUser.SamAccountName
    	SID = $ADUser.objectSID.Value
    	MailboxEnabled = $UserMailboxEnabled
    	EmailAddress = $UserEmailAddress
    	MemberOf = $UserMemberOf[$n].SamAccountName
    	MemberOfSID = $UserMemberOf[$n].SID.Value
    }
    $Result += New-Object PSObject -Property $props
    }
    
    else
    {
    $props = @{
    	DisplayName = ""
    	SamAccountName = ""
    	SID = ""
    	MailboxEnabled = ""
    	EmailAddress = ""
    	MemberOf = $UserMemberOf[$n].SamAccountName
    	MemberOfSID = $UserMemberOf[$n].SID.Value
    }
    $Result += New-Object PSObject -Property $props
    }
    $n++
    }

    :)

    Grüße,
    Friedrich


    There's no place like 127.0.0.1


    • Als Antwort markiert MSchueler Dienstag, 6. Oktober 2015 15:10
    • Bearbeitet FWN Dienstag, 6. Oktober 2015 15:26 Implementierung kleine Korrektur (siehe Post unten)
    Mittwoch, 30. September 2015 15:17
  • Hallo Manfred, ist dein Problem damit gelöst? Dann markiere doch bitte entsprechend die Antworten.

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Kostenloser Powershell Snippet Manager v4: Link ! Neue Version !
    (Schneller, besser + komfortabler scripten.)

    Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
    Warum das Ganze? Hier gibts die Antwort.

    Dienstag, 6. Oktober 2015 01:39
    Moderator
  • Hallo Denniver,

    leider konnte ich mich erst jetzt wieder dem Thema widmen. Habe meine Antwort gerade beim Beitrag von Friedrich hinzugefügt.

    Gruß


    Manfred Schüler

    Dienstag, 6. Oktober 2015 14:49
  • Hallo Friedrich,

    sorry leider etwas verspätet, habe mir gerade dein PS Code angeschaut und ausgeführt.

    Nutze ich diesen wie beschrieben, erhalte ich keine Ergebnisse in der Variable "$Result".

    Ändere ich deinen Code wie folgt ab, kommt genau mein gewünschtes Ergebnis zustande, SUPER :-) TOP!!!

    $Result = @()
    $n = 0
    #
    while ($n -lt $UsermemberOf.Count) {
    if ($n -eq 0) {
    $props = @{
    	DisplayName = $ADUser.DisplayName
    	SamAccountName = $ADUser.SamAccountName
    	SID = $ADUser.objectSID.Value
    	MailboxEnabled = $UserMailboxEnabled
    	EmailAddress = $UserEmailAddress
    	MemberOf = $UserMemberOf[$n].SamAccountName
    	MemberOfSID = $UserMemberOf[$n].SID.Value
    }
    $Result += New-Object PSObject -Property $props
    }
    
    else {
    $props = @{
    	DisplayName = ""
    	SamAccountName = ""
    	SID = ""
    	MailboxEnabled = ""
    	EmailAddress = ""
    	MemberOf = $UserMemberOf[$n].SamAccountName
    	MemberOfSID = $UserMemberOf[$n].SID.Value
    }
    $Result += New-Object PSObject -Property $props
    }
    $n++
    }

    Geändert habe ich nur die While Bedingung

    # $UsermemberOf in $UsermemberOf.Count

    Bin mir zwar nicht sicher, ob das Syntax technisch in Ordnung ist, aber so funktioniert die Ausgabe $False/$True besser und zudem dann auch das Ergebnis.

    Wieder was dazu gelernt ;-)

    Dir im speziellen vielen Dank und evtl. Gruß an die MS Programmierer, bei Arrays ggf. horizontal und vertikal Werte setzen zu können ... aber vermutlich bin ich eher das Problem :-)


    Manfred Schüler


    • Bearbeitet MSchueler Dienstag, 6. Oktober 2015 15:11
    Dienstag, 6. Oktober 2015 15:10
  • Hi Manfred,

    freut mich, dass das jetzt alles funktioniert.

    Bezüglich multidimensionaler Arrays, probier mal das hier:

    [int[][]]$a = new-object int[][](10,10)
    $a[0][1] = 42

    Funktioniert einwandfrei. Das Problem hier ist das CSV Format, das schlicht nicht dafür gedacht ist. Für multiline Darstellung könnte html guten Output anbieten, Excel Spreadsheets oder XML eignen sich aber auch.

    Letzten Endes ist es ja primär eine Frage des Konsummentens.

    Grüße,
    Friedrich


    There's no place like 127.0.0.1


    • Bearbeitet FWN Dienstag, 6. Oktober 2015 16:09 Replaced "new" with "new-object", "new" being a custom alias ...
    Dienstag, 6. Oktober 2015 15:29
  • Hi Friedrich,

    ich verstehe langsam ... sehr langsam 

    [int[][]]$a = new-object int[][](5,5)
    $a[0][0] = 42
    $a[1][0] = 24
    $a[2][0] = 44
    $a[3][0] = 22
    $a[4][0] = 12
    
    $a | Export-csv -Path C:\Temp\Output.csv -NoTypeInformation
    $a | Export-Clixml -Path C:\Temp\Output.xml

    Im XML sind auch die Werte zu sehen, im CSV nicht.

    Ist der Aufbau grundsätzlich auch, statt mit einem Zahlen Array, wie in Excel SpaltenName, ZeilenInhalt möglich?



    Manfred Schüler

    Freitag, 9. Oktober 2015 09:07
  • Hi Manfred,

    das ist genau der Punkt: Csv kann so etwas nicht wirklich nativ abbilden. Die oben beschriebene Methode mit Dummy-Objekten ist da leider der einzige Weg.

    Für Export mit Xml kannst du dein originales Objekt, mit Array Eigenschaften, verwenden. multidimensionale Arrays sind eher eine Spielerei, die in PowerShell meist nicht notwendig sind (du könntest aber zb ein Schachspiel darüber abbilden, oder Schiffe versenken).

    Wenn du andere Inhalte als nur Zahlen in einem multidimensionalen Array verwenden willst, dann kannst du den Array als "Object" deklarieren, statt als "int". Daraufhin kannst du einfach alles reinschieben was dir gefällt.

    Excel Tabellen direkt befüllen ist auch gut möglich, wenn du das wirklich willst, erfordert aber deutlich mehr Aufwand.

    Tip: Funktionen
    Falls du wirklich häufiger vor dem Problem hier stehst, empfehle ich eine maßgeschneiderte Export-CsvCustom Funktion zu schreiben, die den Vorgang oben für dich abbildet, also Dummy-Objekte erstellt und das Ganze exportiert. Die kann man dann recht simpel wiederverwenden.

    Grüße,
    Friedrich


    There's no place like 127.0.0.1

    Freitag, 9. Oktober 2015 13:02
  • Hi Friedrich,

    komme so erstmal klar und denke das andere ist doch sehr aufwendig.

    Danke nochmals für deine Unterstützungen und deine Erklärungen.

    Schönes WE.

    VG


    Manfred Schüler

    Freitag, 9. Oktober 2015 13:24