Я хочу сделать резервную копию некоторых данных поверх моего скрипта. Все данные должны быть заархивированы в отдельном потоке. Но две вещи идут не так:
Вызов скрипта приводит к:
> .\Backup.ps1
outside: -What: Data A -ZipSource -ZipDest C:\Users\xyz\AppData\Local\Temp -Timestamp "20220517-002854
outside: -What: Data B -ZipSource -ZipDest C:\Users\xyz\AppData\Local\Temp -Timestamp "20220517-002854
>
Вот мой сценарий:
class BackupContentData
{
[ValidateNotNullOrEmpty()][string]$What
[ValidateNotNullOrEmpty()][string]$ZipSource
}
$bcd = @(
[BackupContentData]@{ What = "Data A"; ZipSource = "$env:USERPROFILE\Documents\a_file.txt";}
[BackupContentData]@{ What = "Data B"; ZipSource = "$env:USERPROFILE\Documents\b_file.txt";}
)
function testFct {
param([string]$What, [string]$ZipSource, [string]$ZipDest, [string]$Timestamp)
Write-Host "inside: -What: "$What" -ZipSource "$ZipSource" -ZipDest "$ZipDest" -Timestamp "$Timestamp
}
$timestamp = "$(get-date -f yyyyMMdd-HHmmss)"
foreach ($e in $bcd) {
$job = Start-ThreadJob -Name $e.What -InputObject $e -ScriptBlock {
Invoke-Expression "function getTest {$using:testFct}"
Write-Host "outside: -What: "$input.What" -ZipSource "$input.ZipSource" -ZipDest "$env:Temp" -Timestamp ""$(get-date -f yyyyMMdd-HHmmss)"
getTest -What "$input.What" -ZipSource "$input.ZipSource" -ZipDest "$env:Temp" -Timestamp "$(get-date -f yyyyMMdd-HHmmss)"
}
Receive-Job $job -AutoRemoveJob -Wait
}
Что не так со сценарием?
Поскольку testFct
не существует в области вашего ThreadJob, вам нужно сначала сохранить определение функции, а затем передать его в область выполнения и определить там функцию, как показано в этот ответ.
Другая проблема заключается в попытке ссылаться на один и тот же $input
более одного раза. Из-за характера автоматическая переменная $input
вы можете ссылаться на эту переменную только один раз в своем блок сценария:
Since
$input
is an enumerator, accessing any of its properties causes$input
to no longer be available. You can store$input
in another variable to reuse the$input
properties.
В качестве обходного пути вы можете обернуть переменную в Оператор подвыражения массива @( )
или Оператор подвыражения $( )
, чтобы сохранить перечисленный вывод в новой переменной.
Вот простой пример того, что объяснено выше:
Start-ThreadJob -InputObject 'Hello World' -ScriptBlock {
"1. $input"
"2. $input"
} | Receive-Job -AutoRemoveJob -Wait
# This outputs:
# 1. Hello World
# 2.
# And the workaround
Start-ThreadJob -InputObject 'Hello World' -ScriptBlock {
# This would also work:
# $thisInput = foreach($i in $input) { $i }
$thisInput = $($input)
"1. $thisInput"
"2. $thisInput"
} | Receive-Job -AutoRemoveJob -Wait
# Outputs:
# 1. Hello World
# 2. Hello World
Наконец, ваш сценарий на самом деле не многопоточность, это потому, что вы сохраняете задание внутри своего цикла, а затем ожидаете его последовательно вместо того, чтобы запускать все задания сразу, а затем ждать их всех.
class BackupContentData {
[ValidateNotNullOrEmpty()] [string] $What
[ValidateNotNullOrEmpty()] [string] $ZipSource
}
function testFct {
param([string]$What, [string]$ZipSource, [string]$ZipDest, [string]$Timestamp)
Write-Host "inside: -What: $What -ZipSource $ZipSource -ZipDest $ZipDest -Timestamp $Timestamp"
}
# definition of the function is stored here
$def = ${function:testFct}.ToString()
$bcd = @(
[BackupContentData]@{ What = "Data A"; ZipSource = "$env:USERPROFILE\Documents\a_file.txt" }
[BackupContentData]@{ What = "Data B"; ZipSource = "$env:USERPROFILE\Documents\b_file.txt" }
)
$job = foreach ($e in $bcd) {
Start-ThreadJob -Name $e.What -InputObject $e -ScriptBlock {
$thisObject = $($input)
# Define a new function with name `getTest` in this scope using `testFct` definition
${function:getTest} = $using:def
Write-Host "outside: -What: $($thisObject.What) -ZipSource $($thisObject.ZipSource) -ZipDest $env:Temp -Timestamp $(get-date -f yyyyMMdd-HHmmss)"
getTest -What $thisObject.What -ZipSource $thisObject.ZipSource -ZipDest $env:Temp -Timestamp (Get-Date -f yyyyMMdd-HHmmss)
}
}
$job | Receive-Job -AutoRemoveJob -Wait
Результат, который вы можете ожидать от этого:
outside: -What: Data A -ZipSource C:\Users\user\Documents\a_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251
inside: -What: Data A -ZipSource C:\Users\user\Documents\a_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251
outside: -What: Data B -ZipSource C:\Users\user\Documents\b_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251
inside: -What: Data B -ZipSource C:\Users\user\Documents\b_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251