Code/DevelopmentSkype und Lync

Umgang mit CSV Dateien mit Powershell

Inhalt

CSV Dateien zusammenbauen

Wenn Log-Daten in ein CSV geschrieben werden sollen, empfiehlt sich einen Zeitstempel in einem standard Format einzufügen. Die auszugebenden Zeilen können aus einzelnen Datenobjekten zusammengestellt oder zeilenweise manuell als String erstellt werden (die offensichtliche Variante). Bei der objektorientierten Herangehensweise kann eine Zeile sukzessive erweitert werden oder in einem Rutsch gebaut werden. Ebenso kann die CSV Datei gesamthaft geschrieben oder zeilenweise erweitert werden (Append, in früheren PS Versionen nicht vorhanden).
Die Ausschnitte zeigen beide Möglichkeiten.

$datefield = Get-Date -DisplayHint Date -Format yyyy-mm-dd-hh-mm
$imdata1 = "1"
$imdata2 = "0"
$resultsarray =@()
$resultline = new-object PSObject
$resultline |  add-member -membertype NoteProperty -name "Date" -Value $datefield
$resultline |  add-member -membertype NoteProperty -name "IM_DATA1" -Value $imdata1
$resultline |  add-member -membertype NoteProperty -name "IM_DATA2" -Value $imdata2
$resultsarray += $resultline 
$resultsarray| Export-Csv .\CSV-sample-log.csv -notypeinformation

Alternativ kann man eine Zeile als hashtable von Property Namen und Werten erstellen.

$newrow = New-Object PSObject -Property @{
Date    = $datefield
IM_DATA1 = $imdata1
IM_DATA2 = $imdata2
}
$newrow | Export-Csv .\powershell_2_csv.csv -Append –notypeinformation

Das Resultat:

"Date","IM_DATA1","IM_DATA2"
"2014-49-08-07-49","1","0"

Caveat: De Reihenfolge der Werte in der Ausgabe war in meinen Versuchen immer so wie im Code geschriebenen. Dies ist möglicherweise nicht garantiert und man müsste (ab PS 3) einen Cast zu [ordered] or [pscustomobject] machen:

