如何在PowerShell中的Scriptblock中运行模块



我目前正试图将.psm1文件动态导入脚本块以执行它。

我使用并行化和作业,因为我需要作为不同的用户同时触发几个模块。

这是代码:

$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)"
}
}

logger变量是一个哈希表,定义如下:

$Logger = @{
generalLog         = $function:Logger
certificateLog     = $function:LoggerCertificate
alertLog           = $function:LoggerAlert
endpointServiceLog = $function:LoggerEndpointService
}

目前,它出现以下错误:

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.

记录器功能以一种特定的方式为记录文件提供服务,它被概括为可以在许多任务中使用。

记录器的一个精简示例(可能不会编译,只是删除了一堆行来给你大致的想法(:

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

如果有人能帮忙那就太好了,谢谢!

如注释中所述,PowerShell作业在单独的进程中执行,您不能跨进程边界共享活动对象。

当作业执行时,$Logger.generalLog不再是对调用过程中注册为Logger函数的脚本块的引用,它只是一个字符串,包含源函数的定义

您可以从源代码重新创建它:

$actualLogger = [scriptblock]::Create($Logger.generalLog)

或者,在您的情况下,重新创建所有这些:

@($Logger.Keys) |ForEach-Object { $Logger[$_] = [scriptblock]::Create($Logger[$_]) }

只有在日志记录函数完全独立于其环境的情况下,这才起作用-对调用范围中或属于源模块的变量的任何引用都将无法解析!

最新更新