derhoeppi
Goto Top

PowerShell SSH Verbindung - Output exportieren

Hallo Leute,

ich möchte ein kleines Skript erstellen, dass mir Werte über eine SSH Verbindung ausliest. Um mit der PowerShell eine SSH Verbindung aufzubauen, benutze ich die SSH.Net Libary von CodeComplex. Damit schaffe ich es eine Verbindung zu meinem Target aufzubauen und das entsprechende Kommando abzusetzen. Nun möchte ich aber die Ausgabe des Kommandos in eine Variable schreiben, die ich anschließend als CSV ausgeben kann. Genau an diesem Punkt scheitere ich, weil er mir nicht den Variableninhalt in die CSV schreibt, sondern Tags wie TypeInformation und Lenght. Wie komme ich aber an den eigentlichen Inhalt?

Gruß
derhoeppi

Content-Key: 235138

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

Printed on: April 23, 2024 at 18:04 o'clock

Member: colinardo
colinardo Apr 10, 2014 updated at 09:34:15 (UTC)
Goto Top
Hallo derhoeppi,
damit du Werte vernünftig in eine CSV-Datei exportieren kannst sollte das was du exportieren willst ein PS-Objekt sein, und zusätzlich musst du im Export-CSV Befehl den Parameter -NoTypeInformation angeben. Du solltest also aus der Befehls-Ausgabe Objekte erstellen, an ein Array anhängen und dann das ganze an Export-csv übergeben. Alternativ schreibe das ganze via Out-File direkt in eine Datei wenn die Ursprungsausgabe schon das richtige CSV-Format hat.

Grüße Uwe
Member: derhoeppi
derhoeppi Apr 10, 2014 at 10:51:09 (UTC)
Goto Top
Hallo Uwe,

bisher habe ich folgende Zeilen erstellt:

$Array_return = @()
New-SshSession $SshUser $SshHost
Invoke-sshcommand -computername $SshHost -command 'lsvdisk'
$Response = New-Object PSObject
Add-Member -InputObject $Response -MemberType NoteProperty -Name "id" -Value $id
Add-Member -InputObject $Response -MemberType NoteProperty -Name "name" -Value $name
Add-Member -InputObject $Response -MemberType NoteProperty -Name "pool" -Value $pool
$Array_return += $Response
$Array_return | Export-CSV -path c:\temp\export.csv

Wenn ich dies ausführe, erhalte ich zwar in der Shell die entsprechende Ausgabe des Invoke-sshcommand's, aber in der CSV landet letztlich nur die Spaltenüberschrift, die ich via Add-Member vorgeben habe.

Gruß
derhoeppi
Member: colinardo
Solution colinardo Apr 10, 2014, updated at May 13, 2014 at 05:29:22 (UTC)
Goto Top
du musst ja Objekte mit entsprechendem Inhalt erzeugen ... du hast ja nur die Überschriften(Member) erstellt.
hier ein Beispiel (ich verwende hier die kompilierte DLL von SSH.Net) / Kommentare im Code
# Dll einbinden
Add-Type -Path "D:\Renci.SshNet.dll"  
$connInfo = new-Object Renci.SshNet.PasswordConnectionInfo("SSH-SERVER","Username","Password")  
$ssh = new-object Renci.SshNet.SshClient($connInfo)
# Verbinden
$ssh.connect()
# Command ausführen
$result = $ssh.RunCommand("lsvdisk")  
#Verbindung trennen
$ssh.Disconnect()

$Array_return = @()
# Ausgabe des Befehls anhand der Zeilenumbrüche splitten
$lines = $result.Result.Split("`n")  
# für jede Zeile in der Ausgabe
foreach($line in $lines){
        # splitte die Zeile als Beispiel anhand des Semikolons für die Spalten
        $cols = $line.Split(";")  
        # erstelle ein Objekt mit den Spalten und den Werten der jeweiligen Zeile und hänge es an das Array an
        $Array_return += New-Object PSObject -Property @{"id"=$cols;"name"=$cols[1];"pool"=$cols[2]}  
}
# Exportiere das Objekt als CSV
$Array_return |export-csv "C:\temp\testexport.csv" -NoTypeInformation  
Grüße Uwe
Member: derhoeppi
derhoeppi Apr 29, 2014 at 09:30:27 (UTC)
Goto Top
Hallo Uwe,

