lenny4me
Goto Top

Powershell If mit Continue

Hallo Kollegen ich Grüße euch und wünsche einen wunderschönen Tag

Ich habe ein Problem mit einem kleinen Powershell script.
Ich möchte alle Server die einen Neustart benötigen (Windows Updates) per Script nachts neu starten. Ein paar Maschienen die aber auch Nachts laufen müssen vom Neustart ausnehmen...

Was ich schon habe... Alle Server/Clients werden angezeigt...

Das Problem sind die Ausschlüsse..
hier mein Script (das meiste aus der Knowledgebase von MS geklaut...)

if (!$wsus) {
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
}

$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope;
$updateScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$computers = $wsus.GetComputerTargets($computerScope);

$computers | foreach-object {

$_.FullDomainName | out-file -filepath W:\wsus\Clients_reboot_needed.txt -encoding Default -append
$_.FullDomainName |foreach-object {


if ($_ -eq 'Server1.Domain.de'){
continue
}
if ($_ -eq 'Server2.Domain.de'){
continue
}
if ($_ -eq 'Server3.Domain.de'){
continue
}
if ($_ -eq 'Server4.Domain.de'){
continue
}
if ($_ -eq 'Server5.Domain.de'){
continue
}
if ($_ -eq 'Server6.Domain.de'){
continue
}
write-host $_

}

Wenn ich nun dieses Scriptchen ausführe listet er mir nur 2,3 Rechner auf. Wenn ich aber das Continue weglasse sind es wesentlich mehr...
Ich will einfach wenn der Servername gefunden wird, die Schleife zurücksetzen und mit dem nächsten Wert starten... aber aufgrund irgendeinem Fehler will er nicht... Er läuft bis der erste Name matched und steigt dann aus der gesamten Schleife aus... wie bei Break (da gibt genau das gleiche Ergebnis zurück).
Wenn man die If Abfragen auf ElseIf umstrickt gibt er schon mehr Clients zurück... Aber immer noch nicht alle... face-sad
Continue sollte doch der richtige Befehl sein oder?

Grüße Lenny

Content-Key: 168314

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

Printed on: April 16, 2024 at 17:04 o'clock

Member: LittleFlame
LittleFlame Jun 20, 2011 at 11:53:19 (UTC)
Goto Top
Hallo Lenny,

Ich hab jetzt nur mal kurz drübergeschaut, werd mich aber gleich noch n bisschen damit beschäftigen.
Aber das erste was mir aufgefallen ist, ist, dass für

$computers | foreach-object {

am Ende noch die } fehlt. (Evtl auch einfach Copy & Paste falsch)

Ich schau mal schnell drüber.

Grüße,
LF
Member: lenny4me
lenny4me Jun 20, 2011 at 12:00:35 (UTC)
Goto Top
Hallo,

falsches Copy Paste... in meinem Script stimmts...

Danke für die Hilfe.

Grüße Lenny
Member: LittleFlame
LittleFlame Jun 20, 2011 at 12:09:32 (UTC)
Goto Top
Überprüfst du verschiedene Domains, oder befinden sich alle deine zu überprüfenden Rechner in der selben Domain?

Grüße,
LF
Member: lenny4me
lenny4me Jun 20, 2011 at 13:02:24 (UTC)
Goto Top
irgendwann kann man darüber sprechen ob er mehrere Domain abklopfen soll... Momentan würde mir die Domain des WSUS reichen...
Es wäre noch interessant wie ich eine einzelne Gruppe am WSUS Server auslesen kann... Momentan nimmt er mir die gesamten Clients des WSUS mit...


Grüße Lenny
Member: LittleFlame
LittleFlame Jun 20, 2011 at 14:04:38 (UTC)
Goto Top
So... hab mal n bisschen drübergelesen.

Also wenn ich das richtig verstehe, versuchst du mit

if ($_ -eq 'Server1.Domain.de'){
continue
}

die Clients wegzuschreiben, die erlaubt sind, oder?

Aber was passiert, wenn der Client nicht vorkommt?
Dann hängt die Schleife ohne Anweisung irgendwo.

Kann sein, dass ich des falsch verstehe, aber für mich hast du hier keine "Ausnahmen" sondern nur erlaubte Clients.
Und sobald ein Client kommt, der nicht aufgeführt wird, macht dein Script nichtsmehr.

Hab ich das so richtig verstanden?
Member: LittleFlame
LittleFlame Jun 20, 2011 at 14:29:55 (UTC)
Goto Top
Hab nochmal oben nachgelesen...

Ich will einfach wenn der Servername gefunden wird, die Schleife zurücksetzen

Ich bin nicht der große Powershell-Guru, aber warum willst du die Schleife zurücksetzen?
Für deine ersten Tests (Du schreibst das ganze ja momentan nur in ein Logfile) ist es doch unsinnig, die Schleife zurücksetzen zu wollen

Wenn du einfach anstatt deine IF-Abfragen, das ganze sofort mit write-host $_ ins Logfile schreibst, müsstest du doch am Ende in deinem Logfile alle Clients stehen haben, die einen Reboot benötigen. Und genau das willst du doch, oder?

Fragende Grüße,
LF
Member: lenny4me
lenny4me Jun 20, 2011 at 15:00:07 (UTC)
Goto Top
write-host $_ werde ich später durch shutdown /r /f /t oder sonstiges Powershell equivalent ersetzen.
Nur zum testen mag ich ned meine Server permanent durchstarten ;D

Die server 1-6 (die mit den If anweisungen) sind Server die ich nicht neustarten möchte.

Also If Name1 stimmt mit If Anweisung überein -> breche den aktuellen Ablauf ab und starte mit einem neuen Servernamen.
Wenn Server2 in den If Anbweisungen nicht vorkommt dann starte Ihn neu -> Starte die Schleife mt neuem Servernamen usw...

Und einen Schleifendurchlauf sollte man eingentlich mit Continue abbrechen können... ( Strg+c... Another useful statement for use in loops in the continue statement. When the execution process finds a continue statement in any kind of loop it skips all remaining code in the body of the loop and begins execution once again from the top of the loop.)


Grüße Lenny
Member: LittleFlame
LittleFlame Jun 20, 2011 at 15:06:26 (UTC)
Goto Top
if (!$wsus) 
{
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
}

$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope;
$updateScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$computers = $wsus.GetComputerTargets($computerScope);

$computers | foreach-object 
{
	$_.FullDomainName | out-file -filepath C:\Temp\test.txt -encoding Default -append
	$_.FullDomainName | foreach-object 
	{
		if ($_ -eq 'Server1.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server2.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server3.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server4.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server5.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server6.Domain.de')  
		{
			continue
		}
		else 
		{
		}
	write-host $_
	}
}


Verbessert das das ganze?

Und falls du dich fragst, warum ich als relativer PS-Neuling versuche, das ganze hinzukriegen:
Ich sitze ebenfalls gerade an meinen ersten Powershell-Scripts und dachte mit "Geteiltes Leid is halbes Leid" face-smile

Grüße,
LF
Member: lenny4me
lenny4me Jun 20, 2011 at 18:33:36 (UTC)
Goto Top
Werde es morgen mal versuchen und mich dann morgen mal wieder melden.
Member: lenny4me
lenny4me Jun 21, 2011 at 05:13:18 (UTC)
Goto Top
Hallo Little Flame,

das Problem bleibt das gleiche. sobald er einen Rechner findet, seigt er aus...

Grüße Lenny

was allerdings etwas mehr bring t ist
$computers | foreach-object { 
               # $_.FullDomainName | write-host ;
                 $_.FullDomainName | out-file -filepath W:\wsus\Clients_reboot_needed.txt -encoding Default -append
                 $_.FullDomainName |foreach-object {
                                              
                         if ($_ -eq 'server1.Domain.de'){  
            	             continue
                        				
			             elseif ($_ -eq 'server2.Domain.de')  
              	             continue
                        		
                         elseif ($_ -eq 'serve3r.Domain.de')  
              	             continue
                        		
                         elseif ($_ -eq 'serve4r.Domain.de')  
              	             continue
                        	
                         elseif ($_ -eq 'server5.Domain.de')  
            	             continue
                        	
                         elseif ($_ -eq 'server6.Domain.de')  
            	             continue
                        }		
                        write-host $_			
			             
                        }
              }
Aber ich verstehe nicht warum... Grundsätzlich sollte das doch genau das gleiche machen... und es werden zu allem Überfluss in unten genanntem Codebeispiel, Server aufgeführt die ich ausgenommen habe...
Member: LittleFlame
LittleFlame Jun 21, 2011 at 07:32:20 (UTC)
Goto Top
Guten morgen,

du hast in deinem Codebeispiel in Zeile 6 folgendes

 if ($_ -eq 'server1.Domain.de'){    

Warum machst du hier eine klammer auf?

Grüße,
LF
Member: lenny4me
lenny4me Jun 21, 2011 at 07:43:19 (UTC)
Goto Top
Hallo guten morgen,

naja ich mache eine Klammer auf weil die Anweisung doch in geschweiften Klammern stehen muss?! Ohne Klammer meckert er mir das erste Continue an...

Oder bin ich auf dem Holzweg.

Grüße Lenny
Member: LittleFlame
LittleFlame Jun 21, 2011 at 08:35:49 (UTC)
Goto Top
Wie führst du denn dein Script aus?
Überprüfst du die Bildschirmausgabe, oder nur das, was in der "Clients_reboot_needed.txt" steht?
Member: LittleFlame
LittleFlame Jun 21, 2011 at 08:55:04 (UTC)
Goto Top
Probier mal folgendes:

if (!$wsus) 
{
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
}

$file="W:\wsus\Clients_reboot_needed.txt"  

$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope;
$updateScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$computers = $wsus.GetComputerTargets($computerScope);

$computers | foreach-object 
{
	$_.FullDomainName | foreach-object 
	{
		if ($_ -eq 'Server1.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server2.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server3.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server4.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server5.Domain.de')  
		{
			continue
		}
		elseif ($_ -eq 'Server6.Domain.de')  
		{
			continue
		}
	write-host $_
	out-file -filepath $file -inputobject $_ -append -encoding default
	}
}


Somit müsstest du zumindest die richtige Ausgabe in Clients_reboot_needed.txt haben
Member: lenny4me
lenny4me Jun 21, 2011 at 09:46:13 (UTC)
Goto Top
Hallo,

ich werde mich gleich mal ran machen.. Die Datei Clients_reboot_needed ist nur ein Anhaltspunkt welche Rechner er denn neu gestartet hat... also praktisch eine "Doku" welche er mir als geplanter Task per Mail zusendet (Ja ich weis das geht auch über die Powershell)
Member: lenny4me
lenny4me Jun 21, 2011 at 09:54:46 (UTC)
Goto Top
Hallo,

das ging schneller als erwartet...
Nach dem start erscheint die Meldung "Geben Sie Werte für die folgenden Parameter an: Process" <- was ist denn das?!

Beim ausführen des Scripts bekomme ich einen Fehler.

ForEach-Object : Der Befehl kann nicht verarbeitet werden, da mindestens ein verbindlicher Parameter fehlt: Process.
Bei C:\Users\administratorDomain\AppData\Local\Temp\2\60471694-c3fb-4178-92dc-53ec40169413.ps1:23 Zeichen:29

back-to-top$computers | foreach-object <<<<

+ CategoryInfo : InvalidArgument: (:) [ForEach-Object], ParameterBindingException
+ FullyQualifiedErrorId : MissingMandatoryParameter,Microsoft.PowerShell.Commands.ForEachObjectCommand

Das Script läuft zwar weiter... und erstellt auch eine Datei. Aber Server1-6 tauchen wieder in dieser Liste auf...

Langsam bin ich wirkllich am verzweifeln.

Grüße Lenny
Member: LittleFlame
LittleFlame Jun 21, 2011 at 09:58:04 (UTC)
Goto Top
Ein Problem dürfte zumindest gewesen sein, dass er dir nicht deine neu gestartetet Clients in das Logfile geschrieben hat, sondern durch

$_.FullDomainName | out-file -filepath W:\wsus\Clients_reboot_needed.txt -encoding Default -append 

hast du dir hier (glaube ich) alle Clients auflisten lassen, da diese Zeile ja von den "continue" -Zeilen nicht betroffen ist.
Wenn das neue Script das tut, was es soll, schreibt es nur in das Logfile, wenn kein continue erreicht wurde.

Bin gespannt auf das Ergebnis.

Grüße,
LF
Member: LittleFlame
LittleFlame Jun 21, 2011 at 10:16:07 (UTC)
Goto Top
[EDIT]

Vergiss es... geht auch nicht

[EDIT]
Member: LittleFlame
LittleFlame Jun 21, 2011 at 10:21:13 (UTC)
Goto Top
Hier dürfte dieser Fehler nicht vorkommen:

[EDIT]
Schön formatiert
[EDIT]

if (!$wsus) 
{
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
}

$file = "W:\wsus\Clients_reboot_needed.txt"  

$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope;
$updateScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$computers = $wsus.GetComputerTargets($computerScope);

$computers | foreach-object {
	$_.FullDomainName | foreach-object 	{
		if ($_ -eq "Server1.Domain.de")  
		{
			continue
		}
		elseif ($_ -eq "Server2.Domain.de")  
		{
			continue
		}
		elseif ($_ -eq "Server3.Domain.de")  
		{
			continue
		}
		elseif ($_ -eq "Server4.Domain.de")  
		{
			continue
		}
		elseif ($_ -eq "Server5.Domain.de")  
		{
			continue
		}
		elseif ($_ -eq "Server6.Domain.de")  
		{
			continue
		}
	write-host $_
	out-file -filepath $file -inputobject $_ -append -encoding default
	}
}
Member: lenny4me
lenny4me Jun 21, 2011 at 11:00:07 (UTC)
Goto Top
Hallo LittleFlame,

erstmal vorweg: danke das du Dir so viel Mühe gibst.

Leider steigt er mir immer noch aus, soblad der erste Servername "matched"
in meiner alten Version wird die Clients_reboot_needed ja mit allen Rechnern gefüllt die einen Neustart brauchen, incl. derer die ich gerne ausgeschlossen hätte.

Unsere Scripte unterscheiden sich nur darin, das bei dir nur Rechner in der Textfile stehen die nach dem Abbruch auch in der shell angezeigt werden, bei mir jedoch alle.

Grüße Lenny


hier noch mal aktuell was ich habe
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null   
 
if (!$wsus) { 
        $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer(); 
} 
 
$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope; 
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot; 
 
$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope; 
$updateScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot; 
 
$computers = $wsus.GetComputerTargets($computerScope); 

Remove-Item -path Clients_reboot_needed.txt
 
$computers | foreach-object { 
                #$_.FullDomainName | write-host ;
                 $_.FullDomainName | out-file -filepath W:\wsus\Clients_reboot_needed.txt -encoding Default -append
                 }
				 
				 
	$computers | foreach-object { 
				$_.FullDomainName |foreach-object {
		              #Tee-object 'W:\wsus\Clients_reboot_needed.txt'  
		                       
		                  if ($_ -eq 'server1.DOMAIN.de'){  
		            	    continue;
		                  }				
					       if ($_ -eq 'server2.DOMAIN.de'){  
		              	    continue;
		                  }		
		                   if ($_ -eq 'server3.DOMAIN.de'){  
		                   	continue;
		                  }		
		                   if ($_ -eq 'server4.DOMAIN.de'){  
		                  	continue;
		                  }	
		                   if ($_ -eq 'server5.DOMAIN.de'){  
		                    continue;
		                  }	
		                   if ($_ -eq 'server6.DOMAIN.de'){  
		                   	continue;
		                  }		
		                   else {write-host $_}			
					             
		                 }

		}

ich weis wohl das es keinen sinn macht das Textfile in einem speraten Aufruf zu füllen, für momentane Zwecke (debugging) halte ich es aber weiterhin so...
Member: LittleFlame
LittleFlame Jun 21, 2011 at 11:07:53 (UTC)
Goto Top
Hallo Lenny,

ich seh schon... ich hab in dem Bereich zu wenig KnowHow, um dir weiterzuhelfen.
Aber nen Versuch wars wert face-smile

Ich hab mir ein Vergleichsscript gebaut, um deinen Fehler nachzuvollziehen. Und es tut genau das, was du möchtest.
Es springt nur zu "write-host", wenn die If-Bedingung nicht zutrifft.

$ints = @(1,2,3,4,5)
$File ="C:\Temp\test.txt"  

foreach ($i in $ints)
{
	if ($i -eq '1')  
	{
		continue
	}
	elseif ($i -eq '2')  
	{
		continue
	}
write-host $i
out-file -filepath "C:\Temp\test.txt" -inputobject $i -append -encoding default  
} 

Deshalb verstehe ich nicht, warum es in dienem Fall nicht funktioniert.

Aber ich befürchte, ich komm nicht dahinter.

Grüße,
LF
Member: lenny4me
lenny4me Jun 21, 2011 at 11:40:33 (UTC)
Goto Top
Der Herr sei gepriesen... Es funktioniert...
Ich habe mir gedacht wenn er bei den Continues aussteigt, lass ich Sie einfach weg.. und sehe da

[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null   
 
if (!$wsus) 
{
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
}

$file = "W:\Wsus\Clients_reboot_needed.txt"  

$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope;
$updateScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

$computers = $wsus.GetComputerTargets($computerScope);

$computers | foreach-object {
	$_.FullDomainName | foreach-object 	{
		if ($_ -eq 'Server1.DOMAIN.de')  
		{
			
		}
		elseif ($_ -eq 'Server2.DOMAIN.de')  
		{
			
		}
		elseif ($_ -eq 'Server3.DOMAIN.de')  
		{
			
		}
		elseif ($_ -eq 'Server4.DOMAIN.de')  
		{
			
		}
		elseif ($_ -eq 'Server5.DOMAIN.de')  
		{
			
		}
		elseif ($_ -eq 'Server6.DOMAIN.de')  
		{
			
		}
	else {write-host $_
	out-file -filepath $file -inputobject $_ -append -encoding default
	}
	}
}

Es klappt. Wirklich vielen dank für Deine Hilfe. Nun muss ich nur noch dahinter kommen wie ich einzelne Gruppen des WSUS Servers auslesen kann.


Mfg Lenny