Jump to content

Erweiterbares Tool


Recommended Posts

Hallo allerseits,

 

ich habe mir überlegt, eine gui zu erstellen, die ich immer wieder erweitern möchte, wenn Zeit und Forscherdrang besteht.

Ich versuche, alles irgendwie nachzuvollziehen, anzupassen etc.

 

Ich bin jetzt auf ein Problem gestoßen, das ich nicht nachvollziehen kann.

Die Zeile "$Starten_Knopf.Add_Click({ZeitServerStart})" wird als unbekanntes cmdlet angegeben, kann mir jemand sagen, wo ich einen Fehler habe?

 

Zitat

function Funktion-ZeitServer_Test
    {
    
    # ────────── Start Funktion ZeitServerStart    
        function ZeitServerStart {

            if ($Eigenen_Zeit_Server.Checked -eq $true)
            {$Ausgabe_Ergebniss=w32tm /query /source}
            
                if ($Zeit_Server_Testen.Checked -eq $true)
                {$Ausgabe_Ergebniss=w32tm /stripchart /computer:0.de.pool.ntp.org /samples:5 /dataonly}
                
                    if ($Zeit_Server_festlegen.Checked -eq $true)
                    {$Ausgabe_Ergebniss=3}

            $ZeitServer_Test_Ausgabe=$Ausgabe_Ergebniss | fl | out-string;
            $Ausgabe_Feld.text=$ZeitServer_Test_Ausgabe
                     }
    # ────────── Ende Funktion ZeitServerStart
                    
                    
    # ────────── Start Auswahlkasten                
        $AuswahlBox = New-Object System.Windows.Forms.GroupBox
        $AuswahlBox.Location = New-Object System.Drawing.Size(40,50)
        $AuswahlBox.size = New-Object System.Drawing.Size(320,140)
        $AuswahlBox.text = "Auswahl-Funktionen"
        $Hauptfenster.Controls.Add($AuswahlBox)
    # ────────── Ende Auswahlkasten


    # ────────── Start Auswahlschalter Funktion-ZeitServer_Test
        $Eigenen_Zeit_Server = New-Object System.Windows.Forms.RadioButton
        $Eigenen_Zeit_Server.Location = new-object System.Drawing.Point(25,30)
        $Eigenen_Zeit_Server.size = New-Object System.Drawing.Size(260,20)
        $Eigenen_Zeit_Server.Checked = $true
        $Eigenen_Zeit_Server.Text = "Eigenen Zeit-Server ermitteln"
        $AuswahlBox.Controls.Add($Eigenen_Zeit_Server)
        
        $Zeit_Server_Testen = New-Object System.Windows.Forms.RadioButton
        $Zeit_Server_Testen.Location = new-object System.Drawing.Point(25,65)
        $Zeit_Server_Testen.size = New-Object System.Drawing.Size(260,20)
        $Zeit_Server_Testen.Text = "Test des Zeit-Servers Starten"
        $AuswahlBox.Controls.Add($Zeit_Server_Testen)
        
        $Zeit_Server_festlegen = New-Object System.Windows.Forms.RadioButton
        $Zeit_Server_festlegen.Location = new-object System.Drawing.Point(25,100)
        $Zeit_Server_festlegen.size = New-Object System.Drawing.Size(260,20)
        $Zeit_Server_festlegen.Text = "Neuen Zeit-Server festlegen"
        $AuswahlBox.Controls.Add($Zeit_Server_festlegen)
    # ────────── Ende Auswahlschalter Funktion-ZeitServer_Test


    # ────────── Start Startknopf Funktion-ZeitServer_Test
        $Starten_Knopf = New-Object System.Windows.Forms.Button
        $Starten_Knopf.Location = New-Object System.Drawing.Size(370,45)
        $Starten_Knopf.Size = New-Object System.Drawing.Size(40,40)
        $Starten_Knopf.Text = "Test Starten"
        $Starten_Knopf.Add_Click({ZeitServerStart})
        $Starten_Knopf.Cursor = [System.Windows.Forms.Cursors]::Hand
        $Hauptfenster.Controls.Add($Starten_Knopf)
    # ────────── Ende Startknopf Funktion-ZeitServer_Test


    # ────────── Start Ausgabe Funktion-ZeitServer_Test
        $Ausgabe_Feld = New-Object System.Windows.Forms.TextBox
        $Ausgabe_Feld.Location = New-Object System.Drawing.Size(40,195)
        $Ausgabe_Feld.Size = New-Object System.Drawing.Size(320,140)
        $Ausgabe_Feld.MultiLine = $True
    # ────────── Ende Ausgabe Funktion-ZeitServer_Test


        $Ausgabe_Feld.ScrollBars = "Vertical"
        $Hauptfenster.Controls.Add($Ausgabe_Feld)
    }

 

