conquestador
Goto Top

PowerShell prüfen, ob Wert in Array schon da ist

Hallo Community,

ich versuche mich in PowerShell einzuarbeiten und komme momentan nicht weiter.
Ich will ein Arrey mit zahlen füllen, doppelte Eingaben jedoch vermeiden, da der Inhalt nacheinander abgearbeitet werden soll.
hier mein Code:

write-host 
"  
Filialnummern:

Ort1 = 1
Ort2 = 2
Ort3 = 3
Ort4 = 4
Ort5 = 5
Programm beenden = 6

$Filialliste = @()
do {
$input = (Read-Host "Bitte die Filiale auswaehlen, beenden mit 6")  
    if ($input -lt '1') { write-host 'Die Eingabe ist keine Zahl zwischen 1 und 6' -foregroundcolor red }  
        elseif ($input -gt '6') { write-host 'Die Eingabe ist keine Zahl zwischen 1 und 6' -foregroundcolor red }  
           elseif ($input -ne '') {$Filialliste += $input}  
                #elseif ($Filialliste -contains $input) {write-host 'Die Filiale ist schon vorhanden' -foregroundcolor red } 
                #elseif ($Filialliste.Contains("1")) {Write-Host "Eintrag vorhanden"} else {Write-Host "Eintrag nicht vorhanden"} 
 }       

#Loop will stop when user enter '6' as input 
until ($input -eq '6')  
 
$Filialliste

Das funktioniert in dieser Form, wie ich es mir vorstelle. Wenn ich jedoch die Prüfung aktiviere, ob eine Filiale schon eingegeben wurde, passiert nichts und es wird doppelt eingetragen. Ich vermute, dass zum Zeitpunkt der Prüfung der Inhalt von $Filialliste nicht bekannt ist.

Kann mich bitte jemand erleuchten?
Danke!

Content-ID: 3019990677

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

Ausgedruckt am: 17.11.2024 um 23:11 Uhr

em-pie
em-pie 08.06.2022 aktualisiert um 17:43:57 Uhr
Goto Top
Moin,

zwei Dinge:
  1. es heißt Array, nicht Arrey
  2. Nutze Get-Unique()

Ich würde das Array am Ende noch mal neu aufbauen lassen, nur mit | Get-Unique abschließend

Dein Fehler ist zudem die Reihenfolge der Prüfung: Es gilt "First Match Wins"
du hast in Zeile 17 immer geprüft, ob das Feld nicht leer ist, wenn ja, ergänze. Weitere Prüfungen greifen dann nicht mehr. Hier mal, wie es aussehen könnte

$Filialliste = @()

write-host "  
Filialnummern: `r`n

[1] = Ort1
[2] = Ort2
[3] = Ort3
[4] = Ort4
[5] = Ort5
[6] = Programm beenden`r`n"  

do {
$i = Read-Host -Prompt 'Bitte die Filiale auswaehlen, beenden mit 6'  
    if ($Filialliste -contains $i) {write-host "Die Filiale ist schon vorhanden" -foregroundcolor red }  
    elseif ($i -ge 1 -and $i -le 5) {$Filialliste += $i}
    else {write-host "Die Eingabe '$i' ist keine Zahl zwischen 1 und 6" -foregroundcolor red }  
 }       

#Loop will stop when user enter '6' as input 
until ($i -eq 6)
 
$Filialliste


Gruß
em-pie
conquestador
conquestador 08.06.2022 um 17:33:01 Uhr
Goto Top
Upps, sorry für das Arrey !

Werd ich umgehend testen.
TK1987
TK1987 08.06.2022 aktualisiert um 22:27:21 Uhr
Goto Top
Moin,

ich würde mir die Ganze Überprüferei einfach sparen.

Wenn du willst, dass der Nutzer nur Eingaben von 1-6 tätigt, lass einfach keine anderen zu face-wink
@"  
Filialnummern: 

[1] = Ort1
[2] = Ort2
[3] = Ort3
[4] = Ort4
[5] = Ort5
[6] = Programm beende

"@  
write-host -NoNewLine "Auswahl: "  

# Frage nach Eingabe, bis diese eine Zahl von 1-6 enthält
do {$Eingabe = [console]::ReadKey($true).Keychar} until (1..6 -Contains "$Eingabe")  
write-host $Eingabe

Gruß Thomas
conquestador
conquestador 09.06.2022 um 09:36:19 Uhr
Goto Top
Danke für eure Hilfe!

@em-pie
funktioniert so, wie ich es wollte.