entschuldige bitte die urlaubsbedingte Reaktion auf deine Antwort. Ich versuche das ganze bei uns in der Umgebung anzupassen.
Die Renci.SshNet.dll habe ich bei mir in die Powershell über Import-Module geladen. Im Gegensatz zu meinen Versuchen arbeitet dein Skript super schnell, so dass man sich fragt, ob überhaupt etwas passiert ist.

Ich melde mich sobald es weitere Fragen gibt.

Gruß
derhoeppi
Member: derhoeppi
derhoeppi Apr 29, 2014 at 11:46:53 (UTC)
Goto Top
Hallo Uwe,

nun gibt es bereits die erste Frag an der ich scheitere. Du hast als Trennzeichen in einer Zeile das Semikolon ($cols = $line.Split(";")) definiert. In meiner Ausgabe ist es jedoch ein Leerzeichen, so dass der Befehl nach meinem Verständnis - so $cols = $line.Split(" ") oder so $cols = $line.Split() aussehen müsste.
Leider macht er das nicht, so dass ich jede eine Vielzahl von Kommazeichen angezeigt wird.

Gruß
derhoeppi
Member: colinardo
colinardo Apr 29, 2014 updated at 12:12:49 (UTC)
Goto Top
ich kann leider nicht hellsehen wie deine Original Beispielausgabe deine Befehls aussieht... poste mir doch bitte einen Auszug aus der Originalausgabe (aber bitte in Code-Tags). Merci.
Member: derhoeppi
derhoeppi Apr 30, 2014 at 09:44:17 (UTC)
Goto Top
Hallo Uwe,

natürlich kann ich die Ausgabe hier posten.

 id name                                     IO_group_id IO_group_name status mdisk_grp_id mdisk_grp_name      capacity type    FC_id FC_name RC_id RC_name vdisk_UID                        fc_map_count copy_count fast_write_state se_copy_count RC_change compressed_copy_count 
0  stg_a_2_lun200_infra                   0           io_grp0       online 0            atc-stg Pool1 2.00TB   striped 0     fcmap1                6005076802818FF69000000000000000 1            1          not_empty        1             no        0                     

Das ist genau die Ausgabe die mir Putty über eine SSH Verbindung liefert.

Gruß
derhoeppi
Member: colinardo
colinardo Apr 30, 2014 updated at 10:03:24 (UTC)
Goto Top
dann ist mir alles klar, da wird ja nicht nur "ein" Leerzeichen zwischen den Spalten genutzt sondern mehrere !!
Das ist ja ein heilloses Durcheinander ....
melde mich gleich nochmal ...
Member: colinardo
Solution colinardo Apr 30, 2014, updated at May 13, 2014 at 05:29:32 (UTC)
Goto Top
Hier musst du mit einem Regex die Spalten voneinander trennen:
$cols = $line.Trim() -split "\s+"
Grüße Uwe
Member: derhoeppi
derhoeppi May 07, 2014 at 12:29:50 (UTC)
Goto Top
Hallo Uwe,

ohne deine Hilfe wäre ich sicherlich schon untergegangen. Zwei Themen habe ich nun noch, bei denen ich einen Ansatz suche. Wir haben über
 $Array_return += New-Object PSObject -Property @{"id"=$cols;"name"=$cols[1];"pool"=$cols[2]}   
den Header der CSV Datei bestimmt. Nun gibt mein SSH Output selbigen mit, den ich aber nicht verhindern kann. Wenn ich -Property entferne, erhalte ich eine leere CSV. Wie kann ich die Situation lösen?
Punkt zwei, den ich eigentlich über den CSV-Export erledigen möchte ist in der Ausgabe eine Spalte zu durchsuchen. Dabei geht es um die Spalte ID, die in der Regel fortlaufend sein sollte. Ich möchte gerne die Spalte ID durchgehen und die nächste freie Zahl finden.