Link to post

Ohne die komplette Fehlermeldung kann man nur raten ... Du definierst die Funktion "ZeitServerStart" innerhalb der Funktion "Funktion-ZeitServer_Test". So lange die Funktion "Funktion-ZeitServer_Test" noch nicht gelaufen ist, existiert also die Funktion "ZeitServerStart" noch nicht ... isses vielleicht das?  Übrigens ist es Best Practice die Funktionen in Powershell in der gleichen Art und Weise zu benennen, wie die cmdlets - also die Form "Verb-Nomen" zu benutzen - und dabei die empfohlenen Verben zu benutzen. Die kannst Du Dir mit Get-Verb auf der Konsole anzeigen lassen.

Edited by BOfH_666
Link to post

Verschiebe die ZeitServerStart außerhalb von Funktion-ZeitServer_Test.

Bei Powershell ist auch wichtig, dass die Funktionen als erstes kommen, vor dem eigendlichen Code.

 

function a{ ... }

function b{ ... }

function c{ ... }

### Main:

# Run a Function:

a

Link to post

It's all about scope... Eine Funktion, die Du INNERHALB einer andere Funktion erstellst, existiert auch nur IN dieser anderen Funktion. Denn "global gesehen" ist eine Funktion auch wieder nur ein Objekt, und jedes Objekt hat seinen Scope.

Link to post

OK. Als Erstes bitte: In Zukunft solltest Du Code, Fehlermeldungen, Konsolen-Output oder Beispiel-Daten als Code formatieren. Nicht als Zitat und schon gar nicht als Bild. ;-) 

 

Du hast jetzt aus 3 verschiedenen Richtungen gehört, dass es eventuell keine gute Idee ist, eine Funktion innerhalb einer Funktion zu definieren. Wie wär's, wenn Du einfach mal probierst, die Funktionsdefinition für "ZeitServerStart" außerhalb der Funktionsdefinition von "Funktion-ZeitServer_Test" zu packen und schaust, was passiert?

 

Unabhängig davon wäre es bestimmt hilfreich, den kompletten Code zu sehen, oder wenigstens ein größeres Stück, welches einem potenziellen Helfer ermöglicht, den Code auszuführen und evtl. die gleiche Fehlermeldung zu erhalten. Dafür hilft es manchmal, den betreffenden Code-Schnipsel so weit "abzuspecken", dass er ohne den eventuell viel größeren Rest des Scripts läuft.

Link to post
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[Windows.Forms.Application]::EnableVisualStyles()

$PS_Symbol   = [Drawing.Icon]::ExtractAssociatedIcon((Get-Command powershell).Path)
$Schrift = New-Object System.Drawing.Font("Arial",10,[System.Drawing.FontStyle]::Regular)

########## ──────────────────── Start Bereich-Definitionen ──────────────────── ##########


# ─────────────── Start Hauptfenster
$Hauptfenster    = New-Object System.Windows.Forms.Form

# Ende Hauptfenster ─────────────── #

# ─────────────── Start Hauptmenü
$Hauptmenue      = New-Object System.Windows.Forms.MenuStrip
$Statusleiste    = New-Object System.Windows.Forms.StatusStrip
$statustext      = New-Object System.Windows.Forms.ToolStripStatusLabel

# Ende Hauptmenü ─────────────── #


# ─────────────── Start Menüfunktionen
$menue_Datei     = New-Object System.Windows.Forms.ToolStripMenuItem
$menue_System    = New-Object System.Windows.Forms.ToolStripMenuItem
$menue_Netzwerk  = New-Object System.Windows.Forms.ToolStripMenuItem
$menue_Domain    = New-Object System.Windows.Forms.ToolStripMenuItem
$menue_Weblinks  = New-Object System.Windows.Forms.ToolStripMenuItem

# Ende Menüfunktionen ─────────────── #


# ─────────────── Start Unterpunkte-Menüfunktionen ─────────────── #

# ────────── Start Menü-Datei
$menueBeenden           = New-Object System.Windows.Forms.ToolStripMenuItem
$menueDateisuche        = New-Object System.Windows.Forms.ToolStripMenuItem
$menueDateiinhalt       = New-Object System.Windows.Forms.ToolStripMenuItem

# Ende Menü-Datei ────────── #

