geretcondit
Goto Top

Server Festplatten Überwachung mit PowerShell

Hallo meine Lieben mit Administratoren,

heute habe ich ein etwas Komplexeres Problem. Ich versuche seit kurzem den Speicher Verbrauch unsere Server per PowerShell abzugreifen und dan in eine MS SQL Datenbanck zu schreiben.

Die Übertragung von PowerShell zu dem SQL Server an sich funktioneirt aber ich habe einen Großen Code Teil von http://www.sqlprofessionals.com und habe ein kleines problem mit der Umarbeitung.

 
$servers = get-content "C:\<pfad>\Server.txt"  

foreach ( $server in $servers){

[object]$Volumes = Get-WmiObject -NameSpace  "root/cimv2"  -ComputerName $servers Win32_Volume -Filter "DriveType = 3" ;  
[string]$XmlData = "<root><cimv2>";   

$Volumes | % { $XmlData = $XmlData + "<Win32_Volume Name=`"" + $server +  "`" DriveLetter=`"" + $_.DriveLetter  + "`" Capacity=`"" + $_.Capacity + "`" FreeSpace=`"" + $_.FreeSpace + "`"></Win32_Volume>" };   
$XmlData = $XmlData + "</cimv2></root>";  

$SqlConnection = New-Object System.Data.SqlClient.SqlConnection;
$SqlConnection.ConnectionString = "Data Source=<DB>;Initial Catalog=Speicherauslastung;Integrated Security=True;";   
$SqlConnection.Open();
$SqlCommand = New-Object System.Data.SqlClient.SqlCommand;
$SqlCommand.CommandTimeout = 120;
$SqlCommand.Connection = $SqlConnection;
$SqlCommand.CommandText = "EXECUTE [dbo].[InsertDiskVolume] @XmlData = N'$XmlData';";  
$Result = $SqlCommand.ExecuteNonQuery();
$SqlConnection.Close();

}

An sich funktioniert das auch alles recht gut, wenn nicht sogar zu gut. Alle Festplatten werden ausgelessen und auch in den SQL Server geschrieben, aber ich würde mir etwas aus der Rubrik für die Übertragung wünschen:
5d9c2fda57b837aa93d5d8c154a91f8a
(Rein vom Output nicht von der Formatirung)

Was ich aber Bekomme ist das (und das ist nur ein Ausschnitt):
c0a9e9f3ae4f03327a44707f6fa54641
die Richtige platte ist zwar dabei aber halt auch viele andere. Zusätzlich doppeln sich die Laufwerk buchstaben.
Wenn es jetzt also nur noch die Richtigen Platten angezeigt werden würden währe alles perfekt.

Ich habe ja die vermututng das es mit dem CIMV2 zusammenhängt aber ich weiß nicht wie ich es richtig raus bekommen soll.


Ich würde mich über jede hilfe freuen da ich langsam alles was mir ein fiel versucht habe. Vielen Dank im Vorraus.

Mit Freundlichen Grüßen
GeretCondit

Content-ID: 284141

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

Ausgedruckt am: 24.11.2024 um 05:11 Uhr

122990
122990 29.09.2015 aktualisiert um 17:53:22 Uhr
Goto Top
Moin GeretCondit,
aber ich würde mir etwas aus der Rubrik für die Übertragung wünschen:
Und was genau ??
Wenn es jetzt also nur noch die Richtigen Platten angezeigt werden würden währe alles perfekt.
Und welche sind bei dir die "richtigen" Platten ?
Ich würde mich über jede hilfe freuen da ich langsam alles was mir ein fiel versucht habe.
Und wir uns über Konkretisierung deiner gewünschten Ausgabe face-smile

Gruß grexit
GeretCondit
GeretCondit 29.09.2015 um 21:29:54 Uhr
Goto Top
Hallo Grexit,

ich hatte gehofft der Screenshot würde ganz gut verdeutlichen was ich meine.

Alle deine Fragen mal schnell zusammengefasst.


Das Hauptproblem ist das er obwohl dieser Beispiel Server nur 2 Festplatten hat nämlich C und D, im SQL Server landen aber übern Daumen 5 C,4 D und 20 ganz ohne Bezeichnung.

Das ist nicht ganz wie es laufen sollte sagen wir mal freuen würde ich mich über 2 Festplatten bzw. über die Selben Festplatten die man auch im Arbeitsplatz finden würde .

Ich habe auch vorher schon Festplatten mit PowerShell ausgelesen aber es ist das erste mal das ich versuche es mit MS SQL zu kombinieren.


MFG
GeretCondit
TlBERlUS
TlBERlUS 30.09.2015 aktualisiert um 16:31:37 Uhr
Goto Top
Guten Morgen,

was gibt eine Ausgabe mit diesem Code?

Get-WmiObject win32_volume -computername vm-pc | Select-Object Name, Capacity, freespace | where Name -like "*:\" | where freespace -gt 0.5 | fl  

Ich würde deine Abfrage genauer spezifiezieren(siehe oben). Dann hast du im Zweifel weniger Fehlerquellen.

Falls es ein virtueller Server(VMWare) ist, ich könnte die einpowerCli-Skript zur Verfügung stellen.
GeretCondit
GeretCondit 30.09.2015 aktualisiert um 15:12:46 Uhr
Goto Top
Hallo TIBERIUS,

es geht bei den Servern um VM´s und Reale Server und der Verwendete Beispiel Server: Server-Storage ist ein Realer Server.

Die ausgebae deines Scriptes(mit geändertem PC namen):

Name Capacity freespace
-------- ---------
D:\ 7020982824960 3693985251328
C:\ 1978749939712 1925382512640

Das klapt an sich ohne fehler.

Vorher als ich es noch nicht auf den SQL Übertragen wollte habe ich volgendes benutzt und das hat immer gut geklapt:
 Get-WmiObject -Class Win32_LogicalDisk -Computername $Server[$i] -Filter "DriveType=3" | Format-Table @{Label="Drive"; Expression={$_.DeviceID}; width=8}, @{Label="Size"; Expression={$_.Size / $SFaktor}; Format="000.000"; width=8}, @{Label="GB Free" ; Expression={$_.FreeSpace/ $SFaktor} ; Format="000.000" ; width=8} , @{Label="% Free" ; Expression={$_.FreeSpace * 100 /$_.Size}; Format="00.000" ; width=10} -ErrorAction Continue  


Dabei war die Formatierung aber nicht mehr MS SQL Kompatibel daher habe ich neu angefangen.
TlBERlUS
TlBERlUS 30.09.2015 um 16:31:24 Uhr
Goto Top
setz nochmal ein
| fl

hinter das skript
GeretCondit
GeretCondit 30.09.2015 um 16:55:02 Uhr
Goto Top
Ich glaube das währe kontraproduktiv. Ich bekomme ja eh schon mehr daten als ich möchte ;)
TlBERlUS
TlBERlUS 30.09.2015 um 20:21:20 Uhr
Goto Top
Damit solltest du (wenn auch unformatiert), die daten bekommen, die du haben willst (bis auf den %-Wert)
GeretCondit
GeretCondit 01.10.2015 um 11:53:54 Uhr
Goto Top
An sich bekomme ich ja die Richtigen werte. Ich bekomme nur zu viele davon sagen wir mal.

Ich bekomme ja zu den Gesuchten Festplatten alle werte die ich möche aber ich bekomme einfach viel zu viele Festplatten agnezeigt die es eigentlich nicht geben sollte.

Ich bekomme ja einfach 5 mal C:\ angezeigt nur als ein beispiell.
TlBERlUS
TlBERlUS 01.10.2015 aktualisiert um 12:32:25 Uhr
Goto Top
 
> $servers = get-content "C:\<pfad>\Server.txt"  
> 
> foreach ( $server in $servers){
> > [object]$Volumes = Get-WmiObject -NameSpace  "root/cimv2"  -ComputerName $servers Win32_Volume -Filter "DriveType = 3" ;  
> [string]$XmlData = "<root><cimv2>";   
> 
> $Volumes | % { $XmlData = $XmlData + "<Win32_Volume Name=`"" + $server +  "`" DriveLetter=`"" + $_.DriveLetter  + "`" Capacity=`"" + $_.Capacity + "`" FreeSpace=`"" + $_.FreeSpace + "`"></Win32_Volume>" };   

Ist es gewollt, dass du in deiner Foreach-Schleife noch ein foreach hast?

$Volumes | % {
GeretCondit
GeretCondit 01.10.2015 aktualisiert um 13:18:05 Uhr
Goto Top
Also rein vom sinn ist das da um das Object und den String vernünftig zu verknüpfen.
GeretCondit
GeretCondit 01.10.2015 aktualisiert um 14:07:58 Uhr
Goto Top
Ich verstehe jetzt galube ich was du meinst.
Ich habe mir gerade nochmal meine Asugabe angesehen und festgestelt das zwar wirklich alle Server ausgelesen werden aber auch das alle Server die Festplatten von jedem anderen ausgelesenen server bekommen.

Allerdings sind dan immer noch ein Paar platten dabei die es nicht geben sollte.
TlBERlUS
TlBERlUS 01.10.2015 aktualisiert um 14:33:35 Uhr
Goto Top
Das ist der Auszug aus einem meiner Skripte:
 
clear-host
$server = ListeanServern
Get-WmiObject win32_logicaldisk -ComputerName $Server | where{$_.DriveType -eq 3} |select `
    @{Expression={$_.PSComputername};Label="System"}, `  
    @{Expression={$_.DeviceID};Label="Partition"}, `  
    @{Expression={[decimal]("{0:N0}" -f($_.Size/1gb))};Label="Max.(GB)"},`  
    @{Expression={[decimal]("{0:N0}" -f($_.Freespace/1GB))};Label="Frei(GB)"}, `  
    @{Expression={if((($_.freespace/1gb)/($_.size/1gb))*100-gt 10) {"{0:P0}" -f(($_.freespace/1gb)/($_.size/1gb))}else{"{0:P0}" -f(($_.freespace/1gb)/($_.size/1gb))}};Name="Frei(%)"}, `  
    @{Expression={if((($_.freespace/1gb)/($_.size/1gb))*100-gt 10) {"OK"}else{"Warnung"}};Name="Status"}  

Das müsste eig. deine Anforderung komplett erfüllen.

Wenn du willst, kann ich dir den Rest auch geben (HTMl/css-Formatierung + Mail-Versand)
GeretCondit
GeretCondit 01.10.2015 um 17:01:40 Uhr
Goto Top
Danke das ist sehr nett, aber das wird mir leider nicht viel helfen da ich mir die Formatirung schon speziel so gedacht habe damit der MS SQL Server das interpretieren kann. Ich habe auch schon einen HTML Bericht per Mail ;)

Aber ich denke ich habe das Problem eingegrentzt
foreach ( $server in $servers){

[object]$Volumes = Get-WmiObject -NameSpace  "root/cimv2"  -ComputerName $servers Win32_Volume -Filter "DriveType=3" | where {$_.DriveLetter -like "D*" -or $_.DriveLetter -like "C*" -or $_.DriveLetter -like "E*" }  
[string]$XmlData = "<root><cimv2>";   

$Volumes | % { <#$XmlData = $XmlData + #> "<Win32_Volume Name=`"" + $server +  "`" DriveLetter=`"" + $_.DriveLetter  + "`" Capacity=`"" + $_.Capacity/1GB + "`" FreeSpace=`"" + $_.FreeSpace/1GB + "`"></Win32_Volume>" };  
$XmlData = $XmlData + "</cimv2></root>";  
}


Den nachdem du das mit den Mehreren "foreach" ewähnt hast habe ich nochmal etwas rumprobiert und habe es zum einen geshcaft das nur noch die richtigen Platten angezeigt werden aber habe nun das Problem das Jeder Server mit jeder Festplatte angezeigt wird. Und ich bin gerade leider nicht mehr in der lage meinen code zu verstehen (Tunnelblick). Ich währe danckbar wenn man mir hier mit der Schleife einmal auf die Spünge helfen könnte.

//XmlData ist bewusst auskommentiert damit es nicht an den SQL Server gesendet wird sondern in der Konsole angezeigt wird.
GeretCondit
GeretCondit 01.10.2015 um 17:47:10 Uhr
Goto Top
Zitat von @GeretCondit:

Den nachdem du das mit den Mehreren "foreach" ewähnt hast habe ich nochmal etwas rumprobiert und habe es zum einen geshcaft das nur noch die richtigen Platten angezeigt werden aber habe nun das Problem das Jeder Server mit jeder Festplatte angezeigt wird. Und ich bin gerade leider nicht mehr in der lage meinen code zu verstehen (Tunnelblick). Ich währe danckbar wenn man mir hier mit der Schleife einmal auf die Spünge helfen könnte.

Zur erklärung was ich mit "Jeder Server mit jeder Festplatte" meine. Die einträge werden für jden Server abgefahren aber jeder Server zeigt auch die Platten der anderen server + seine eigenen an.
122990
Lösung 122990 01.10.2015, aktualisiert am 30.11.2015 um 02:07:34 Uhr
Goto Top
Zitat von @GeretCondit:
Zur erklärung was ich mit "Jeder Server mit jeder Festplatte" meine. Die einträge werden für jden Server abgefahren aber jeder Server zeigt auch die Platten der anderen server + seine eigenen an.
Kein Wunder .... Schau dir mal die Variable für Computername an face-wink
Get-WmiObject -NameSpace "root/cimv2" -ComputerName $servers
TlBERlUS
Lösung TlBERlUS 02.10.2015, aktualisiert am 30.11.2015 um 02:07:30 Uhr
Goto Top
Zitat von @122990:

Get-WmiObject -NameSpace "root/cimv2" -ComputerName $servers

Tatsache, das hab ich auch übersehen.
Aber immerhin fühle ich mich noch mehr darin bestätigt
foreach($s in $servers)

zu verwenden, anstatt ein komplettes Wort. Dann kommt es zu weniger Verwechselungen face-smile
GeretCondit
GeretCondit 30.11.2015 um 02:07:16 Uhr
Goto Top
So etwas verspätet aber besser spät als nie, das Problem wurde schon vor einiger zeit dank eurer Hilfe gelöst aber hier nochmal für alle interessierten der Komplette Code in funktionsfähiger Form.

$server = get-content "C:\Users\...\Server.txt"  

foreach ( $s in $server){

[object]$Volumes = Get-WmiObject -NameSpace  "root/cimv2"  -ComputerName $s Win32_Volume -Filter "DriveType=3" | where {$_.DriveLetter -like "D*" -or $_.DriveLetter -like "C*" -or $_.DriveLetter -like "E*" };  
[string]$XmlData = "<root><cimv2>";   

$Volumes | % { $XmlData = $XmlData + "<Win32_Volume Name=`"" + $s +  "`" DriveLetter=`"" + $_.DriveLetter  + "`" Capacity=`"" + $_.Capacity/1GB + "`" FreeSpace=`"" + $_.FreeSpace/1GB + "`"></Win32_Volume>" };   
$XmlData = $XmlData + "</cimv2></root>";  



$SqlConnection = New-Object System.Data.SqlClient.SqlConnection;
$SqlConnection.ConnectionString = "Data Source=PC-FC;Initial Catalog=Speicherauslastung;Integrated Security=True;";   
$SqlConnection.Open();
$SqlCommand = New-Object System.Data.SqlClient.SqlCommand;
$SqlCommand.CommandTimeout = 120;
$SqlCommand.Connection = $SqlConnection;
$SqlCommand.CommandText = "EXECUTE [dbo].[InsertDiskVolume] @XmlData = N'$xmldata';";  
$Result = $SqlCommand.ExecuteNonQuery();
$SqlConnection.Close();

}


Das hat so bei mir sehr gut geklappt und nochmal danke an alle.