Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 18 additions & 37 deletions adapters/powershell/psDscAdapter/powershell.resource.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ $ps = [PowerShell]::Create().AddScript({
[string]$ScriptRoot
)

trap {
Write-Error ($_ | Format-List -Force | Out-String)
}

# NOTE:
# The adapter explicitly suppresses Debug and Verbose output by default to avoid
# excessively noisy logs from DSC resources that call Write-Debug / Write-Verbose.
Expand All @@ -85,7 +81,7 @@ $ps = [PowerShell]::Create().AddScript({
# an example of this pattern.
$DebugPreference = 'SilentlyContinue'
$VerbosePreference = 'SilentlyContinue'
$ErrorActionPreference = 'Continue'
$ErrorActionPreference = 'Stop'
$InformationPreference = 'Continue'
$ProgressPreference = 'SilentlyContinue'

Expand Down Expand Up @@ -369,83 +365,68 @@ $traceLevel = if ($env:DSC_TRACE_LEVEL) {
[DscTraceLevel]::Warn
}

$null = Register-ObjectEvent -InputObject $ps.Streams.Error -EventName DataAdding -MessageData @{traceQueue=$traceQueue; hadErrors=$hadErrors} -Action {
$null = Register-ObjectEvent -SourceIdentifier 'PSAdapter.Error' -InputObject $ps.Streams.Error -EventName DataAdding -MessageData @{traceQueue=$traceQueue; hadErrors=$hadErrors} -Action {
$traceQueue = $Event.MessageData.traceQueue
# convert error to string since it's an ErrorRecord
$traceQueue.Enqueue(@{ error = [string]$EventArgs.ItemAdded })
$Event.MessageData.hadErrors.Enqueue($true)
}

if ($traceLevel -ge [DscTraceLevel]::Warn) {
$null = Register-ObjectEvent -InputObject $ps.Streams.Warning -EventName DataAdding -MessageData $traceQueue -Action {
$traceQueue = $Event.MessageData
$null = Register-ObjectEvent -SourceIdentifier 'PSAdapter.Warning' -InputObject $ps.Streams.Warning -EventName DataAdding -MessageData @{traceQueue=$traceQueue} -Action {
$traceQueue = $Event.MessageData.traceQueue
$traceQueue.Enqueue(@{ warn = $EventArgs.ItemAdded.Message })
}
}

if ($traceLevel -ge [DscTraceLevel]::Info) {
$null = Register-ObjectEvent -InputObject $ps.Streams.Information -EventName DataAdding -MessageData $traceQueue -Action {
$traceQueue = $Event.MessageData
$null = Register-ObjectEvent -SourceIdentifier 'PSAdapter.Information' -InputObject $ps.Streams.Information -EventName DataAdding -MessageData @{traceQueue=$traceQueue} -Action {
$traceQueue = $Event.MessageData.traceQueue
if ($null -ne $EventArgs.ItemAdded.MessageData) {
$traceQueue.Enqueue(@{ info = [string]$EventArgs.ItemAdded.MessageData })
}
}
}

if ($traceLevel -ge [DscTraceLevel]::Debug) {
$null = Register-ObjectEvent -InputObject $ps.Streams.Verbose -EventName DataAdding -MessageData $traceQueue -Action {
$traceQueue = $Event.MessageData
$null = Register-ObjectEvent -SourceIdentifier 'PSAdapter.Debug' -InputObject $ps.Streams.Verbose -EventName DataAdding -MessageData @{traceQueue=$traceQueue} -Action {
$traceQueue = $Event.MessageData.traceQueue
# Verbose messages tend to be in large quantity and more useful to developers, so log as Debug
$traceQueue.Enqueue(@{ debug = $EventArgs.ItemAdded.Message })
}
}

if ($traceLevel -ge [DscTraceLevel]::Trace) {
$null = Register-ObjectEvent -InputObject $ps.Streams.Debug -EventName DataAdding -MessageData $traceQueue -Action {
$traceQueue = $Event.MessageData
$null = Register-ObjectEvent -SourceIdentifier 'PSAdapter.Trace' -InputObject $ps.Streams.Debug -EventName DataAdding -MessageData @{traceQueue=$traceQueue} -Action {
$traceQueue = $Event.MessageData.traceQueue
# Debug messages may contain raw info, so log as Trace
$traceQueue.Enqueue(@{ trace = $EventArgs.ItemAdded.Message })
}
}
$outputObjects = [System.Collections.Generic.List[Object]]::new()

try {
$asyncResult = $ps.BeginInvoke()
# This while loop with sleep must remain so that registered object events
# can take over the pipeline thread.
while (-not $asyncResult.IsCompleted) {
Write-TraceQueue

Start-Sleep -Milliseconds 100
}
$outputCollection = $ps.EndInvoke($asyncResult)
Write-TraceQueue

if ($ps.HadErrors) {
# Anything written to stderr sets this flag, so we'll write a debug trace, but not treat as error
Write-DscTrace -Now -Operation Debug -Message 'HadErrors set during script execution.'
}

foreach ($output in $outputCollection) {
$outputObjects.Add($output)
}
$outputCollection = $ps.EndInvoke($asyncResult)
}
catch {
Write-DscTrace -Now -Operation Error -Message $_
Write-TraceQueue
exit 1
}
finally {
$ps.Dispose()
Get-EventSubscriber | Unregister-Event
}

# Allow any remaining event handlers time to enqueue to $traceQueue and $hadErrors
Start-Sleep -Milliseconds 200
if ($hadErrors.Count -gt 0) {
Write-DscTrace -Now -Operation Error -Message 'Errors were captured during script execution. Check previous error traces for details.'
exit 1
Write-DscTrace -Now -Operation Debug -Message 'Errors were captured during script execution. Check previous error traces for details.'
}
Comment thread
SteveL-MSFT marked this conversation as resolved.

foreach ($obj in $outputObjects) {
Start-Sleep -Milliseconds 200 # wait a bit to ensure all events are processed before unregistering
Get-EventSubscriber | Where-Object { $_.SourceIdentifier -like 'PSAdapter.*' } | ForEach-Object { Unregister-Event -SourceIdentifier $_.SourceIdentifier } # unregister before dispose
Write-TraceQueue

foreach ($obj in $outputCollection) {
$obj | ConvertTo-Json -Depth 10 -Compress
}
Loading