# ────────── Start Menü-System
$menueZeitServerTest        = New-Object System.Windows.Forms.ToolStripMenuItem
$menueZeitServerFestlegen   = New-Object System.Windows.Forms.ToolStripMenuItem
$menueDISM                  = New-Object System.Windows.Forms.ToolStripMenuItem

# Ende Menü-System ────────── #

# ────────── Start Menü-Netzwerk
$menuePing           = New-Object System.Windows.Forms.ToolStripMenuItem

# Ende Menü-Netzwerk ────────── #

# ────────── Start Menü-Domain
$menueFSR_DFS_Migration           = New-Object System.Windows.Forms.ToolStripMenuItem

# Ende Menü-Domain ────────── #

# ────────── Start Menü-Weblinks
$menueFSR_DFS_Migration           = New-Object System.Windows.Forms.ToolStripMenuItem

# Ende Menü-Weblinks ────────── #


# ─────────────── Ende Unterpunkte-Menüfunktionen ─────────────── #


# ─────────────── Start Import-Symbole ─────────────── #

$Import = @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace System
{
	public class IconExtractor
	{

	 public static Icon Extract(string file, int number, bool largeIcon)
	 {
	  IntPtr large;
	  IntPtr small;
	  ExtractIconEx(file, number, out large, out small, 1);
	  try
	  {
	   return Icon.FromHandle(largeIcon ? large : small);
	  }
	  catch
	  {
	   return null;
	  }

	 }
	 [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
	 private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);

	}
}
"@

Add-Type -TypeDefinition $Import -ReferencedAssemblies System.Drawing

# ─────────────── Ende Import-Symbole ─────────────── #

########## ──────────────────── Ende Bereich-Definitionen ──────────────────── ##########




########## ──────────────────── Start Bereich-Funktionen ──────────────────── ##########

# ─────────────── Start Hauptfenster Setup
$Hauptfenster.Icon            = $PS_Symbol
$Hauptfenster.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::SizableToolWindow
$Hauptfenster.MainMenuStrip   = $Hauptmenue
$Hauptfenster.Height          = 600
$Hauptfenster.Width           = 1000
$Hauptfenster.StartPosition   = "CenterScreen"
$Hauptfenster.TopMost         = $true
$Hauptfenster.Text            = "Probi Tool"
$Hauptfenster.Font            = $Schrift
$Hauptfenster.Controls.Add($Hauptmenue)

# Ende Hauptfenster Setup ─────────────── #

# ─────────────── Start Statusbalken
[void]$Statusleiste.Items.Add($Statustext)
$Statustext.AutoSize  = $true
$Statustext.Text      = "Bereit."
$Hauptfenster.Controls.Add($Statusleiste)

# Ende Statusbalken ─────────────── #


##### ──────────────────── Start Menüleiste Setup ──────────────────── #####

[void]$Hauptfenster.Controls.Add($Hauptmenue)


# ─────────────── Menüleiste - Datei
$menue_Datei.Text = "&Datei"
[void]$Hauptmenue.Items.Add($menue_Datei)

# ─────────────── Menüleiste - System
$menue_System.Text = "&System"
[void]$Hauptmenue.Items.Add($menue_System)

# ─────────────── Menüleiste - Netzwerk
$menue_Netzwerk.Text = "&Netzwerk"
[void]$Hauptmenue.Items.Add($menue_Netzwerk)

# ─────────────── Menüleiste - Active-Directory
$menue_Domain.Text = "&Active-Directory"
[void]$Hauptmenue.Items.Add($menue_Domain)

# ─────────────── Menüleiste - Active-Directory
$menue_Weblinks.Text = "&Website-Links"
[void]$Hauptmenue.Items.Add($menue_Weblinks)


##--------------- Ende Menüleiste Setup ---------------##


########## ──────────────────── Ende Bereich-Funktionen ──────────────────── ##########



########## ──────────────────── Start Bereich-Programm ──────────────────── ##########

##### ──────────────────── Start Datei-Menüleiste ──────────────────── #####

$menueBeenden.Image = [System.IconExtractor]::Extract("shell32.dll", 27, $true)
$menueBeenden.Text = "&Beenden"
$menueBeenden.Add_Click({$Hauptfenster.Close()})
[void]$menue_Datei.DropDownItems.Add($menueBeenden)

##### ──────────────────── Ende Datei-Menüleiste ──────────────────── #####


##### ──────────────────── Start System-Menüleiste ──────────────────── #####