$newrow += [pscustomobject] @{

 

CSV Dateien speichern

Das grundsätzliche Cmdlet zum Speichern in eine Datei ist Export-CSV. Im Gegensatz dazu gibt das Cmdlet ConvertTo-CSV das Resultat in einen String aus, der dann natürlich in eine Datei geleitet werden kann. ConvertTo-CSV dient aber eher dazu, Objekte und ihre Attribute (keine Methoden) zu Weiterverarbeitung als String bereitzustellen. Als Input wird ein PS Object erwartet, in den Beispielen unten wurde das Array $DataSet.Tables[0] von einer SQL DB Query gefüllt.

Beispiel: als UTF8 schrieben, Datentyp des PS Objects unterdrücken, ; als Trenner (-UseCulture nimmt den aktuellen länderspezifischen Wert)

$DataSet.Tables[0] | Export-CSV -Delimiter ";" $datafilename -encoding UTF8 -NoTypeInformation

Beispiel: mit Leerzeichen als Trenner, selektive Auswahl von Attributen

$DataSet.Tables[0] | Select-Object -Property Day,ReceivedCalls,SuccessfulCalls | Export-CSV $datafilename -Delimiter " " -encoding UTF8 –NoTypeInformation

Beispiel: entfernen von Hochkommata rund um jedem Datenwert

$DataSet.Tables[0] | ConvertTo-Csv -Delimiter ";" -NoTypeInformation | % {$_.Replace('"','')} | Out-File $datafilename

 

Fileshare verbinden mit verschlüsseltem Passwort

Vor dem Speichern in eine Datei müssen wir möglicherweise einen Fileshare verbinden. Damit man dabei nicht das Passwort im Klartext in das Script schreiben muss, kann man es als Secure String vorgängig abspeichern und bei Bedarf wieder einlesen. Der Secure String verschlüsselt dabei nicht nur das Passwort, sondern auch die SID des verschlüsselnden Users und die SID des Computers, worauf dieses Komnando ausgeführt wird. Somit ist sichergestellt, dass die Datei mit den gespeicherten Passwort auf keiner anderen Machine und von keinem anderen User benutzt werden kann.

Wir können das Passwort von der Konsole interaktiv einlesen und speichern:

read-host -AsSecureString | ConvertFrom-SecureString | Set-Content c:\powershell\pass.txt

oder initial aus einem Klartext-Passwort heraus erzeugen:

$secure_string_pwd = ConvertTo-Securestring "xxxxxx" -asplaintext -force
ConvertFrom-SecureString  $secure_string_pwd | Set-Content c:\powershell\pass.txt

Bei Gebrauch lesen wir es ein:

$password = Get-Content c:\powershell\pass.txt | ConvertTo-SecureString 
$credential = New-Object System.Management.Automation.PSCredential "DOMAIN\samaccountname",$password 
New-PSDrive -Persist -name P -Psprovider FileSystem -root \\server\share -credential $credential

 

CSV lesen

Das Einlesen einer CSV Datei geht komfortabel: man iteriert über alle Zeilen. Die einzelnen Felder stehen als Properties $_.propertyname zur Verfügung. Import-CSV kennt ähnliche Optionen wie Export-CSV. Praktisch ist, dass bereits beim Einlesen die Header geändert werden können (sodass die Properties anders heissen werden).

 

Import-Csv -path $inputFile -delimiter ',' |  % {   
 try {
       # read CSV columns und cast to string
       $myDate = [string]$_.Date
       $myIM1 = [string]$_.IMDATA1
       $myIM2 = [string]$_.IMDATA2
      }
 catch {
       $logmsg = "*** test catch error: $error[0]"
       } 
}

 

Spalten unformatieren und berechnen

In Powershell ist alles ein Objekt und nicht einfach nur ein String oder ein Array von Buchstaben, wie man es von anderen C-basierten Sprachen her kennt. Als Beispiel für den grossen Komfort, den uns Powershell bietet, hier ein Ausschnitt, wie Resultate aus einer SQL Query über Lync Response Groups weiterverarbeitet werden können. Vor der Ausgabe in eine CSV Datei werden hier neue Spalten eingefügt und deren Werte zeilenweise neu berechnet.

 

$DataSet.Tables[0].Columns.Add("Day") | Out-Null
            $DataSet.Tables[0].Columns.Add("ReceivedCalls") | Out-Null
            $DataSet.Tables[0].Columns.Add("SuccessfulCalls") | Out-Null
            $DataSet.Tables[0].Columns.Add("OfferedCalls") | Out-Null
            $DataSet.Tables[0].Columns.Add("AnsweredCalls") | Out-Null
            $DataSet.Tables[0].Columns.Add("TransferredCalls") | Out-Null
            ($DataSet.Tables[0]) | foreach {
                $_.ReceivedCalls    = $_.SOCCnt + $_.FOCCnt
                $_.SuccessfulCalls  = $_.SOCCnt + 0
                $_.OfferedCalls     = $_.SACCnt + $_.FACCnt
                $_.AnsweredCalls    = $_.SLCnt + 0
                if (-not $_.AnsweredCalls ) {  $_.AnsweredCalls = "9999"}
                $_.TransferredCalls = $_.STCCnt + $_.FTCCnt 
                # shorten date (samples column)         
                $_.Day = ([datetime]$_.Sample).tostring('dd.MM.yyyy')
            }

Die Ausgabe mit Filter haben wir schon angetroffen. Hier werden die neuen Spalten exportiert und die Spalten mit den nicht benutzten Rohdaten unterdrückt.

$DataSet.Tables[0] | Select-Object -Property Day,ReceivedCalls,SuccessfulCalls | Export-CSV $datafilename -Delimiter " " -encoding UTF8 –NoTypeInformation

  

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert