Несовместимый результат с функцией msgbox в консоли ISE и PowerShell
Я возлюсь с объектом таймера и окнами сообщений и попадаю в кирпичную стену.
Я пытаюсь управлять объектом таймера и всплывающими окнами через многократно используемые функции.
Сначала я протестировал большинство этих функций самостоятельно и небольшими частями. Поскольку все работало, я решил связать все вместе.
Вместе, это не сработало, поэтому я разбил функциональность на основы:
# functionfile
function Show-MsgBox {
Write.Host "debugFUNC2"
#usage:
#Show-MsgBox -Prompt "This is the prompt" -Title "This Is The Title" -Icon Critical -BoxType YesNo -DefaultButton 1
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)] [string]$Prompt,
[Parameter(Position=1, Mandatory=$false)] [string]$Title ="",
[Parameter(Position=2, Mandatory=$false)] [string]$Icon ="Information",
[Parameter(Position=3, Mandatory=$false)] [string]$BoxType ="OkOnly",
[Parameter(Position=4, Mandatory=$false)] [int]$DefaultButton = 1
)
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
switch ($Icon) {
"Question" {$vb_icon = [microsoft.visualbasic.msgboxstyle]::Question }
"Critical" {$vb_icon = [microsoft.visualbasic.msgboxstyle]::Critical}
"Exclamation" {$vb_icon = [microsoft.visualbasic.msgboxstyle]::Exclamation}
"Information" {$vb_icon = [microsoft.visualbasic.msgboxstyle]::Information}
}
switch ($BoxType) {
"OKOnly" {$vb_box = [microsoft.visualbasic.msgboxstyle]::OKOnly}
"OKCancel" {$vb_box = [microsoft.visualbasic.msgboxstyle]::OkCancel}
"AbortRetryIgnore" {$vb_box = [microsoft.visualbasic.msgboxstyle]::AbortRetryIgnore}
"YesNoCancel" {$vb_box = [microsoft.visualbasic.msgboxstyle]::YesNoCancel}
"YesNo" {$vb_box = [microsoft.visualbasic.msgboxstyle]::YesNo}
"RetryCancel" {$vb_box = [microsoft.visualbasic.msgboxstyle]::RetryCancel}
}
switch ($Defaultbutton) {
1 {$vb_defaultbutton = [microsoft.visualbasic.msgboxstyle]::DefaultButton1}
2 {$vb_defaultbutton = [microsoft.visualbasic.msgboxstyle]::DefaultButton2}
3 {$vb_defaultbutton = [microsoft.visualbasic.msgboxstyle]::DefaultButton3}
}
$popuptype = $vb_icon -bor $vb_box -bor $vb_defaultbutton
$ans = [Microsoft.VisualBasic.Interaction]::MsgBox($prompt,$popuptype,$title)
return $ans
} #end function
function mafunc {
Write-Host "debugFUNC1"
$timer.start()
$timer
return 0
}
# calling file
$timer = New-Object System.Timers.Timer
#$timer.interval = 1800000
$timer.interval = 30000
$timer.Enabled = $true
$timer.AutoReset = $False
$scriptsleep = 0
$timer.stop()
$ThirtyAction = {
Write-Host "action"
Write-Host "action2"
if ((Show-MsgBox -Prompt "prompt" -Title "title" -Icon Critical -BoxType YesNo -DefaultButton 1) -eq "No") {
Write-Host "debugNO"
} else {
Write-Host "debugYES"
$timer
$timer.stop()
Show-MsgBox -Prompt "prompt" -Title "title" # standard promt = OKonly button
$timer.interval=30000
$timer.start()
$timer
Write-Host "timer start"
}
}
Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier ThirtySecTimer -Action $ThirtyAction
myfunc
Я все еще не могу запустить скрипт, так как он продолжает зависать во время действия Elapsed ($Thirtyaction
). Последнее, что он показывает в консоли PowerShell: action
а также action2
, Итак, я решил, что проблема заключается в функции box, но:
- если я вызову скрипт с ISE, он запустится как положено
- если я сначала выполню функциональный файл, а затем файл, он снова остановится / зависнет на (сначала /YesNo) msgBox
- если я вручную ввожу функцию msgBox в консоль и затем запускаю файл, он покажет msgBoxes, но не выполнит код в
else
оператор правильно (останавливается после того, как (секунд /OKonly)msgBox был показан)
Я не могу придумать, каким образом это имеет смысл, и я потратил много времени, пытаясь отлаживать / переключать его / тупить и т.д.
edit1: свежий день и немного больше информации.
Я изменил функцию на windows.Forms, но не повезло. Затем я приступил к печати идентификаторов потоков для всех функций и частей сценария и вуаля:
Main script
6
1176
myfunc
6
1176
Elapsedaction ($Thirtyaction)
11
4236
$action
это срабатывает, когда срабатывает Timerevent, запускается в новом пространстве выполнения PowerShell и, следовательно, больше не имеет доступа к переменным и функциям, которые были определены ранее.
Я не уверен, как это исправить или обойти это, но по крайней мере я знаю, в чем проблема. Любые идеи приветствуются и спасибо ппл, который уже ответил и дал мне подсказку в правильном направлении!
Edit2 с решением и обходным путем:
спасибо другому пользователю, если нашел ответ на вопрос о том, как управлять атрибутами таймера изнутри $Thirtyaction
ScriptBlock:
Я могу использовать функцию MsgBox, просто поставив файл функции в блоке скриптов
Мой обходной путь для переменных состоял в том, чтобы использовать три переменные окружения. Я уверен, что это не умная и не лучшая практика, но это не должно быть проблемой в моем особом случае, и это работает.
в качестве примера вот мой ток $Thirtyaction
ScriptBlock:
$ThirtyAction={
. .\testfunction.ps1
$Sender.stop()
Write-Host "action"
Write-Host "action2"
if ((($ans=(Show-new-MsgBox -Prompt "Prompt" -Title "Title" -Icon "Warning" -BoxType "YesNo")) -eq "No") -or !($Env:Sessionsleepstate -eq 0)) {
Write-Host $Env:Sessionsleepstate
$Env:Sessionsleepstate = 3
if ($Env:Sessionsleepstate -eq 1) {
Show-new-MsgBox -Prompt "Prompt" -Title "Title"
}
Show-new-MsgBox -Prompt "Prompt" -Title "Title"
Write-Host "killfunction placeholder"
}
else{
$Sender.stop()
Show-new-MsgBox -Prompt "Prompt" -Title "Title"
$Sender.interval=300000
$Env:Sessionsleepstate = 1
$Sender.start()
Write-Host "timer start"
}
}
1 ответ
Как интересно... Я проверил несколько проверок.
Сначала я думал, что доступ к GUI будет просто заблокирован из окна консоли. Но я обнаружил, что окно сообщения отображается очень хорошо, если вы вызываете его прямо вверх (не из функции таймера) примерно так:
Add-Type -AssemblyName "Microsoft.VisualBasic"
[Microsoft.VisualBasic.Interaction]::MsgBox("MyPrompt",[microsoft.visualbasic.msgboxstyle]::OKOnly,"title")
Тогда я подумал, что это может быть многопоточность: в консоли таймер будет вызывать функцию в другом потоке, а сборка VisualBasic будет игнорировать или отклонять ее. Но я нашел
Write-Host ([System.Threading.Thread]::CurrentThread).ManagedThreadId
Write-Host ([System.AppDomain]::GetCurrentThreadId())
дал одинаковые значения в основном коде или в функции, вызываемой таймером.
Тогда я подумал, что сборка может быть недоступна из функции таймера. Но я нашел это призвание
([Microsoft.VisualBasic.Interaction]::Beep())
работал нормально из окна консоли.
Так что это просто странно. Однако, кажется, есть простой обходной путь: если вы используете System.Windows.Forms.MessageBox, он работает должным образом:
Add-Type -AssemblyName System.Windows.Forms
$Result = [System.Windows.Forms.MessageBox]::Show('Now I''ll be a son of a gun...', 'How about that?', 'YesNo', 'Warning')