@TK1987
ich verstehe deinen Code noch nicht ganz, nehme es aber als Studiengrundlage face-smile
TK1987
TK1987 09.06.2022 um 12:17:44 Uhr
Goto Top
Zitat von @conquestador:
ich verstehe deinen Code noch nicht ganz, nehme es aber als Studiengrundlage face-smile
An welchem Teil hakt es denn mit dem Verständnis?
conquestador
conquestador 09.06.2022 um 16:47:43 Uhr
Goto Top
Die ISE macht ein Endlosloop beim Testen. Hier der Fehlertext:

Ausnahme beim Aufrufen von "ReadKey" mit 1 Argument(en):  "Schlüssel können   
nicht gelesen werden, wenn keine der Anwendungen eine Konsole besitzt, oder 
wenn die Konsoleneingabe aus einer Datei umgeleitet wurde. Verwenden Sie 
Console.Read."  
In Zeile:15 Zeichen:5
+ do {$Eingabe = [console]::ReadKey($true).Keychar} until (1..6 -Contai ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) , MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException

Hier weiß ich leider nicht weiter.
TK1987
TK1987 09.06.2022 um 17:32:08 Uhr
Goto Top
Moin,

Zitat von @conquestador:
Die ISE macht ein Endlosloop beim Testen. Hier der Fehlertext:

Ausnahme beim Aufrufen von "ReadKey" mit 1 Argument(en):  "Schlüssel können 
nicht gelesen werden, wenn keine der Anwendungen eine Konsole besitzt, oder 
wenn die Konsoleneingabe aus einer Datei umgeleitet wurde. Verwenden Sie 
Console.Read."
In Zeile:15 Zeichen:5
+ do {$Eingabe = [console]::ReadKey($true).Keychar} until (1..6 -Contai ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) , MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException
Der Fehler ist ja eindeutig: Die ISE besitzt keine Konsole, kann daher die Read-Key Methode auch nicht ausführen.

Und genau aus dem Grund rate ich allen immer: Finger weg von der ISE!!!

Die Produziert zum Teil andere Ausgaben als die Richtige Shell - was aber will man mit einer IDE, wenn das fertige Skript hinterher gänzlich anders abläuft?!

Wenn man unbedingt eine IDE benötigt, sollte man lieber Visual Studio Code nutzen.

Ich persönlich schreibe alle Skripte einfach mit Notepad++.
Wenn man sich dort unter "Ausführen > Externes Programm ausführen" folgenden Befehl abspeichert, kann man die Skripte auch bequem daraus ausführen (das Skript muss nur vorher immer gespeichert werden):
powershell -NoExit -ExecutionPolicy ByPass -Command "cd -Lit '$(CURRENT_DIRECTORY)';. '.\$(FILE_NAME)'"  
Zur Info: '$(CURRENT_DIRECTORY)' und '$(FILE_NAME)' sind bei diesem Befehl Variablen von Notepad++, nicht von Powershell.

Gruß Thomas
conquestador
conquestador 10.06.2022 aktualisiert um 09:55:27 Uhr
Goto Top
Moin Thomas,


Zitat von @TK1987:


Der Fehler ist ja eindeutig: Die ISE besitzt keine Konsole, kann daher die Read-Key Methode auch nicht ausführen.

Und genau aus dem Grund rate ich allen immer: Finger weg von der ISE!!!

Die Produziert zum Teil andere Ausgaben als die Richtige Shell - was aber will man mit einer IDE, wenn das fertige Skript hinterher gänzlich anders abläuft?!

Das wusste ich nicht, bin ja schließlich auch noch PS-Anfänger. Also Danke für den Hinweis.
Ich nutze auch recht gern NP++ und der PS-Aufruf, wie von dir geschrieben, funktioniert prima.

Leider bekomme ich deinen Code nicht integriert. Nehme ich dein Beispiel und führe es in sich geschlossen aus, kann ich einmalig eine Zahl zwischen 1 und 6 einfügen. Jetzt will ich aber damit ein Array befüllen. Das funktioniert nicht. Was mache ich falsch?

Hier noch mal der erste Teil des Scripts zum Vergleich:

cls
Write-host 
"  
Shutdown oder Reboot der PC's  
=============================

Bitte starte das Programm als Administrator!

"  