Wenn ich den Inhalt mit VOL.id extrahiere und daraus eine Addition mit +1 durchführen möchte, wird die 1 nur angehängt. Sprich habe ich ein Volume mit der ID 24 erhalte ich als Ergebnis 241.

Hast du dafür auch einen Tipp?

Gruß
derhoeppi
Member: colinardo
Solution colinardo May 07, 2014, updated at May 13, 2014 at 05:29:39 (UTC)
Goto Top
Hallo hoeppi,
auch kein Beinbruch face-wink in diesem Fall ändern wird die Schleife etwas ab (überspringen einfach die erste Zeile):
for ($i=1;$i -lt $lines.Count;$i++){
        $cols = $lines[$i].Trim() -split "\s+"  
        $Array_return += New-Object PSObject -Property @{"id"=$cols;"name"=$cols[1];"pool"=$cols[2]}  
}
Alternativ wenn du bei der alten Schleifenvariante bleiben willst, kannst du die erste Zeile einfach so nach der Schleife ausfiltern:
 $Array_return = $Array_return | select -Skip 1

Dann zur nächsten Frage: Um die nächste ID-Nummer aud dem Array zu ermitteln kannst du dies so machen:
$nextID = ($Array_Return.id | measure -Maximum).Maximum + 1
oder alternativ so
$nextID = [int]($Array_Return.id | sort -Descending | select -First 1) + 1
In der Variablen $nextID ist dann die nächste freie Nummer enthalten
Sprich habe ich ein Volume mit der ID 24 erhalte ich als Ergebnis 241
das kommt deswegen weil du zu einem String hinzuaddierst, und bei String bedeutet + einfach den String hinten anhängen. Um das zu verhindern musst du der Variablen zu der du addieren willst noch ein [int] voranstellen, so dass sie zu einem Integer umgewandelt wird.

Grüße Uwe
Falls der Beitrag gefällt, seid so nett und unterstützt mich durch eine kleine Spende / If you like my contribution please support me and donate
Member: derhoeppi
derhoeppi May 08, 2014 updated at 06:50:19 (UTC)
Goto Top
Hallo Uwe,

vielen Dank. Mit der nextID habe ich jedoch ein Problem. Er liest nicht die $Array_Return.id 's aus, so dass ich als Ergebnis immer nur einen Wert von 1 - also den Additionswert erhalte. Ich habe das ganze dann einmal mit einem eigenen Array ausprobiert. Sofern er Werte auslesen kann, funktioniert es. Was mich jedoch daran "stört" ist folgendes:

$a=1,5,6
$nextID = ($a | measure - Maximum).Maximum + 1 

Wenn ich das ausführe, erhalte ich immer 7 als Ergebnis der $nextID. Wenn $a die Werte mit 1-6 belegt hätte, wäre ich glücklich, aber die Kollegen löschen auch mal ein Volume und dann soll die nächste freie Volume ID gewählt werden. Als Ergebnis in diesem Bespiel hätte ich also den Wert 2 erwartet. Wenn in diesem Fall $a den Wert 1-6 hätte, sollte mir die 7 ausgegeben werden. Muss ich an dieser Stelle mit einem Inhaltsvergleich arbeiten oder gibt es einen eleganteren Weg? Als Werte für einen Inhaltsvergleich kann ich sowohl den Maximum-Wert nutzen als auch den Count des Arrays, wobei der Maximum-Wert größer sein könnte als der Count.

Gruß
derhoeppi
Member: colinardo
Solution colinardo May 08, 2014, updated at May 13, 2014 at 05:29:46 (UTC)
Goto Top
Zitat von @derhoeppi:

Hallo Uwe,

