derhoeppi
Goto Top

PowerShell Import Text

Hallo,

ich habe mal eine Frage an die Profis. Ich erstelle gerade ein Script, welches den Arbeitsablauf beschleunigen und standardisieren soll. Dabei geht es um das Anlegen von Benutzer im AD inkl. Gruppenzuweisung und das Anlegen von Portgruppen im vCenter. Wenn ich das einzeln machen würde, hätte ich mir für jede dieser Aufgaben eine CSV Datei erstellt und diese entsprechend eingelesen. Damit es aber für die Kollegen handle bar ist, frage ich mich, ob diese Information nicht in einer Datei stehen können. Aus meiner Sicht besteht das Problem darin, dass die Anzahl der Benutzer oder eben der Portgruppen variable ist, so dass das selektieren der einzelnen Bereiche schwer fällt.

Die Datei hätte ich mir in etwa so vorgestellt:
#ActiveDirectory
#Vorname, Nachname, Login
Max,Mustermann,MustermannMax
Karl,August,AugustKarl

#vCenter
#Bezeichnung,VlanID,PrivatVLANTag
LAN1,50,
Lan2,60,Promiscouse
Lan3,70,Isolated

Wie würdet Ihr solch eine Datensammlung und Verarbeitung lösen? Ist eine CSV vielleicht nicht das richtige oder gibt es bessere Möglichkeiten?

Gruß
derhoeppi

Content-Key: 284092

Url: https://administrator.de/contentid/284092

Printed on: April 24, 2024 at 06:04 o'clock

Member: colinardo
Solution colinardo Sep 28, 2015, updated at Sep 29, 2015 at 11:28:58 (UTC)
Goto Top
Guten Abend @derhoeppi,
also ich persönlich würde das schon in zwei separate Files trennen, da das eine mit dem anderen hier ja eigentlich nicht viel gemeinsam hat.
Realisieren lässt sich sowas aber, wenn es unbedingt sein muss, problemlos mit Regular Expressions.
Z.b. lässt sich der folgende leicht abgewandelte Inhalt deiner Datei
#ActiveDirectory-Start
Vorname,Nachname,Login
Max,Mustermann,MustermannMax
Karl,August,AugustKarl
#ActiveDirectory-End

#vCenter-Start
Bezeichnung,VlanID,PrivatVLANTag
LAN1,50,
Lan2,60,Promiscouse
Lan3,70,Isolated
#vCenter-End
mit diesem Code in zwei separate Objekte einlesen:
$settings = gc 'c:\settings.txt' | out-string  
$users = [regex]::match($settings,'(?ism)^#ActiveDirectory-Start\s*(.*?)#ActiveDirectory-End').Groups[1].Value | ConvertFrom-CSV -delimiter ","  
$vCenter = [regex]::match($settings,'(?ism)^#vCenter-Start\s*(.*?)#vCenter-End').Groups[1].Value | ConvertFrom-CSV -delimiter ","  
Der Code extrahiert via Regex deine zwei durch die speziellen Markierungen gesetzten Blöcke und schickt sie an Convertfrom-CSV um sie zu handelbaren Objekten zu konvertieren. Das ganze lässt sich natürlich nach Belieben erweitern.

Trotzdem wären mit zwei CSV wahrscheinlich lieber, da die Leute hier hinterher kein Copy n' Paste in das zusammenfassende File machen müssen. Aber das bleibt deinem Gusto überlassen face-smile

Grüße Uwe
Member: derhoeppi
derhoeppi Sep 29, 2015 at 11:28:44 (UTC)
Goto Top
Hallo Uwe,

vielen Dank für die Ausführung. Ich werde mir das ganze noch ein paar Tage durch den Kopf gehen lassen. Ich bin von der 1-Datei Lösung auch nicht ganz überzeugt, finde aber mehrere Dateien auch nicht schön, weil das editieren einer Datei schnell vergessen wird und dann werden Kommandos ausgeführt, die bereits ausgeführt wurden. Das wird natürlich abgefangen, aber glücklich wäre ich darüber nicht.