for ($z=1; $z -le 2; $z++) {

@"  
Filialnummern:

Ort1	= 1
Ort2	= 2
Ort3	= 3
Ort4	= 4
Ort5	= 5
Eingabe beenden  = 6

"@  

# Eingabe der Filialen inklusive Prüfabfrage korrekte Eingabe

$ArrayFilialliste = @()
do {
	
#===========================================================
# funktioniert so leider nicht
	
write-host -NoNewLine "Auswahl: "  

do {$Eingabe = [console]::ReadKey($true).Keychar}
until (1..6 -Contains "$Eingabe")  

#===========================================================


#____________________________________________________________________________________________________________________

# funktioniert wie es soll, lässt bei der ersten Eingabe aber Zahlen mit nehreren Ziffern zu!

	#$input = Read-Host -Prompt 'Bitte die Filiale auswaehlen und mit enter bestätigen, beenden mit 6: ' 
        #if ($ArrayFilialliste -contains $input) {write-host "Die Filiale ist schon vorhanden" -foregroundcolor red } 
            #elseif ($input -ge 1 -and $input -le 6) {$ArrayFilialliste += $input}
                #else {write-host "Die Eingabe '$input' ist keine Zahl zwischen 1 und 6" -foregroundcolor red } 
#____________________________________________________________________________________________________________________				
				
}
until ($input -eq '6')  
 
$ArrayFilialliste


Gruß (auch) Thomas
TK1987
Lösung TK1987 10.06.2022 aktualisiert um 12:56:46 Uhr
Goto Top
Moin,

Leider bekomme ich deinen Code nicht integriert. Nehme ich dein Beispiel und führe es in sich geschlossen aus, kann ich einmalig eine Zahl zwischen 1 und 6 einfügen. Jetzt will ich aber damit ein Array befüllen. Das funktioniert nicht. Was mache ich falsch?
das liegt u.a. daran, dass mir nicht ganz klar war, was genau du bezwecken willst. Du kannst leicht einen Array von 1-5 füllen:
$ArrayFilialliste = 1..5

oder willst du, das der Benutzer eine Auswahl aus den Filialen treffen kann?
Dies geht viel leichter und sogar mit GUI:
$Filialen = @(
  "Hamburg"  
  "München"  
  "Frankfurt"  
  "Köln"  
  "Stuttgart"  
)

$Auswahl = $Filialen | Out-Gridview -Title "Bitte Filialen auswählen: " -Passthru  

"Folgende Filialen wurden ausgewählt: "  
$Auswahl
Da kann man einfach eine Mehrfachauswahl treffen.

Aber um auch deinen bisherigen Versuch zu vervollständigen, etwa so:
@"  
Filialnummern:

Ort1	        = 1
Ort2	        = 2
Ort3	        = 3
Ort4	        = 4
Ort5	        = 5
Eingabe beenden = 6

"@  

while ($true) {
  Write-Host -NoNewLine "Auswahl: "  
  # Nach Eingabe fragen, bis diese eine Zahl von 1-6 enthält
  do {$Eingabe = [Console]::ReadKey($true).KeyChar} until (1..6 -Contains "$Eingabe")  
  
  # Wenn 6, While-Schleife beenden
  if ("$Eingabe" -eq 6) {break}  
  
  # Wenn Auswahl schon vorhanden
  if ($FilialAuswahl -Contains $Eingabe) {Write-host -ForegroundColor Yellow "`rFiliale $Eingabe ist schon in Auswahl vorhanden. "}  
  else {
    [Array]$FilialAuswahl += $Eingabe
    Write-Host -ForegroundColor Green "`rFiliale $Eingabe wurde hinzugefügt"  
  }
}
write-host "`rGewähle Filialen: "  
$FilialAuswahl | Sort

back-to-topWas für dich dann auch noch interessant sein könnte dürfte: Enumerationen
So werden den Filialen direkt ihrer persönliche Nummer zugewiesen - und du kannst die Filialnummer ganz leicht in den Filialnamen oder umgekehrt den Namen in die nummer konvertieren. Beispiel:
Enum Filiale {
  Hamburg   = 1
  München   = 2
  Frankfurt = 3
  Köln      = 4
  Stuttgart = 5
}
Dann in Aktion:
PS C:\Users\Thomas> [Filiale]3
Frankfurt
PS C:\Users\Thomas> [int][Filiale]"Stuttgart"
5

Oder sogar eine Enumeration als Bit-Flags. Diese besitzt den Vorteil, dass auch jede Kombinationsmöglichkeit der einzelnen Filialen einen eigenen Wert besitzt:
[Flags()] Enum Filiale {
  Hamburg   = 1
  München   = 2
  Frankfurt = 4
  Köln      = 8
  Stuttgart = 16
}
in Aktion:
PS C:\Users\Thomas> [Filiale]25
Hamburg, Köln, Stuttgart

PS C:\Users\Thomas> [int][Filiale]("Hamburg","München","Stuttgart")
19

PS C:\Users\Thomas> 1..31 | Foreach-Object {
>>   [pscustomobject]@{
>>      Nummer  = $_
>>      Wert    = [Filiale]$_
>>   }
>> }

Nummer                                         Wert
------                                         ----
     1                                      Hamburg
     2                                      München
     3                             Hamburg, München
     4                                    Frankfurt
     5                           Hamburg, Frankfurt
     6                           München, Frankfurt
     7                  Hamburg, München, Frankfurt
     8                                         Köln
     9                                Hamburg, Köln
    10                                München, Köln
    11                       Hamburg, München, Köln
    12                              Frankfurt, Köln
    13                     Hamburg, Frankfurt, Köln
    14                     München, Frankfurt, Köln
    15            Hamburg, München, Frankfurt, Köln
    16                                    Stuttgart
    17                           Hamburg, Stuttgart
    18                           München, Stuttgart
    19                  Hamburg, München, Stuttgart
    20                         Frankfurt, Stuttgart
    21                Hamburg, Frankfurt, Stuttgart
    22                München, Frankfurt, Stuttgart
    23       Hamburg, München, Frankfurt, Stuttgart
    24                              Köln, Stuttgart
    25                     Hamburg, Köln, Stuttgart
    26                     München, Köln, Stuttgart
    27            Hamburg, München, Köln, Stuttgart
    28                   Frankfurt, Köln, Stuttgart
    29          Hamburg, Frankfurt, Köln, Stuttgart
    30          München, Frankfurt, Köln, Stuttgart
    31 Hamburg, München, Frankfurt, Köln, Stuttgart

Gruß Thomas
conquestador
conquestador 10.06.2022 aktualisiert um 13:39:00 Uhr
Goto Top
Oha, wieder einiges zum Studieren face-smile
Danke!
Eingebaut habe ich es auch und es funktioniert jetzt. (Sehr gut sogar!) aus dem, was ich hieraus gelernt habe kann ich das script im weiteren Verlauf weiter optimieren (z.B. brauche ich dann weiter unten die Eingabe"6" im Array nicht blocken, wenn ich den Inhalt weiterverwende. Außerdem werde ich die weiteren Abfragen nochmal überarbeiten).

Vielleicht kurz zur Erklärung, welchen Zweck das Script hat:
1. Ich will zuallererst programmieren in Powershell lernen. Daher sind meine Versuche sicher erst mal bissl unbeholfen und umständlich.
2. Ziel dieses Sriptes ist vor allem Lernen am Beispiel. allerdings verfolgt es auch einen Nutzen:

5 Filialen -> etliche Mitarbeiter lassen über Wochen ihre Rechner an. Manchmal will ich die aus Gründen mal neu gestartet haben.
Nach mehreren Abfragen kommt der Neustart der Rechner mit Hilfe von Textdateien, in denen die IP's pro Filiale gelistet sind.

Hier mal das Script im Ganzen:
(sicher kann man einiges anders machen, aber so taste ich mich an verschiedenes erst mal heran und versuche zu verstehen, was da passiert)

cls
Write-host 
"  
Shutdown oder Reboot der PC's  
=============================

Bitte starte das Programm als Administrator!

"  

for ($z=1; $z -le 2; $z++) {

@"  
Filialnummern:

Filiale 1 = 1
Filiale 2 = 2
Filiale 3 = 3
Filiale 4 = 4
Filiale 5 = 5
Eingabe beenden  = 6

"@  

$ArrayFilialliste = @()

while ($true) {
  Write-Host -NoNewLine "Auswahl: "  
  # Nach Eingabe fragen, bis diese eine Zahl von 1-6 enthält
  do {$Eingabe = [Console]::ReadKey($true).KeyChar} until (1..6 -Contains "$Eingabe")  
  
  # Wenn 6, While-Schleife beenden
  if ("$Eingabe" -eq 6) {break}  
  
  # Wenn Auswahl schon vorhanden
  if ($ArrayFilialliste -Contains $Eingabe) {Write-host -ForegroundColor Yellow "`rFilale schon in Auswahl vorhanden. "}  
  else {
    [Array]$ArrayFilialliste += $Eingabe
    Write-Host -ForegroundColor Green "`rFilale $Eingabe wurde hinzugefügt"  
  }
}
write-host "`rGewähle Filalen: "  
$ArrayFilialliste




# Eingabe der Filialen inklusive Prüfabfrage korrekte Eingabe


#____________________________________________________________________________________________________________________

# funktioniert wie es soll, lässt bei der ersten Eingabe aber Zahlen mit nehreren Ziffern zu!

	#$input = Read-Host -Prompt 'Bitte die Filiale auswaehlen und mit enter bestätigen, beenden mit 6: ' 
        #if ($ArrayFilialliste -contains $input) {write-host "Die Filiale ist schon vorhanden" -foregroundcolor red } 
            #elseif ($input -ge 1 -and $input -le 6) {$ArrayFilialliste += $input}
                #else {write-host "Die Eingabe '$input' ist keine Zahl zwischen 1 und 6" -foregroundcolor red } 
#____________________________________________________________________________________________________________________				
				
#}
#until ($input -eq '6') 
 
$ArrayFilialliste

do {
Write-host "Ist die Liste so korrekt?"  
$i = Read-Host -Prompt "j = ja,weiter /  n = nein, von vorn: "  

if (-not ($i -eq "j" -or $i -eq "n")) {  
	write-host "  
	Falsche Eingabe! Bitte st oder min oder sec verwenden!" -foregroundcolor magenta}  
}
until ($i -eq "j" -or $i -eq "n")  

if ($i -eq "j") {$z=2}  
}


#shutdown oder reboot?

do{
$sr = Read-Host -Prompt '  
Soll bei diesen Rechnern ein shutdown (= s) oder ein reboot (= r) durchgeführt werden?

Bitte s oder r eingeben und mit enter bestätigen '  


#Prüfabfrage korrekte Eingabe

if (-not ($sr -eq "s" -or $sr -eq "r")) {  
write-host "Falsche Eingabe! Bitte st oder min oder sec verwenden!" -foregroundcolor magenta}  
}
until ($sr -eq "s" -or $sr -eq "r")  

if ($sr -eq "s") {$x="shutdown"} else {$x="reboot"}  


#Zeit bis shutdown oder Reboot in Stunden, Minuten oder Sekunden?

do {
write-host "  
Zeit bis" $x "kann in Stunden (= st) oder Minuten (= min) oder Sekunden (= sek) angegeben werden.  

"  
[string]$Zeit = Read-Host -Prompt "Bitte st oder min oder sek eingeben und mit enter bestätigen"  


#Prüfabfrage korrekte Eingabe

if (-not ($Zeit -eq "st" -or $Zeit -eq "min" -or $Zeit -eq "sec")) {  
write-host "Falsche Eingabe! Bitte st oder min oder sec verwenden!" -foregroundcolor magenta}  
}
until ($Zeit -eq "st" -or $Zeit -eq "min" -or $Zeit -eq "sec")  


#Abfrage der Zeit bis shutdown oder Reboot und Berechnung der Pause-Zeit 

write-host ""  
if ($Zeit -eq "st") { Write-Host "Stunden bis" $x   
    [int]$t = read-host -prompt "eingeben: "  
    $Time = $t*10 }
elseif ($Zeit -eq "min") { Write-Host "Minuten bis" $x  
    [int]$t = read-host -prompt "eingeben: "  
    $Time = $t*5 }
else { write-host "Sekunden bis $x "  
    [int]$t = read-host -prompt "eingeben: "  
    $Time = $t }


#Start-Sleep -Seconds $Time
sleep $Time


$Log  = "C:\Users\xxxx\Desktop\PowerShell\welcher_PC_war_noch_an.txt"  
$D = Get-Date -Format "dddd dd/MM/yyyy HH:mm:ss"  

foreach ( $Filiale in $ArrayFilialliste ) {

    if ($Filiale -lt "6"){  
        $IPList = Get-Content -Path C:\Users\xxxx\Desktop\PowerShell\reboot\neu\ip.list.$Filiale
    
        foreach ( $IP in $IPList ) {
            #ping $IP -n 1 > $null
            Test-Connection $IP -Count 1 -Quiet > $null
        
            if ($lastexitcode -eq 0) {
               "$IP - $D" | out-file "C:\Users\xxxx\Desktop\PowerShell\welcher_PC_war_noch_an.txt" -Append  
                if ($sr="r"){shutdown.exe /m \\$IP /r /t 0 /f} else {shutdown.exe /m \\$IP /s /t 0 /f}  
            }
        }
    }
}

write-host "Script ausgeführt" $Date  

Gruß Thomas