Power Shell
Zuletzt geändert: 04.03.2026 17:07

PowerShell aus einem Menüpunkt starten #

Menüpunkte lassen sich innerhalb von EULANDA® sehr einfach als Actions in der SQL-Registry zufügen. Dort wiederum lässt sich als CommandText ein VbScript hinterlegen, welches wiederum ein externes PowerShell-Skript aufrufen kann.

Hierzu legt man in der SQL-Registry einen Ordner an unter:

ROOT\OBJECTS\DATAOBJECTS\Eulanda.Adresse\Actions

Über die Rechte Mausoption auf dem Actions-Ordner dann auf Neu einen neuen Schlüssel anlegen. In der Auswahl wählt man iScript-Menübefehl aus, geben Sie einen Namen ein, z.B. user.MeinPowerShellAufruf. Auf der rechten Seite werden dann alle Felder angelegt. Das VbScript wird in den CommandText gelegt.

Das eigentliche Skript, welches an Ihre Funktion angepasst werden muss, ist nur der Abschnitt Main. Aber sie fügen immer das Komplette Skript wie angegeben ein und ändern dann den Main-Abschnitt nach Ihren Bedürfnissen ab.

Hinweis

Bei Nutzung des Befehls Clear-Host gibt es eine Exception, wenn das PowerShell-Skript von EULANDA® gestartet wird. Dies hängt damit zusammen, dass es, wenn die Ausgabe über eine Pipe umgeleitet wird, kein Konsolen-Host verfügbar ist. Notwendig ist die Umleitung, um die Meldungen und Fehler in EULANDA® anzeigen zu können.

sub main(id)
    Dim command, strOutput, strError
    
    command = CommandScript("C:\users\johndoe\desktop\pwtest.ps1")
    command = Append(command, "-udl", """X:\Eulanda_1 MyCompany.udl""")
    command = Append(command, "-deliveryId", id)

    call Powershell(command, true, 30, strOutput, strError)
end sub

Überschreiben Sie den kompletten Inhalt und fügen Sie folgendes Skript ein:

option explicit


Sub Popup(sec)
    Dim WshShell, fso, tempFolder, tempFilePath, file
    Dim vbscriptCode

    if sec > 0 then
        vbscriptCode = "Dim message, WshShell" & vbCrLf & _                        
            "Set WshShell = CreateObject(""WScript.Shell"")" & vbCrLf & _
            "message = ""Bitte warten, die Verarbeitung kann bis zu '" & sec & "' Sekunden dauern...""" & vbCrLf & _
            "firstRun = False" & vbCrLf & _
            "Do" & vbCrLf & _
            "    If Not firstRun Then WshShell.Popup message, " & sec & " , ""Info-Popup"", 0" & vbCrLf & _
            "    WScript.Sleep 10" & vbCrLf & _
            "    firstRun = True" & vbCrLf & _
            "Loop While WshShell.AppActivate(""ShowPopup.vbs"")"

        Set fso = CreateObject("Scripting.FileSystemObject")
        tempFolder = fso.GetSpecialFolder(2)  ' 2 steht für den temporären Ordner
        If Not fso.FolderExists(tempFolder) Then
            fso.CreateFolder(tempFolder)
        End If
        tempFilePath = fso.BuildPath(tempFolder, "ShowPopup.vbs")

        Set file = fso.CreateTextFile(tempFilePath, True)
        file.Write vbscriptCode
        file.Close
        Set WshShell = CreateObject("WScript.Shell")
        WshShell.Run "wscript.exe " & tempFilePath, 0, false
    end if
End Sub



Function ConvertUmlaute(strInput)
    Dim strOutput
    strOutput = ""

    Dim i
    For i = 1 To Len(strInput)
        Dim character
        character = Mid(strInput, i, 1)

        Dim asciiValue
        asciiValue = AscW(character)

        Select Case asciiValue
            Case 8482
                character = "Ö"
            Case 381
                character = "Ä"
            Case 353
                character = "Ü"
            Case 8221
                character = "ö"
            Case 8222
                character = "ä"
            Case 129
                character = "ü"
            Case 225
                character = "ß"
            case 184
                character = "©"    
            case 169
                character = "®"    
        End Select        
        strOutput = strOutput & character
    Next

    ConvertUmlaute = strOutput
End Function


Function RemoveAnsiCodes(str)
    Dim regex

    Set regex = New RegExp
    regex.Pattern = "\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]"
    regex.Global = True
    RemoveAnsiCodes = regex.Replace(str, "")
End Function