$menueZeitServerTest.Image = [System.IconExtractor]::Extract("shell32.dll", 265, $true)
$menueZeitServerTest.Text = "&Zeit Server Testen"
$menueZeitServerTest.Add_Click({Funktion-ZeitServer_Test})
[void]$menue_System.DropDownItems.Add($menueZeitServerTest)

##### ──────────────────── Ende System-Menüleiste ──────────────────── #####

########## ──────────────────── Ende Bereich-Programm ──────────────────── ##########




########## ──────────────────── Start Bereich-Funktionen ──────────────────── ##########


##### ──────────────────── Start Funktion-ZeitServer_Test ──────────────────── #####
function Funktion-ZeitServer_Test
	{
	
	# ────────── Start Funktion ZeitServerStart	
		function ZeitServerStart {

			if ($Eigenen_Zeit_Server.Checked -eq $true)
			{$Ausgabe_Ergebniss=w32tm /query /source}
			
				if ($Zeit_Server_Testen.Checked -eq $true)
				{$Ausgabe_Ergebniss=w32tm /stripchart /computer:0.de.pool.ntp.org /samples:5 /dataonly}
				
					if ($Zeit_Server_festlegen.Checked -eq $true)
					{$Ausgabe_Ergebniss=3}

			$ZeitServer_Test_Ausgabe=$Ausgabe_Ergebniss | fl | out-string;
			$Ausgabe_Feld.text=$ZeitServer_Test_Ausgabe
                     }
	# ────────── Ende Funktion ZeitServerStart
					 
					 
	# ────────── Start Auswahlkasten				 
		$AuswahlBox = New-Object System.Windows.Forms.GroupBox
		$AuswahlBox.Location = New-Object System.Drawing.Size(40,50) 
		$AuswahlBox.size = New-Object System.Drawing.Size(320,140) 
		$AuswahlBox.text = "Auswahl-Funktionen" 
		$Hauptfenster.Controls.Add($AuswahlBox) 
	# ────────── Ende Auswahlkasten


	# ────────── Start Auswahlschalter Funktion-ZeitServer_Test
		$Eigenen_Zeit_Server = New-Object System.Windows.Forms.RadioButton
		$Eigenen_Zeit_Server.Location = new-object System.Drawing.Point(25,30)
		$Eigenen_Zeit_Server.size = New-Object System.Drawing.Size(260,20)
		$Eigenen_Zeit_Server.Checked = $true
		$Eigenen_Zeit_Server.Text = "Eigenen Zeit-Server ermitteln"
		$AuswahlBox.Controls.Add($Eigenen_Zeit_Server)
		
		$Zeit_Server_Testen = New-Object System.Windows.Forms.RadioButton
		$Zeit_Server_Testen.Location = new-object System.Drawing.Point(25,65)
		$Zeit_Server_Testen.size = New-Object System.Drawing.Size(260,20)
		$Zeit_Server_Testen.Text = "Test des Zeit-Servers Starten"
		$AuswahlBox.Controls.Add($Zeit_Server_Testen)
		
		$Zeit_Server_festlegen = New-Object System.Windows.Forms.RadioButton
		$Zeit_Server_festlegen.Location = new-object System.Drawing.Point(25,100)
		$Zeit_Server_festlegen.size = New-Object System.Drawing.Size(260,20)
		$Zeit_Server_festlegen.Text = "Neuen Zeit-Server festlegen"
		$AuswahlBox.Controls.Add($Zeit_Server_festlegen)
	# ────────── Ende Auswahlschalter Funktion-ZeitServer_Test


	# ────────── Start Startknopf Funktion-ZeitServer_Test
		$Starten_Knopf = New-Object System.Windows.Forms.Button 
		$Starten_Knopf.Location = New-Object System.Drawing.Size(370,65) 
		$Starten_Knopf.Size = New-Object System.Drawing.Size(90,50) 
		$Starten_Knopf.Text = "Test Starten" 
		$Starten_Knopf.Add_Click({ZeitServerStart}) 
		$Starten_Knopf.Cursor = [System.Windows.Forms.Cursors]::Hand
		$Hauptfenster.Controls.Add($Starten_Knopf) 
	# ────────── Ende Startknopf Funktion-ZeitServer_Test


	# ────────── Start Ausgabe Funktion-ZeitServer_Test
		$Ausgabe_Feld = New-Object System.Windows.Forms.TextBox 
		$Ausgabe_Feld.Location = New-Object System.Drawing.Size(40,195) 
		$Ausgabe_Feld.Size = New-Object System.Drawing.Size(320,140) 
		$Ausgabe_Feld.MultiLine = $True 
	# ────────── Ende Ausgabe Funktion-ZeitServer_Test


		$Ausgabe_Feld.ScrollBars = "Vertical" 
		$Hauptfenster.Controls.Add($Ausgabe_Feld) 
	}
