Zum Inhalt wechseln


Foto

PS 4.0 Arrayfehler = wie kann ich den abfangen?


  • Bitte melde dich an um zu Antworten
11 Antworten in diesem Thema

#1 Pikus1234

Pikus1234

    Newbie

  • 19 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:20

Hallo,

 

Ich bin gerade dabei eine umfangreiche Inventory für Hardwareabfragen zu basteln. 

 

Jetzt komme ich leider nicht weiter und hoffe auf eure Hilfe.

 

Im Script wird durch eine WMI-Abfrage eben ein Monitor-Array von bis zu 4 Monitoren abgefragt und erstellt.

Das läuft auch, sofern der WMI der Remotemaschine läuft und Daten liefert

 

Aber wenn der WMI nicht läuft und keine Daten liefert, bekomme ich entsprechende Fehlermeldungen, welche ich nun abfangen bzw. durch Ersatz auffüllen muss. Wer kann da helfen....

Weitere Fehler sind natürlich durch den nicht erfolgten Zugriff auf die WMI möglich.....viell. habe ich auch einen Denkfehler beim Aufbau drin.

Ich bin noch nicht so fit in Powershell, weshalb ich eure Hilfe benötige.

$testcomputers = '#Name des Remote-PC'
# normal wird hier eine bestimmte txt.Datei eingelesen, welche mir die Namen liefert
foreach ($computer in $testcomputers) {
  if (Test-Connection -ComputerName $computer -Quiet -count 1){
    Add-Content -value $computer -Force "$PSScriptRoot\livePCs.txt" 
  }else{
    Add-Content -value $computer -Force "$PSScriptRoot\deadPCs.txt" 
  }
}
$computers = #die PC-Namen aus der Liste "livePCs.txt" oder '#Name des Remote-PC'
$Inventory = foreach ($computer in $computers) {
        $Bios = Get-WmiObject win32_bios -Computername $computer
        $Hardware = Get-WmiObject Win32_computerSystem -Computername $computer
        $Sysbuild = Get-WmiObject Win32_WmiSetting -Computername $computer
        $OS = Get-WmiObject Win32_OperatingSystem -Computername $computer
        $GUID = Get-wmiobject Win32_ComputerSystemProduct -Computername $computer | Select-Object -ExpandProperty UUID 
        $Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.IPEnabled}
        $driveSpace = Get-WmiObject win32_volume -Computername $Computer -Filter 'drivetype    = 3' |
            Select-Object PScomputerName, driveletter, label, @{LABEL='GBfreespace';EXPRESSION={'{0:N2}' -f($_.freespace/1GB)} } |
                Where-Object { $_.driveletter -match 'C:' }
        $cpu = Get-WmiObject Win32_Processor  -Computername $computer
        $CDROM = Get-WmiObject win32_CDROMDrive -ComputerName $computer
        $Video = Get-WmiObject Win32_Videocontroller -ComputerName $computer -Filter "NOT name LIKE '%DameWare%'" |Select-Object 'Name*'
        $username = Get-ChildItem "\\$computer\c$\Users" | Sort-Object LastWriteTime -Descending | Select-Object Name, LastWriteTime -first 1