Function TrimCrLf(ByVal str)
    ' Führende Zeilenumbrüche und Leerzeichen entfernen
    Do While Left(str, 2) = vbCrLf Or Left(str, 1) = vbLf Or Left(str, 1) = " "
        If Left(str, 2) = vbCrLf Then
            str = Mid(str, 3)
        ElseIf Left(str, 1) = vbLf Then
            str = Mid(str, 2)
        Else
            str = Trim(Mid(str, 2))
        End If
    Loop

    ' Nachfolgende Zeilenumbrüche und Leerzeichen entfernen
    Do While Right(str, 2) = vbCrLf Or Right(str, 1) = vbLf Or Right(str, 1) = " "
        If Right(str, 2) = vbCrLf Then
            str = Left(str, Len(str) - 2)
        ElseIf Right(str, 1) = vbLf Then
            str = Left(str, Len(str) - 1)
        Else
            str = Trim(Left(str, Len(str) - 1))
        End If
    Loop

    TrimCrLf = str
End Function


Function GetOutput(Message)
    Dim output
    output = ""

    Dim line, lines
    lines = Split(Message, vbCrLf)

    For Each line In lines
        ' Prüfen, ob die Zeile nicht mit "Write-Error:" beginnt
        If (Left(line, 12) <> "Write-Error:") and  (Left(line, 14) <> "ERROR Message:") Then
            output = output & vbCrLf & Trim(line)            
        End If
    Next

    output = TrimCrLf(output)
    GetOutput = output
End Function


Function GetError(Message)
    Dim errors
    errors = ""

    Dim line, lines
    lines = Split(Message, vbCrLf)

    For Each line In lines
        If Left(line, 12) = "Write-Error:" Then
            errors = errors & vbCrLf & Trim(Mid(line, 13))
        elseif Left(line, 14) = "ERROR Message:" Then 
            errors = errors & vbCrLf & Trim(Mid(line, 15))
        End If
    Next

    errors = TrimCrLf(errors)
    GetError = errors
End Function



Function Append(strBase, strAppend1, strAppend2)
    If (strBase <> "") And (Right(strBase, 1) <> " ") Then
        strBase = strBase & " "
    End If
    strBase = strBase & strAppend1
    If strAppend2 <> "" Then
        strBase = strBase & " " & strAppend2
    End If
    Append = strBase
End Function