Gruß
derhoeppi
Member: colinardo
colinardo Sep 29, 2015 at 13:05:55 (UTC)
Goto Top
Zitat von @derhoeppi:
finde aber mehrere Dateien auch nicht schön, weil das editieren einer Datei schnell vergessen wird und dann werden Kommandos ausgeführt, die bereits ausgeführt wurden. Das wird natürlich abgefangen, aber glücklich wäre ich darüber nicht.
Dann mach dir halt eine simple GUI in der du deine User die CSV-Files aus dem Dateisystem auswählen lässt, welche du dann mit deinem Skript auf Gültigkeit prüfst und dann importierst.
Da bist du als Programmierer gefragt das alles abzufangen.
Ebenso sollte man natürlich vor dem AD Import checken ob es einen User mit dem gleichen Namen schon gibt etc., das alles musst du bedenken, erst dann wird es absolut Wasser- und DAU-Fest.
Zum AD Import und Check habe ich hier ja schon diverse Skripte gepostet ... Einfach mal die Suche anschmeißen, dann findest du dazu diversen Input von mir.

Grüße Uwe
Member: derhoeppi
derhoeppi Sep 30, 2015 at 17:41:45 (UTC)
Goto Top
Hallo Uwe,

ich habe heute mal mit meinen Kollegen gesprochen. Diese würden eine GUI für alles favorisieren. Deshalb habe ich heute mal ein Layout entworfen das ich nun mit Leben füllen möchte.
Dabei stoße ich auf ein Problem. Ich möchte die anzulegenden Benutzer in einem ListView festhalten und diese nicht aus einer CSV importieren. Das Problem ist nun das ListView Handling. Ich habe neben dem ListView TextBoxen, deren Inhalt ich in einzelne Variablen schreibe. Nun möchte ich diesen Inhalt in einzelne Spalten des ListViews schreiben. Der Header der Spalten habe ich bereits in den ListView Eigenschaften angelegt.

Im Internet habe ich einige Beispiele gefunden, die mich letztlich zu diesem Code geführt haben:

$item = New-Object System.Windows.Forms.ListViewItem($FirstName)
    [void] $item.SubItems.Add($LastName)
    [void] $item.SubItems.Add($Login)
    $LV_Network.Items.Add($item)

Wenn ich das ausführe, steht in dem Listview in jeder Spalte "ListViewItem:{$FirstName}". Statt $FirstName steht natürlich der Inhalt der Variablen dort. Wie bekomme ich es aber hin, dass nur der Name dort steht und dass auch die anderen beiden Variablen in den entsprechenden Spalten stehen?

Gruß
derhoeppi
Member: colinardo
colinardo Sep 30, 2015 updated at 18:20:28 (UTC)
Goto Top
Ein veraltetes ListView verwenden ? Wir haben doch mit Powershell so schöne Controls wie das DataGridView face-smile