vielen Dank. Mit der nextID habe ich jedoch ein Problem. Er liest nicht die $Array_Return.id 's aus, so dass ich als Ergebnis immer nur einen Wert von 1 - also den Additionswert erhalte.
Dann machst du noch irgendetwas falsch, hier geht das einwandfrei...eventuell hast du eine ältere Powershell-Version als 3.0.

Wenn ich das ausführe, erhalte ich immer 7 als Ergebnis der $nextID. Wenn $a die Werte mit 1-6 belegt hätte, wäre
ich glücklich, aber die Kollegen löschen auch mal ein Volume und dann soll die nächste freie Volume ID gewählt
werden. Als Ergebnis in diesem Bespiel hätte ich also den Wert 2 erwartet. Wenn in diesem Fall $a den Wert 1-6 hätte,
sollte mir die 7 ausgegeben werden. Muss ich an dieser Stelle mit einem Inhaltsvergleich arbeiten oder gibt es einen eleganteren Weg?
Beispiel: (Ergebnis: 2)
$arr = @(1,5,3,4,6)
$ids = $arr | sort
for($i=0;$i -lt $ids.count;$i++){
    if ([int]$ids[$i] -ne [int]($ids[$i+1]-1)){
        $nextID = [int]$ids[$i] + 1
        break
    }
}
$nextID
Grüße Uwe
Member: derhoeppi
derhoeppi May 08, 2014 updated at 09:54:11 (UTC)
Goto Top
Hallo Uwe,

ich habe eben mal nach meiner PSVersion gesehen und nun Version 3 und 4 nachinstalliert. Bisher habe ich auf meinem Rechner nur Version 2 gehabt. Nun habe ich es noch einmal mit
 $nextID = ($Array_Return.id | measure -Maximum).Maximum + 1 
versucht. Leider erhalte ich nur id1 als Ergebnis. Wenn ich mir nur $Array_Return.id ausgeben lasse, sieht es so aus:
id 0 1 2 3 4 5

Gruß
derhoeppi

EDIT: Ich habe das Problem gefunden. Ich habe die foreach-Schleife nicht durch die for-Schleife ersetzt. Nachdem ich das getan habe, konnte ich
 $nextID = ($Array_Return.id | measure -Maximum).Maximum + 1 
fehlerfrei und korrekt ausführen. Bei der anderen Alternative mit dem vorausgehenden sortieren, erhalte ich falsche Werte zurück.
Member: derhoeppi
derhoeppi May 09, 2014 at 05:34:54 (UTC)
Goto Top
Hallo Uwe,

folgende Schleife liefert einen Fehler:

<Quote>
for($i=0;$i -lt $ids.count;$i++){
if ([int]$ids[$i] -ne [int]($ids[$i+1]-1)){
$nextID = [int]$ids[$i] + 1
break
}
}
</Quote>

Wenn in der Schleife :
<Quote>
for ($i=1;$i -lt $lines.Count;$i++){
$cols = $lines[$i].Trim() -split "\s+"
$Array_return += New-Object PSObject -Property @{"id"=$cols;"name"=$cols[1];"pool"=$cols[2]}
}
</Quote>

i=0 als Anfangswert gesetzt wird. Da ich jedoch im Array_Return einen Rückgabewert mit der ID=0 erhalte, muss ich entsprechend i anpassen. Mir ist dennoch nicht bewusst warum es zu der Fehlermeldung kommt. Als Meldung erhalte ich den Hinweis das er den Wert der id nicht nach int32 konvertieren kann, obwohl 0 ein Integer-Wert ist.

Gruß
derhoeppi
Member: colinardo
colinardo May 09, 2014 updated at 06:36:40 (UTC)
Goto Top
wenn du zwei Schleifen verschachtelst solltest du nie die Schleifenvariable $i doppelt verwenden, benutze also eine andere z.B. $z

mir fehlt jetzt inzwischen deine Logik bzw. dein bisheriger Code um hier noch weiter zu kommen, wenn bei mir das alles so geht wie es soll, sorry... face-sad
da liegt bei dir noch irgendeine "Variable" die ich mit meiner Glaskugel nicht sehen kann.