#hier muss der Fehler abgefangen werden, dass es bei scheitern keine Daten gibt - es muss ersatzdaten geben::::::: [ARRAY]$MonitorList = $null $ MonitorList = $ null
        [ARRAY]$MonitorList = Get-WmiObject -Class WmiMonitorID -Namespace root\wmi -ComputerName $computer
        $PrinterHP      = Get-WmiObject -Class Win32_Printer -ComputerName $Computer |Where-Object { $_.Local -like 'True' -and $_.Name -like 'HP*'}| Select-Object Name
        $PrinterSamsung = Get-WmiObject -Class Win32_Printer -ComputerName $Computer |Where-Object { $_.Local -like 'True' -and $_.Name -like 'Samsung*'}| Select-Object Name
        $PrinterCanon   = Get-WmiObject -Class Win32_Printer -ComputerName $Computer |Where-Object { $_.Local -like 'True' -and $_.Name -like 'Canon*'}| Select-Object Name

        [PSCustomObject]@{
            ComputerName           = $Computer.ToUpper()
            Manufacturer           = $Hardware.Manufacturer
            Model                  = $Hardware.Model
            Serial_Number          = $Bios.serialnumber
            MAC_Address            = $Networks.MACAddress
            Netboot_GUID           = $GUID
            IP_Address             = $Networks.IpAddress[0]
            Processor_Type         = $cpu.Name
            System_Type            = $Hardware.SystemType
            Total_Memory_GB        = [math]::round($Hardware.TotalPhysicalMemory/1024/1024/1024, 2)
            CDROM_Drive            = $CDROM.Caption
            Graphics               = $Video.Name
            Last_User              = $username.Name
            User_Last_Login        = $username.LastWriteTime
            'C:_FreeSpace_GB'      = $driveSpace.GBfreespace
            Last_ReBoot            = $OS.ConvertToDateTime($OS.LastBootUpTime)
            Operating_System       = $OS.Caption
            Operating_System_Version = $OS.version
            Operating_System_BuildVersion = $SysBuild.BuildVersion
            Monitor1Hersteller     = If($MonitorList[0]){($MonitorList[0].ManufacturerName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor1Typ            = If($MonitorList[0]){($MonitorList[0].UserFriendlyName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor1Seriennummer   = If($MonitorList[0]){($MonitorList[0].SerialNumberID -notmatch '^0$'   | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor2Hersteller     = If($MonitorList[1]){($MonitorList[1].ManufacturerName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor2Typ            = If($MonitorList[1]){($MonitorList[1].UserFriendlyName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor2Seriennummer   = If($MonitorList[1]){($MonitorList[1].SerialNumberID -notmatch '^0$'   | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor3Hersteller     = If($MonitorList[2]){($MonitorList[2].ManufacturerName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor3Typ            = If($MonitorList[2]){($MonitorList[2].UserFriendlyName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Monitor3Seriennummer   = If($MonitorList[2]){($MonitorList[2].SerialNumberID -notmatch '^0$'   | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
            Drucker_HP             = $PrinterHP.Name
            Drucker_Samsung        = $PrinterSamsung.Name
            Drucker_Canon          = $PrinterCanon.Name
        }  ### End PSCustomObject
       
} ### End Foreach Computer

$Inventory

#Wie erwähnt wird nun beim [ARRAY]$MonitorList = Get-WmiObject -Class WmiMonitorID #-Namespace root\wmi -ComputerName $computer  ein Fehler gezeigt.

#Get-WmiObject : Nicht unterstützt 
#At C:\Test\fehlerabfangen.ps1:25 char:31
#+ ... nitorList = Get-WmiObject -Class WmiMonitorID -Namespace root\wmi -Co ...
#+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException
#    + FullyQualifiedErrorId : #GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
# 
#Cannot index into a null array.
#At C:\Test\fehlerabfangen.ps1:50 char:41
#+             Monitor1Hersteller     = If($MonitorList[0]){($MonitorLis ...
#+                                         ~~~~~~~~~~~~~~~
#    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
#    + FullyQualifiedErrorId : NullArray 

Unterste Zeilen im Code stellen die Fehlermeldung im Script dar.

 

Danke für eure Unterstützung

 

:thumb1:  :)  Pikus



#2 Dukel

Dukel

    Board Veteran

  • 9.298 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:24

Wieso zwei Foreach Schleifen, die das selbe machen?

 

foreach($computer in $testcomputer){

   if(test-connection){

      # Nicht in eine Datei schreiben sondern weiteremachen!

      get-wmiobject ...

   }

}

 

Zum Problem:

Fehler abfangen kannst du mit try / Catch oder einfach mit if.


Stop making stupid people famous.


#3 zahni

zahni

    Expert Member

  • 16.472 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:24

Schau mal hier: 

 

https://kevinmarquet...wanted-to-know/


  • Pikus1234 gefällt das

Wen du nicht mit Können beeindrucken kannst, den verwirre mit Schwachsinn!


#4 tesso

tesso

    Board Veteran

  • 2.252 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:25

Schau dir mal das Konstrukt "try" "catch" an. Das dürfte in deinem Fall helfen.



#5 Pikus1234

Pikus1234

    Newbie

  • 19 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:31

Erst mal danke für die Antwort, welche ja blitzschnell kam :p .

 

Nun Ich habe die Dateien extra ausgegeben, damit ich die nicht erreichten PC´s und Online-PC trennen kann. diese PC´s können dann gesondert betrachtet, eingeschaltet und später abgefragt werden, ohne dass ich alle wiederholen müsste.

 

Die Abfragemenge variiert schon stark je nach Anforderung. :)

 

Und zum Fehler selbst lese ich mich natürlich ein. Über ein Beispiel in diesem speziellen Fall würde ich mich freuen, da ich sonst alle Hilfethemen sehr abstrakt finde und oftmals Verständnisprobleme dabei habe.

 

Danke :jau:



#6 Cybquest

Cybquest

    Expert Member

  • 1.886 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:34

Statt Fehler abfangen evtl. einfach dieses If($MonitorList[0] ersetzen durch sowas:

ForEach ($Monitor in $MonitorList) { ...


My name is Frank, you can say you to me.

#7 Dukel

Dukel

    Board Veteran

  • 9.298 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:34

das kannst du ja trotzdem machen:

 

foreach($computer in $testcomputer){

   if(test-connection){

      #In Datei schreiben und weiter machen

      $computer | add-content ...

      get-wmiobject ...

   }else{

      $computer | add-content ...

   }

}

 

Angenommen du hast 5000 Computer. Er pingt alle 5000 Computer und schreibt diese in eine Datei und liesst dann erst die Infos aus, dann sind sicher die ersten PC's schon wieder aus. Und das Auslesen braucht auch eine gewisse Zeit.


  • Pikus1234 gefällt das

Stop making stupid people famous.


#8 Pikus1234

Pikus1234

    Newbie

  • 19 Beiträge

 

Geschrieben 11. Oktober 2017 - 13:38

Danke für diese Seite, welche sehr aufschlussreich ist. Ich probiere mich aus. Super :thumb1:


das kannst du ja trotzdem machen:

 

foreach($computer in $testcomputer){

   if(test-connection){

      #In Datei schreiben und weiter machen

      $computer | add-content ...

      get-wmiobject ...

   }else{

      $computer | add-content ...

   }

}

 

Angenommen du hast 5000 Computer. Er pingt alle 5000 Computer und schreibt diese in eine Datei und liesst dann erst die Infos aus, dann sind sicher die ersten PC's schon wieder aus. Und das Auslesen braucht auch eine gewisse Zeit.

jetzt wo du es mir so erklärst klingt es doch schlüssig. Ich werde deinen Ansatz mal versuchen umzusetzen. Danke für den Tipp..... :thumb1:  Ich lasse dich wissen ob ich es auch hinbekommen habe..... :D



#9 Pikus1234

Pikus1234

    Newbie

  • 19 Beiträge

 

Geschrieben 18. Oktober 2017 - 07:17

das kannst du ja trotzdem machen:

 

foreach($computer in $testcomputer){

   if(test-connection){

      #In Datei schreiben und weiter machen

      $computer | add-content ...

      get-wmiobject ...

   }else{

      $computer | add-content ...

   }

}

 

Angenommen du hast 5000 Computer. Er pingt alle 5000 Computer und schreibt diese in eine Datei und liesst dann erst die Infos aus, dann sind sicher die ersten PC's schon wieder aus. Und das Auslesen braucht auch eine gewisse Zeit.

Also ich stelle mich bei deiner Idee zu b***d an, da fehlt mir doch noch einiges Wissen offensichtlich. Ich erhalte nachfolgende Fehlermeldung.:

 

Add-Content : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and

its properties do not match any of the parameters that take pipeline input.

 

Ich hab es wie folgt versucht umzusetzen (streng an deinen Vorschlag)

foreach ($computer in $testcomputers) {
  if (Test-Connection -ComputerName $computer -Quiet -count 1){
#hier liegt der Fehler weil das $computer ja wohl offensichtlich hier nicht verwendet werden kann.
      $computer| Add-Content -Value $computer "$PSScriptRoot\livePCs.txt"
        $Inventory = foreach ($computer in $computers) {
            $Bios = Get-WmiObject win32_bios -Computername $Computer}

Wie gesagt das Ziel ist das Speichern der Live-PC in eine Datei um anschließend die Inventur mit diesen PC´s durchzuführen. Aber Wie?

 

 

 

 



#10 Dukel

Dukel

    Board Veteran

  • 9.298 Beiträge

 

Geschrieben 18. Oktober 2017 - 07:24

$computer| Add-Content -Value $computer "$PSScriptRoot\livePCs.txt"

 

Der Inhalt ist doppelt. Entweder vor die Pipe oder als Parameter.

 

Add-Content -Value $computer "$PSScriptRoot\livePCs.txt"

Oder

$computer| Add-Content "$PSScriptRoot\livePCs.txt"


Stop making stupid people famous.


#11 Pikus1234

Pikus1234

    Newbie

  • 19 Beiträge

 

Geschrieben 19. Oktober 2017 - 09:35

$computer| Add-Content -Value $computer "$PSScriptRoot\livePCs.txt"

 

Der Inhalt ist doppelt. Entweder vor die Pipe oder als Parameter.

 

Add-Content -Value $computer "$PSScriptRoot\livePCs.txt"

Oder

$computer| Add-Content "$PSScriptRoot\livePCs.txt"

Leider klappt dieser Schritt nicht zufriedenstellend. Add-Content -Value....klappt aber die Ausgabe ist nicht wie gewünscht. PS scheint also alle PC entsprechend zu verarbeiten, als nur die Online-PC. Oder die Zuordnung bei der Dateispeicherung klemmt. Kurz gesagt....

Ich lasse also lieber doch die Schleifen und lese die PC wieder ein. Denn ehrlich gesagt dauert dieser Schritt gar nicht so lange.

 

Schlimmer wird es ja in der Abfrageschleife $Inventory....

Hier habe ich, auch mit Hilfe von Euch ein Monitor-Array erstellt, um die bis zu 4 angeschlossene Monitore per WMI auslesen zu können.

Das Problem ist jetzt:

Wenn der PC einen WMI-Fehler aufweist und die Abfrage nicht klappt, muss ich diesen Fehler abfangen. Ihr hattet hier den Tipp gegeben es mit Try und Catch zu tun. Ich habe mich mal ausprobiert und versucht den Fehler in nachfolgender Form abzufangen....

Ideenratgeber war dazu:

https://kevinmarquet...-know/#trycatch

try {[ARRAY]$MonitorList = Get-WmiObject -Class WMIMonitorID -Namespace root\wmi -ComputerName $computer} catch {Write-Output $computer "kein Monitor erkannt"}

Aber natürlich klappt das nur bedingt.....Das Script läuft zwar weiter durch (arbeitet alle PC ab)

Aber wie kann ich jetzt noch dem "catch" mitteilen, dass ich dennoch zur CSV-Ausgabe eine Zeile mit dem PC-Namen erhalten will? Die anderen PC erzeugen ja entsprechende Ausgaben, welche anschließend in eine CSV-Datei gespeichert werden?!

Nur 1 PC  erzeugt also Fehler bei der WMI-Abfrage und in der Folge bei der Monitorarrayerstellung und erzeugt keine Zeile im CSV. Der PC fehlt mir in der CSV schlichtweg. Dennoch will ich auch diesen PC erfasst wissen.  

Mir würde also der Eintrag reichen :

PCName ($Computer);  "keine WMI-Abfrage möglich" oder ähnliches?

 

Mhhh....Ich weiß = viele Fragen aber ich hoffe auf eure Hilfe hier und darf mich für die vielen schnellen Antworten bisher bedanken..... :thumb1:  :)  

 

Hier nochmal die ganze Inventory-Abfrage und die erzeugten Fehlermeldung des 1. PC aus dieser Abfrage:

$Inventory = foreach ($computer in $computers) {
12.        $Bios = Get-WmiObject win32_bios -Computername $computer
13.        $Hardware = Get-WmiObject Win32_computerSystem -Computername $computer
14.        $Sysbuild = Get-WmiObject Win32_WmiSetting -Computername $computer
15.        $OS = Get-WmiObject Win32_OperatingSystem -Computername $computer
16.        $GUID = Get-wmiobject Win32_ComputerSystemProduct -Computername $computer | Select-Object -ExpandProperty UUID 
17.        $Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.IPEnabled}
18.        $driveSpace = Get-WmiObject win32_volume -Computername $Computer -Filter 'drivetype    = 3' |
19.            Select-Object PScomputerName, driveletter, label, @{LABEL='GBfreespace';EXPRESSION={'{0:N2}' -f($_.freespace/1GB)} } |
20.                Where-Object { $_.driveletter -match 'C:' }
21.        $cpu = Get-WmiObject Win32_Processor  -Computername $computer
22.        $CDROM = Get-WmiObject win32_CDROMDrive -ComputerName $computer
23.        $Video = Get-WmiObject Win32_Videocontroller -ComputerName $computer -Filter "NOT name LIKE '%DameWare%'" |Select-Object 'Name*'
24.        $username = Get-ChildItem "\\$computer\c$\Users" | Sort-Object LastWriteTime -Descending | Select-Object Name, LastWriteTime -first 1
25.#Fehler abfangen mit try und catch?!
26.    try{[ARRAY]$MonitorList = Get-WmiObject -Class WmiMonitorID -Namespace root\wmi -ComputerName $Computer}catch{write-Output $Computer "keine WMI-Abfrage möglich"}
27.        $PrinterHP      = Get-WmiObject -Class Win32_Printer -ComputerName $Computer |Where-Object { $_.Local -like 'True' -and $_.Name -like 'HP*'}| Select-Object Name
28.        $PrinterSamsung = Get-WmiObject -Class Win32_Printer -ComputerName $Computer |Where-Object { $_.Local -like 'True' -and $_.Name -like 'Samsung*'}| Select-Object Name
29.        $PrinterCanon   = Get-WmiObject -Class Win32_Printer -ComputerName $Computer |Where-Object { $_.Local -like 'True' -and $_.Name -like 'Canon*'}| Select-Object Name
30. 
31.        [PSCustomObject]@{
32.            ComputerName           = $Computer.ToUpper()
33.            Manufacturer           = $Hardware.Manufacturer
34.            Model                  = $Hardware.Model
35.            Serial_Number          = $Bios.serialnumber
36.            MAC_Address            = $Networks.MACAddress
37.            Netboot_GUID           = $GUID
38.            IP_Address             = $Networks.IpAddress[0]
39.            Processor_Type         = $cpu.Name
40.            System_Type            = $Hardware.SystemType
41.            Total_Memory_GB        = [math]::round($Hardware.TotalPhysicalMemory/1024/1024/1024, 2)
42.            CDROM_Drive            = $CDROM.Caption
43.            Graphics               = $Video.Name
44.            Last_User              = $username.Name
45.            User_Last_Login        = $username.LastWriteTime
46.            'C:_FreeSpace_GB'      = $driveSpace.GBfreespace
47.            Last_ReBoot            = $OS.ConvertToDateTime($OS.LastBootUpTime)
48.            Operating_System       = $OS.Caption
49.            Operating_System_Version = $OS.version
50.            Operating_System_BuildVersion = $SysBuild.BuildVersion
51.# Fehler Abfangen wegen des Null-Arrays wenn die WMI-Abfrage nicht klappt
52.            Monitor1Hersteller     = If($MonitorList[0]){($MonitorList[0].ManufacturerName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
52.            Monitor1Typ            = If($MonitorList[0]){($MonitorList[0].UserFriendlyName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
53.            Monitor1Seriennummer   = If($MonitorList[0]){($MonitorList[0].SerialNumberID -notmatch '^0$'   | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
54.            Monitor2Hersteller     = If($MonitorList[1]){($MonitorList[1].ManufacturerName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
55.            Monitor2Typ            = If($MonitorList[1]){($MonitorList[1].UserFriendlyName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
56.            Monitor2Seriennummer   = If($MonitorList[1]){($MonitorList[1].SerialNumberID -notmatch '^0$'   | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
57.            Monitor3Hersteller     = If($MonitorList[2]){($MonitorList[2].ManufacturerName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
58.            Monitor3Typ            = If($MonitorList[2]){($MonitorList[2].UserFriendlyName -notmatch '^0$' | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
59.            Monitor3Seriennummer   = If($MonitorList[2]){($MonitorList[2].SerialNumberID -notmatch '^0$'   | ForEach-Object {[CHAR]$_}) -join ''}Else{'N/A'}
60.            Drucker_HP             = $PrinterHP.Name
61.            Drucker_Samsung        = $PrinterSamsung.Name
62.            Drucker_Canon          = $PrinterCanon.Name
63.        }  ### End PSCustomObject
64.       
65.} ### End Foreach Computer
66. 
67.$Inventory

Fehler 1:

Get-WmiObject : Nicht unterstützt

At C:\test.ps1:26 char:36

+ ... nitorList = Get-WmiObject -Class WMIMonitorID -Namespace root\wmi -Co ...

 

Fehler 2:

Cannot index into a null array.

 

At C:\test.ps1:52 char:41

+ Monitor1Hersteller = If($MonitorList[0]){($MonitorLis ...

 

 

 

 

 

Ich hoffe nun auf eure Vorschläge.....Bedenkt bitte ich bin echter Newbie in Sachen Power Shell.



#12 Dukel

Dukel

    Board Veteran

  • 9.298 Beiträge

 

Geschrieben 19. Oktober 2017 - 10:43

Fang doch einfach an.

Lies z.B. nur den Computername und den Hesteller aus und schreibe dies in die gewünschte Datei in die gewünschte Form.

Dann erweiterest du das ganze.

Außerdem finde ich das sehr komplex. Wenn du plötzlich ein weiteren Wert brauchst musst du dies an zig Stellen im Script anpassen. Mach das Modular.


  • BOfH_666 gefällt das

Stop making stupid people famous.