##### ──────────────────── Ende Funktion-ZeitServer_Test ──────────────────── #####
	
########## ──────────────────── Ende Bereich-Funktionen ──────────────────── ##########
[void] $Hauptfenster.ShowDialog()

 

Wenn ich die Funktion "ZeitServerStart" ausserhalb von "Funktion-ZeitServer_Test" habe bekomme ich die Meldung das er mit "$Ausgabe_Feld.text=$ZeitServer_Test_Ausgabe" nichts anfangen kann.

Link to post

OK ... vorher muss ich sagen, dass ich mich überhaupt gar nicht mit GUIs in Powershell beschäftige und auch nicht auskenne, ABER ...  ;-)

 

Du versuchst innerhalb einer Funktion auf eine Eigenschaft eines Objekts zuzugreifen, welches die Funktion nicht kennt. Stattdessen solltest Du einfach den Wert als Rückgabewert der Funktion ausgeben und damit weiterarbeiten.

Also statt:

$Ausgabe_Feld.text = $ZeitServer_Test_Ausgabe

Einfach:

$ZeitServer_Test_Ausgabe

Wie Du das allerdings in Deine GUI eingebaut bekommst, kann ich Dir leider auch nicht sagen. Ich bin aber sicher, dass das einer der anderen Kollegen hier drauf hat ... hab ein bissl Geduld, bitte!   ;-)

  • Like 1
Link to post

Hm - Scope... Ich glaub ich hab das nicht deutlich rübergebracht: Scope, Scope, Scope!

$ZeitServer_Test_Ausgabe=$Ausgabe_Ergebniss | fl | out-string;

Das ist in zweierlei Hinsicht - sorry - Mist. Einerseits zerstörst Du mit "| fl | out-string" jedwede Objekteigenschaften und machst $Ausgabe_Ergebniss zu einem Stringhaufen. Andererseits existiert diese Variable nur INNERHALB ihres Scopes  und das ist diese nested Function. "get-help about_scopes" wäre meine erste Empfehlung in dieser Situation :-)

Und wie Olaf schon schrieb: Wenn Funktionen etwas tun, was dann woanders benötigt wird, dann speichern sie das nicht in Variablen (die dann nur im Funktions-Scope existieren), sondern sie geben es zurück. Entweder per Return $var explizit oder einfach per $var in die Pipeline. Zweiteres klappt aber nur, wenn man darauf achtet, daß man keinen "Kruscht" in die Pipeline schreibt. Weil auch ein simples "Hallo" in ebendieser landet.

Link to post

Einen wunderschönen Guten Morgen allerseits,

 

vorab danke für die ganzen Hilfestellungen.

Ich denke, ich muss mich noch etwas in die Thematik mit Funktionen einlesen, daher habe ich mir etwas anderes überlegt, wie ich es Realisieren könnte (glaube ich zumindest).

 

Wenn ich peer button click eine Funktion Aufrufen kann, dann sollte doch Folgendes auch möglich sein oder.

# ────────── Start Startknopf Funktion-ZeitServer_Test
		$Starten_Knopf = New-Object System.Windows.Forms.Button 
		$Starten_Knopf.Location = New-Object System.Drawing.Size(370,65) 
		$Starten_Knopf.Size = New-Object System.Drawing.Size(90,50) 
		$Starten_Knopf.Text = "Test Starten" 
		$Starten_Knopf.Cursor = [System.Windows.Forms.Cursors]::Hand
		$Starten_Knopf.Add_Click({
								if ($Eigenen_Zeit_Server.Checked)
								{
									$Ausgabe_Ergebniss=w32tm /query /source
									write-host "Der aktuelle Zeitserver ist: "$Ausgabe_Ergebniss
								}
								elseif ($Zeit_Server_Testen.Checked)
								{
									$Ausgabe_Ergebniss=w32tm /stripchart /computer:0.de.pool.ntp.org /samples:5 /dataonly
									write-host "Der Zeitserver Unterschied beträgt: "$Ausgabe_Ergebniss
								}
								else
								{
									$Ausgabe_Ergebniss="Keine Funktion ansgewaehlt!"
								}
							})
		$Hauptfenster.Controls.Add($Starten_Knopf) 
	# ────────── Ende Startknopf Funktion-ZeitServer_Test

 

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...