function CommandScript(strScript)
    Const quotes = """"
    dim strBase
    strBase = "pwsh.exe -windowstyle hidden -nologo -noprofile -ExecutionPolicy Bypass -File"
    CommandScript = Append("", strBase, quotes & strScript & quotes)
end function


function CommandInline(str)
    dim strBase
    strBase = "pwsh.exe -windowstyle hidden -nologo -noprofile -ExecutionPolicy Bypass --Command"
    Command = strBase & " " & str
    ' Beispielaufruf dieser Funktion
    ' CommandInline("try {throw 'Das ist eine Exception mit Umlaut ÖÄÜ!'} catch {Write-Output $_.Exception.Message; exit 99}")
end function


Function IsPwshInstalled()
    Dim WshShell, strPwsh

    Set WshShell = CreateObject("WScript.Shell")
    On Error Resume Next
    strPwsh = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\pwsh.exe\")
    On Error GoTo 0
    Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
    If fso.FileExists(strPwsh) Then
        IsPwshInstalled = True
    Else
        IsPwshInstalled = False
    End If
End Function


dim top

sub PowerShell(CommandLine, MsgOnSuccess, sec, ByRef strOutput, ByRef strError)
    ' 1. Parameter = Aufruf mit pwsh, Standard-Switches und Skript sowie Skript-Parameter
    ' 2. Parameter = bei Erfolg keine Meldung anzeigen
    ' 3. Parameter = Wartezeit in Sekunden für das Popup. Zeigt an, dass noch etwas passiert. Bei 0 erscheint kein Popup

    ' Popup wird im Hintergrund aufgerufen, um über den langsamen Ladevorgang von PowerShell zu informieren
    Popup(sec)

    Dim fso, WshShell, tempFileName, file, line, strCommon, result
    Const TemporaryFolder = 2
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set WshShell = CreateObject("WScript.Shell")

    tempFileName = fso.GetSpecialFolder(TemporaryFolder) & "\" & fso.GetTempName                       
    CommandLine = "%comspec% /c """ & CommandLine & " > " & tempFileName & " 2>&1" & """"
    ' RUN verwenden, weil es das Fenster versteckt; Nebeneffekt: unterstützt kein stdErr
    Top = top & "Now22 = " & Now
    result = WshShell.Run(CommandLine, 0, true)


    ' Ausgabe aus der temporären Datei lesen
    Set file = fso.OpenTextFile(tempFileName, 1)
    strOutput = ""
    strError = ""
    Do Until file.AtEndOfStream
    strOutput = strOutput & file.ReadLine() & vbCrLf
    Loop
    file.Close()
    fso.DeleteFile(tempFileName)
    strOutput = ConvertUmlaute(strOutput)
    strOutput = RemoveAnsiCodes(strOutput)
    strError = GetError(strOutput)
    strOutput = GetOutput(strOutput)
    if strOutput <> "" then strCommon = "Output:" & vbCrLf & strOutput else strCommon = ""         
        if strError <> "" then strCommon = Trim(strCommon & vbCrLf & vbCrlf & "Error(s):" & vbCrlf & strError)
     
    if result <> 0 Then         
                ellib.showMessage(strCommon & vbCrLf & vbCrLf & "Errorcode: " & result )
    Else
        If MsgOnSuccess Then
            ellib.showMessage(strOutput)
        End if
    end if
end sub


sub main(id)
    Dim command, strOutput, strError
    
    command = CommandScript("C:\users\johndoe\desktop\pwtest.ps1")
    command = Append(command, "-udl", """X:\Eulanda_1 MyCompany.udl""")
    command = Append(command, "-deliveryId", id)

    call Powershell(command, true, 30, strOutput, strError)
end sub


Main(1)

Die Sub-Routine main, ist diejenige, die man nur anpassen muss. Legen Sie das PowerShell-Skript auf den Desktop und passen Sie dessen Namen an. Hier im Beispiel heißt es psTest.ps1. Mit Append lassen sich an den String command jeweils Parameter Pärchen anfügen. Diese hängen von Ihrem Skript ab. Wird nur ein Switch benötigt, dann lassen sie in Append den zweiten Wert leer (zwei Anführungszeichen).

Der Powershell-Aufruf erfolgt über einen Call-Aufruf. Der erste Parameter ist die vollständige Kommandozeile, der zweite besagt, dass bei Erfolg eine Messagebox angezeigt werden soll, und der dritte Parameter gibt ein Timeout an. Da der Aufruf einige Sekunden in Anspruch nehmen kann, wird eine Splash-Box im Hintergrund angezeigt, die innerhalb des PowerShell-Skripts mit Stop-Popup jederzeit abgeschaltet werden kann, spätestens eben nach dem Timeout.

Bei einem Fehler mit Fehlercode wird eine Message-Box angezeigt. Treten ansonsten Fehler oder Meldungen auf, erhält man diese nach dem Aufruf in den Variablen strOutput und strError.

Am Ende des Dokuments finden Sie eine entsprechende PowerShell-Datei zum Testen.

[cmdletbinding()]
Param(
    [string]$udl,
    [int]$deliveryId
)

function Start-Popup {
    param (
        [Parameter(Mandatory=$true)]
        [int]$sec
    )

    if ($sec -gt 0) {
        $vbscriptCode = @'
        Dim message, WshShell
        Set WshShell = CreateObject("WScript.Shell")
        message = "Bitte warten, die Verarbeitung kann bis zu '{0}' Sekunden dauern..."
        firstRun = False
        Do
            If Not firstRun Then WshShell.Popup message, {0} , "Info-Popup", 0
            WScript.Sleep 10
            firstRun = True
        Loop While WshShell.AppActivate("ShowPopup.vbs")

'@ -f $sec

        $tempFolder = [System.IO.Path]::GetTempPath()
        $tempFilePath = Join-Path -Path $tempFolder -ChildPath "ShowPopup.vbs"

        try {
            $vbscriptCode | Out-File -FilePath $tempFilePath -Force
            Start-Process -FilePath "wscript.exe" -ArgumentList $tempFilePath -WindowStyle Hidden
        } catch {
            Write-Error "Fehler beim Erstellen und Ausführen des VBScript: $_"
        }

    }
}


function Stop-Popup {
    param ()

    $windowTitle = "Info-Popup"
    $process = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle }
    if ($process) {
        Stop-Process -Id $process.Id
    }
}


try {
    Clear-Host -ErrorAction SilentContinue
}
catch {
    <#
        Wenn Clear-Host aufgerufen wird, aber das Skript über eine Pipe läuft,
        liefert Clear-Host eine Exception wie 'Cannot bind argument to parameter
        Path because it is an empty string'. Das passiert besonders, wenn das
        ps1-Skript von EULANDA aufgerufen wird, weil dort die Ausgabe immer
        über eine Pipe zurückgelesen wird. Clear-Host sollte in jedem Fall
        in einem eigenen try/catch-Block stehen.
    #>
}

# Alternativ steht eine identische Funktion zur Anzeige eines Popups mit Start-Popup zur Verfügung
# Start-Popup -sec 5

write-error "Erster Fehler"

Write-Host "Udl: $udl"
Write-Host "DeliveryId: $deliveryId"
Write-Verbose "Verbose is on"

start-sleep -Seconds 3

try {
    write-error "Das ist ein Umlaut-Test: ÖÄÜ"
}
catch {
    $ErrorMessage = $_.Exception.Message
    # Fehlermeldungen ausgeben
    # Write-Error $ErrorMessage
}
finally {
	<#
  		Es schadet nicht, den Befehl Stop-Popup im finally-Block aufzurufen.
  		Besonders bei einer Exception wird das Popup sofort ausgeblendet.
  		Zusätzlich sollte der Befehl vor dem ersten Dialog aufgerufen werden,
  		damit das Popup dann ebenfalls ausgeblendet wird.
	#>
	Stop-Popup
}

# Wenn ein Exit-Code > 0 gesetzt wird, wird der Fehler immer in EULANDA angezeigt
# Exit 99