Reputation: 45
I am currently trying to import a .psm1 file dynamically into a script block to execute it.
I am using parallelisation along with jobs as I need to trigger several modules simultaneously as different users.
This is the code:
$tasksToRun | ForEach-Object -Parallel {
$ScriptBlock = {
param ($scriptName, $Logger, $GlobalConfig, $scriptsRootFolder )
Write-Output ("hello $($scriptsRootFolder)\tasks\$($scriptName)")
Import-Module ("$($scriptsRootFolder)\tasks\$($scriptName)")
& $scriptName -Logger $Logger -GlobalConfig $GlobalConfig
}
$job = Start-Job -scriptblock $ScriptBlock `
-credential $Cred -Name $_ `
-ArgumentList ($_, $using:Logger, $using:globalConfig, $using:scriptsRootFolder) `
Write-Host ("Running task $_")
$job | Wait-job -Timeout $using:timeout
if ($job.State -eq 'Running') {
# Job is still running, stop it
$job.StopJob()
Write-Host "Stopped $($job.Name) task as it took too long"
}
else {
# Job completed normally, get the results
$job | Receive-Job
Write-Host "Finished task $($job.Name)"
}
}
The logger variable is a hashtable as defined here:
$Logger = @{
generalLog = $function:Logger
certificateLog = $function:LoggerCertificate
alertLog = $function:LoggerAlert
endpointServiceLog = $function:LoggerEndpointService
}
Currently, it is erroring with the following:
ObjectNotFound: The term
' blah blah blah, this is the code straight from the logger function '
is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
The logger function servers the purpose of logging to a file in a specific way, it is generalised to that it can be used across many tasks.
A cut down example of a logger (probably won't compile, just deleted a bunch of lines to give you the general idea):
function LoggerEndpointService {
param (
# The full service name.
[string]$ServiceFullName,
# The unique identifier of the service assigned by the operating system.
[string]$ServiceId,
# The description of the service.
[string]$Description,
# The friendly service name.
[string]$ServiceFriendlyName,
# The start mode for the service. (disabled, manual, auto)
[string]$StartMode,
# The status of the service. (critical, started, stopped, warning)
[string]$Status,
# The user account associated with the service.
[string]$User,
# The vendor and product name of the Endpoint solution that reported the event, such as Carbon Black Cb Response.
[string]$VendorProduct
)
$ServiceFullName = If ([string]::IsNullOrEmpty($ServiceFullName)) { "" } Else { $ServiceFullName }
$ServiceId = If ([string]::IsNullOrEmpty($ServiceId)) { "" } Else { $ServiceId }
$ServiceFriendlyName = If ([string]::IsNullOrEmpty($ServiceFriendlyName)) { "" } Else { $ServServiceFriendlyNameiceName }
$StartMode = If ([string]::IsNullOrEmpty($StartMode)) { "" } Else { $StartMode }
$Status = If ([string]::IsNullOrEmpty($Status)) { "" } Else { $Status }
$User = If ([string]::IsNullOrEmpty($User)) { "" } Else { $User }
$Description = If ([string]::IsNullOrEmpty($Description)) { "" } Else { $Description }
$VendorProduct = If ([string]::IsNullOrEmpty($VendorProduct)) { "" } Else { $VendorProduct }
$EventTimeStamp = Get-Date -Format "yyyy-MM-ddTHH:mm:ssK"
$Delay = 100
For ($i = 0; $i -lt 30; $i++) {
try {
$logLine = "{{timestamp=""{0}"" dest=""{1}"" description=""{2}"" service=""{3}"" service_id=""{4}""" `
+ "service_name=""{5}"" start_mode=""{6}"" vendor_product=""{7}"" user=""{8}"" status=""{9}""}}"
$logLine -f $EventTimeStamp, $env:ComputerName, $Description, $ServiceFullName, $ServiceId, $ServiceFriendlyName, $StartMode, $VendorProduct, $User, $Status | Add-Content $LogFile -ErrorAction Stop
break;
}
catch {
Start-Sleep -Milliseconds $Delay
}
if ($i -eq 29) {
Write-Error "Alert logger failed to log, likely due to Splunk holding the file, check eventlog for details." -ErrorAction Continue
if ([System.Diagnostics.EventLog]::SourceExists("SDOLiveScripts") -eq $False) {
Write-Host "Doesn't exist"
New-EventLog -LogName Application -Source "SDOLiveScripts"
}
Write-EventLog -LogName "Application" -Source "SDOLiveScripts" `
-EventID 1337 `
-EntryType Error `
-Message "Failed to log to file $_.Exception.InnerException.Message" `
-ErrorAction Continue
}
}
}
Export-ModuleMember -Function LoggerEndpointService
If anyone could help that'd be great, thank you!
Upvotes: 0
Views: 1162
Reputation: 174485
As mentioned in the comments, PowerShell Jobs execute in separate processes and you can't share live objects across process boundaries.
By the time the job executes, $Logger.generalLog
is no longer a reference to the scriptblock registered as the Logger
function in the calling process - it's just a string, containing the definition of the source function.
You can re-create it from the source code:
$actualLogger = [scriptblock]::Create($Logger.generalLog)
or, in your case, to recreate all of them:
@($Logger.Keys) |ForEach-Object { $Logger[$_] = [scriptblock]::Create($Logger[$_]) }
This will only work if the logging functions are completely independent of their environment - any references to variables in the calling scope or belonging to the source module will fail to resolve!
Upvotes: 1