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-Hostgibt 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