#Form Function
function GenerateForm {

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null  
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null  
#endregion

#region Form Objects
$form1 = New-Object System.Windows.Forms.Form
$btnOK = New-Object System.Windows.Forms.Button
$dgv = New-Object System.Windows.Forms.DataGridView
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
# Event Script Blocks
#----------------------------------------------
$handler_btnOK_Click= 
{
    $dgv.Rows | ?{!$_.IsNewRow} | %{
        $vorname = $_.Cells.Value
        $nachname = $_.Cells[1].Value
        $loginname = $_.Cells[2].Value
        [System.Windows.Forms.MessageBox]::Show($vorname + " # " + $nachname + " # " + $loginname)  
    }

}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 214
$System_Drawing_Size.Width = 359
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"  
$form1.Text = "Demo"  


$btnOK.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 272
$System_Drawing_Point.Y = 180
$btnOK.Location = $System_Drawing_Point
$btnOK.Name = "btnOK"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 75
$btnOK.Size = $System_Drawing_Size
$btnOK.TabIndex = 1
$btnOK.Text = "OK"  
$btnOK.Anchor = 10
$btnOK.UseVisualStyleBackColor = $True
$btnOK.add_Click($handler_btnOK_Click)

$form1.Controls.Add($btnOK)

$dgv.Anchor = 15
$System_Windows_Forms_DataGridViewTextBoxColumn_4 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$System_Windows_Forms_DataGridViewTextBoxColumn_4.AutoSizeMode = 16
$System_Windows_Forms_DataGridViewTextBoxColumn_4.HeaderText = "Vorname"  
$System_Windows_Forms_DataGridViewTextBoxColumn_4.Name = ""  
$System_Windows_Forms_DataGridViewTextBoxColumn_4.Width = 97

$dgv.Columns.Add($System_Windows_Forms_DataGridViewTextBoxColumn_4)|Out-Null
$System_Windows_Forms_DataGridViewTextBoxColumn_5 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$System_Windows_Forms_DataGridViewTextBoxColumn_5.AutoSizeMode = 16
$System_Windows_Forms_DataGridViewTextBoxColumn_5.HeaderText = "Nachname"  
$System_Windows_Forms_DataGridViewTextBoxColumn_5.Name = ""  
$System_Windows_Forms_DataGridViewTextBoxColumn_5.Width = 98

$dgv.Columns.Add($System_Windows_Forms_DataGridViewTextBoxColumn_5)|Out-Null
$System_Windows_Forms_DataGridViewTextBoxColumn_6 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$System_Windows_Forms_DataGridViewTextBoxColumn_6.AutoSizeMode = 16
$System_Windows_Forms_DataGridViewTextBoxColumn_6.HeaderText = "Loginname"  
$System_Windows_Forms_DataGridViewTextBoxColumn_6.Name = ""  
$System_Windows_Forms_DataGridViewTextBoxColumn_6.Width = 97

$dgv.Columns.Add($System_Windows_Forms_DataGridViewTextBoxColumn_6)|Out-Null
$dgv.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$dgv.Location = $System_Drawing_Point
$dgv.Name = "dgv"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 162
$System_Drawing_Size.Width = 335
$dgv.Size = $System_Drawing_Size
$dgv.TabIndex = 0

$form1.Controls.Add($dgv)

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm
Member: colinardo
colinardo Sep 30, 2015 updated at 18:40:59 (UTC)
Goto Top
Falls du es doch mit einem ListView machen willst hier beide Varianten in einer Form:
Dann hast du die Qual der Wahl face-smile
Zur Info und deiner Frage: Zum Hinzufügen eines ListView-Items mit dessen Subitems kannst du eine verkürzte Variante nehmen:
$deinListView.Items.Add("Max").SubItems.AddRange(@("Muster","mmuster"))

#Generated Form Function
function GenerateForm {

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null  
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null  
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$btnAddItem = New-Object System.Windows.Forms.Button
$lv = New-Object System.Windows.Forms.ListView
$btnOK = New-Object System.Windows.Forms.Button
$dgv = New-Object System.Windows.Forms.DataGridView
$columnHeader1 = New-Object System.Windows.Forms.ColumnHeader
$columnHeader2 = New-Object System.Windows.Forms.ColumnHeader
$columnHeader3 = New-Object System.Windows.Forms.ColumnHeader
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------

$handler_btnOK_Click= 
{
    $dgv.Rows | ?{!$_.IsNewRow} | %{
        $vorname = $_.Cells.Value
        $nachname = $_.Cells[1].Value
        $loginname = $_.Cells[2].Value
        [System.Windows.Forms.MessageBox]::Show($vorname + " # " + $nachname + " # " + $loginname)  
    }

}

$handler_btnAddItem_Click= 
{
    $lv.Items.Add("Max").SubItems.AddRange(@("Muster","mmuster"))  

}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 356
$System_Drawing_Size.Width = 435
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.FormBorderStyle = 3
$form1.MaximizeBox = $False
$form1.Name = "form1"  
$form1.SizeGripStyle = 2
$form1.Text = "Demo"  


$btnAddItem.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 292
$System_Drawing_Point.Y = 321
$btnAddItem.Location = $System_Drawing_Point
$btnAddItem.Name = "btnAddItem"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 131
$btnAddItem.Size = $System_Drawing_Size
$btnAddItem.TabIndex = 3
$btnAddItem.Text = "Item hinzufügen"  
$btnAddItem.UseVisualStyleBackColor = $True
$btnAddItem.add_Click($handler_btnAddItem_Click)

$form1.Controls.Add($btnAddItem)


$lv.Columns.Add($columnHeader1)|Out-Null
$lv.Columns.Add($columnHeader2)|Out-Null
$lv.Columns.Add($columnHeader3)|Out-Null
$lv.DataBindings.DefaultDataSourceUpdateMode = 0
$lv.FullRowSelect = $True
$lv.HideSelection = $False
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 198
$lv.Location = $System_Drawing_Point
$lv.Name = "lv"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 117
$System_Drawing_Size.Width = 411
$lv.Size = $System_Drawing_Size
$lv.TabIndex = 2
$lv.UseCompatibleStateImageBehavior = $False
$lv.View = 1

$form1.Controls.Add($lv)

$btnOK.Anchor = 10

$btnOK.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 292
$System_Drawing_Point.Y = 165
$btnOK.Location = $System_Drawing_Point
$btnOK.Name = "btnOK"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 131
$btnOK.Size = $System_Drawing_Size
$btnOK.TabIndex = 1
$btnOK.Text = "Collection auflisten"  
$btnOK.UseVisualStyleBackColor = $True
$btnOK.add_Click($handler_btnOK_Click)

$form1.Controls.Add($btnOK)

$System_Windows_Forms_DataGridViewTextBoxColumn_19 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$System_Windows_Forms_DataGridViewTextBoxColumn_19.AutoSizeMode = 16
$System_Windows_Forms_DataGridViewTextBoxColumn_19.HeaderText = "Vorname"  
$System_Windows_Forms_DataGridViewTextBoxColumn_19.Name = ""  
$System_Windows_Forms_DataGridViewTextBoxColumn_19.Width = 123

$dgv.Columns.Add($System_Windows_Forms_DataGridViewTextBoxColumn_19)|Out-Null
$System_Windows_Forms_DataGridViewTextBoxColumn_20 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$System_Windows_Forms_DataGridViewTextBoxColumn_20.AutoSizeMode = 16
$System_Windows_Forms_DataGridViewTextBoxColumn_20.HeaderText = "Nachname"  
$System_Windows_Forms_DataGridViewTextBoxColumn_20.Name = ""  
$System_Windows_Forms_DataGridViewTextBoxColumn_20.Width = 122

$dgv.Columns.Add($System_Windows_Forms_DataGridViewTextBoxColumn_20)|Out-Null
$System_Windows_Forms_DataGridViewTextBoxColumn_21 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$System_Windows_Forms_DataGridViewTextBoxColumn_21.AutoSizeMode = 16
$System_Windows_Forms_DataGridViewTextBoxColumn_21.HeaderText = "Loginname"  
$System_Windows_Forms_DataGridViewTextBoxColumn_21.Name = ""  
$System_Windows_Forms_DataGridViewTextBoxColumn_21.Width = 123

$dgv.Columns.Add($System_Windows_Forms_DataGridViewTextBoxColumn_21)|Out-Null
$dgv.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$dgv.Location = $System_Drawing_Point
$dgv.Name = "dgv"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 147
$System_Drawing_Size.Width = 411
$dgv.Size = $System_Drawing_Size
$dgv.TabIndex = 0

$form1.Controls.Add($dgv)

$columnHeader1.Text = "Vorname"  
$columnHeader1.Width = 108

$columnHeader2.Text = "Nachname"  
$columnHeader2.Width = 99

$columnHeader3.Text = "Loginname"  
$columnHeader3.Width = 112

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm
Member: derhoeppi
derhoeppi Oct 01, 2015 at 08:53:51 (UTC)
Goto Top
Hallo Uwe,

das DataGridView ist eine interessante Alternative zum ListView Element. Mein Problem dabei ist, dass ich das Frontend mit VisualStudio 2012 erstelle und das Ganze als xaml speichere. Die Datei lade ich dann in Powershell. VisualStdio 2012 bietet mir das DataGridView Element nicht als WPF Element an, so dass ich es nicht hinzufügen kann. Das Element als solches kann ich jedoch in der xaml Datei hinterlegen.
Folgendes Problem habe ich mit dem ListView:
$deinListView.Items.Add("Max").SubItems.AddRange(@("Muster","mmuster"))  
Wenn ich das Absetze steht in allen drei Spalten der ListView „Max“. Ich weiß nicht woran das liegt. In der xaml Datei wurde das Element folgendermaßen angelegt und wird über die PowerShell mit dem Namen angeprochen
<ListView x:Name="LV_User" HorizontalAlignment="Left" Height="195.723" Margin="10,10,0,0" VerticalAlignment="Top" Width="253.566" Grid.ColumnSpan="2">  
                        <ListView.View>
                            <GridView>
                                <GridViewColumn Header="Vorname"/>  
                                <GridViewColumn Header="Nachname"/>  
                                <GridViewColumn Header="Login"/>  
                            </GridView>
 </ListView.View>
Das DataGridView habe ich so in der xaml Datei eingepflegt:
<DataGrid x:Name="LV_User" HorizontalAlignment="Left" Height="195.723" Margin="10,10,0,0" VerticalAlignment="Top" Width="253.566" Grid.ColumnSpan="2" AutoGenerateColumns="False">  
                    <DataGrid.Columns>
                      <DataGridTextColumn Header="Vorname" Binding="{Binding Vorname}"  />  
                      <DataGridTextColumn Header="Nachname" Binding="{Binding Nachname}" />  
                      <DataGridTextColumn Header="Login" Binding="{Binding Login}" />  
                    </DataGrid.Columns>
                </DataGrid>
Ich kann nun die Daten aus separaten Textboxen in das DataGrid übernehmen. Mein Problem mit dem DataGrid ist, dass wenn ich mit einem Doppelklick auf einen Eintrag gehe – das Skript stirbt und nur über den TaskManager beendet werden kann. In der PowerShell Console erhalte ich die Meldung, dass das Editieren des Eintrags nicht erlaubt ist. Aus meiner Sicht ist das so gewollt, aber eben nicht, dass das Skript sich mit dieser Meldung aufhängt.
Wie könnte ich das Problem lösen?

Gruß
derhoeppi
Member: colinardo
colinardo Oct 01, 2015 updated at 11:57:50 (UTC)
Goto Top
WPF ist kein Windows Forms deswegen geht das obige von mir dort so nicht. Zu WPF und Powershell habe ich hier schon etwas gepostet:
WPF Oberflächen mit Powershell

Bei WPF gibt es nur das DataGrid und das ist kein DataGridView, das sollte nur über eine Datenquelle gesteuert werden. Manuell kommt es zu deinem beobachteten Crash.

Hier ein Beispiel:
Add-Type -AssemblyName Presentationframework
[string]$xaml = @"  
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Window" Title="Mein Fenster" WindowStartupLocation = "CenterScreen" ResizeMode="NoResize" SizeToContent = "WidthAndHeight" ShowInTaskbar = "True" Background = "lightgray">  
    <StackPanel>
        <DataGrid x:Name="LV_User" HorizontalAlignment="Left" Height="195.723" Margin="10,10,0,0" VerticalAlignment="Top" Width="253.566" Grid.ColumnSpan="2" AutoGenerateColumns="True">  
       </DataGrid>
    </StackPanel>
</Window>
"@  
# Markup laden 
$window=[Windows.Markup.XamlReader]::Parse($xaml)

# DataGrid
$dgv = $window.FindName('LV_User')  
# DataTable erstellen
$dt = new-Object System.Data.DataTable
[void]$dt.Columns.Add("Vorname")  
[void]$dt.Columns.Add("Nachname")  
[void]$dt.Columns.Add("Loginname")  

# Row zur DataTable hinzufügen
$dt.Rows.Add(@("Max","Muster","mmustermann"))  

# DataTable dem DataGrid als Quelle zuweisen
$dgv.ItemsSource = $dt.DefaultView


$async = $window.Dispatcher.InvokeAsync({$window.ShowDialog() | Out-Null})
$async.Wait() | Out-Null

Aber das ist ja nun ein ganz anderes Thema als der Ursprungsthreads. Bitte eine neue Frage dazu erstellen. Danke.

Grüße Uwe