Я пытаюсь написать скрипт для отслеживания хода выполнения WIM - пока я использовал этот пример оболочки WimgAPI: https://managedwimgapi.codeplex.com/wikipage?title=Using%20the%20message%20callback %20functionality %20for %20recieving %20progress %20and %20Разный %20information & referringtitle= документация
Которое я превратил в Powershell:
Add-Type -Path "Microsoft.Wim.dll"
# Open a handle to the .wim file
$wimHandle = [Microsoft.Wim.WimgApi]::CreateFile("G:\sources\boot.wim", '
[Microsoft.Wim.WimFileAccess]::Read,[Microsoft.Wim.WimCreationDisposition]::OpenExisting, '
[Microsoft.Wim.WimCreateFileOptions]::None, [Microsoft.Wim.WimCompressionType]::None)
# Always set temporary path
[Microsoft.Wim.WimgApi]::SetTemporaryPath($wimHandle, $env:temp) | Out-Null
# Build & register a callback method for actions which are performed by WIMGAPI for this .wim file
$callback = [Microsoft.Wim.WimMessageCallback]{
param (
[Microsoft.Wim.WimMessageType] $messageType,
[System.Object] $message,
[System.Object] $userData
)
if($messageType -eq [Microsoft.Wim.WimMessageType]::Progress)
{
$progressMessage = ($message -as [Microsoft.Wim.WimMessageProgress])
Write-Host "Percent Complete: $($progressMessage.PercentComplete)"
}
return [Microsoft.Wim.WimMessageResult]::Success
}
[Microsoft.Wim.WimgApi]::RegisterMessageCallback($wimHandle, $callback) | Out-Null
try
{
# Get a handle to the first image in the .wim file
$imageHandle = [Microsoft.Wim.WimgAPI]::LoadImage($wimHandle, 1)
# Apply the contents to C:\Apply
[Microsoft.Wim.WimgApi]::ApplyImage($imageHandle, "C:\Apply", [Microsoft.Wim.WimApplyImageOptions]::None)
Read-Host
}
catch
{
Write-Host $_.Exception
}
finally
{
[Microsoft.Wim.WimgApi]::UnregisterMessageCallback($wimHandle, $callback) | Out-Null
}
Код выполняется успешно, и WIM применяется, но, к сожалению, я вижу, что callback выполняется дважды, например:
Percent Complete: 0
Percent Complete: 100
Хотя при выполнении приложения С# я вижу каждое процентное значение от нуля до 100.
Я думаю, что это может иметь какое-то отношение к тому факту, что ApplyImage является блокирующим вызовом и, следовательно, может блокировать консоль от выполнения обратного вызова, хотя я не могу придумать никакого способа обойти это.
Любые мысли были бы весьма признательны. Благодарю!
Я написал CmdLet в С#, который будет применять образ *.wim
к местоположению и подтолкнул его к GitHub и создал пакет Nuget.
https://github.com/dennisroche/Microsoft.Wim.Powershell
Сначала я начал писать CmdLet, так как мне удалась быстрая демонстрация С#, которая записывала прогресс% в консоль и считала, что CmdLet может быть решением (раньше я не писал CmdLet).
При написании CmdLet я обнаружил, что PowerShell выбрасывал InvalidOperationException
при попытке записи (например, Write-Host
, Write-Progress
). Глядя далее на MSDN, я нашел следующее:
Этот метод может быть вызван только из реализации способа обработки входного сигнала (
BeginProcessing
,ProcessRecord
иEndProcessing
) и только из этого потока. Если вызов выполняется извне этих реализаций или из другого потока,InvalidOperationException
исключениеInvalidOperationException
.
Это объясняет, почему он не работал при вызове непосредственно в Powershell - обратный вызов был в другом потоке, и его нужно было вызвать обратно в потоке Pipeline Execution Thread
. Хотя по некоторым причинам первые и последние события прогресса были в Pipeline Execution Thread
, поэтому мы видели результат, который мы сделали.
Я нашел интересное решение для вызова сообщений о ходе обновления в AsyncOperationManager
Pipeline Execution Thread
, используя AsyncOperationManager
, WindowsFormsSynchronizationContext
и Application.DoEvents()
. Если вы нашли этот ответ в этом сообщении об ошибке, посмотрите на код GitHub.