You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell脚本中Start-Job创建的作业无法通过Get-Job检测到

问题:PowerShell脚本启动的后台作业无法通过Get-Job检测到

我编写了一个PowerShell 7脚本,会根据当前时间启动sync-job.ps1作为后台作业并监控。脚本运行正常,数据传输符合预期,但脚本运行时执行Get-Job却找不到这些作业;直接在PowerShell环境中执行相同的Start-Job命令,却能正常创建并通过Get-Job检测到作业。

监控脚本

#-- Global Variables

Write-Host "Enter Credentials for Network Share"

$cred = Get-Credential
$Source = Read-Host "Enter Source"
$Destination = Read-Host "Enter Destination"
$Sleepduration = Read-Host "Enter Sleepduration of Robocopy"

$runtime_throttled_start = "0600"
$runtime_throttled_end = "1759"

$runtime_unthrottled_start = "1801"
$runtime_unthrottled_end =  "2359"

$runtime_unthrottled_start_nextday = "0001"
$runtime_unthrottled_end_nextday = "0558"

$Date = Get-Date -Format "MM-dd-yyyy"
$Logfile = "$PSScriptRoot\Logs\start-copy\start-copy-$Date.log"

$Script_Root = "C:\temp"

$Status = "0"

#-- Functions

function logging ($Value) { 

    $Script_Output = "$(Get-Date -Format "MM-dd-yyyy HH:mm:ss") - $Value"

    Write-Host $Script_Output
    Write-Output $Script_Output >> $Logfile

}

function main {

    if (! (Test-Path "$PSScriptRoot\Logs\start-copy")) {

        Logging "Creating Logging folder..."
        New-Item -Path "$PSScriptRoot\Logs" -Name "start-copy" -Type "directory"

    }

    $i = 1

    try {

        while ($i -eq 1) {

            $Time = get-date -Format "HHmm"

            if (($Time -ge $runtime_throttled_start) -and ($Time -le $runtime_throttled_end)) {

                if (($Status -eq "not_throttled") -or ($Status -eq 0)) {

                    Logging "Stopping running jobs..."
                    Get-Job | Where-Object {$_.Command -match "sync-job"} | Remove-Job -Force

                    Logging "Starting throttled script..."
                    Start-Job -Name Robocopy_Throttled -Filepath ".\sync-job.ps1" -ArgumentList "$Source", "$Destination", $Script_Root, $Sleepduration, "0", "$runtime_throttled_start-$runtime_throttled_end", "$cred"

                    $nextday = $false

                }

                $Status = "throttled"
                Logging "Status: $Status"

            }

            if ((($Time -ge $runtime_unthrottled_start-1) -and ($Time -le ($runtime_unthrottled_end))) -or (($Time -ge $runtime_unthrottled_start_nextday) -and ($Time -le $runtime_unthrottled_end_nextday))) {

                if (($Status -eq "throttled") -or ($Status -eq 0)) {

                    Logging "Stopping running jobs..."
                    Get-Job | Where-Object {$_.Command -match "sync-job"} | Remove-Job -Force

                    Logging "Starting unthrottled script..."
                    Start-Job -Name Robocopy_Unthrottled -Filepath ".\sync-job.ps1" -ArgumentList "$Source", "$Destination", $Script_Root, $Sleepduration, "3", "$runtime_unthrottled_start-$runtime_unthrottled_end", "$cred"

                    $nextday = $false

                }

                $Status = "not_throttled"
                Logging "Current status: $Status"

            }

            if (($Time -eq "0000") -and ($nextday -eq $false)) {

                $nextday = $true

                Logging "Next day, stopping running jobs once..."
                Get-Job | Where-Object {$_.Command -match "sync-job"} | Remove-Job -Force

                Logging "Starting next-day unthrottled script...."
                Start-Job -Name Robocopy_Unthrottled_nextday -Filepath ".\sync-job.ps1" -ArgumentList "$Source", "$Destination", $Script_Root, $Sleepduration, "3", "$runtime_unthrottled_start_nextday-$runtime_unthrottled_end_nextday", "$cred"

                $Status = "not_throttled_nextday"
                Logging "Current status: $Status"

            }  

            Logging "Waiting 10 Seconds for the next check"
            Start-Sleep 10

            Logging "The following Jobs are currently running:
            Get-Job | Where-Object {$_.Command -match "sync-job"}

        }

    }

    finally {

        Logging "Stopping and removing all jobs..."
        Get-Job | Where-Object {$_.Command -match "sync-job"} | Remove-Job -Force

    }

}

main

作业脚本(sync-job.ps1)

param (

    $Source,
    $Destination,
    $Root,
    $Sleepduration,
    $Mode,
    $Runtime,
    $Cred

)

#-- Global Variables

$Date = Get-Date -Format "MM-dd-yyyy_HH-mm"
$Time = Get-Date -Format "HH:mm"

Write-Host $Logfile

if ($Time -eq "00:00") {

    $Logfile = "$Root\Logs\Log-$Date-unthrottled_nextday.txt"

}

else {

    switch ($Mode) {

        0 {$Logfile = "$Root\Logs\Log-$Date-throttled.txt"}
        3 {$Logfile = "$Root\Logs\Log-$Date-unthrottled.txt"}

    }

}

#-- Functions

function logging ($Value) { 

    $Script_Output = "$(Get-Date -Format "MM-dd-yyyy HH:mm:ss") - $Value"

    Write-Host $Script_Output
    Write-Output $Script_Output >> $Logfile

}

function sync-folder ($Source, $Destination, $Mode) {

    if (!(Get-PSDrive -PSProvider FileSystem).Name -eq "TempMmount") {

        $cred = Get-Credential
        New-PSDrive -Name "TempMount" -PSProvider "FileSystem" -Credential $Cred -Root $Source

    }

    switch ($Mode) {

        0 {robocopy $Source $Destination /e /z /copy:DAT /dcopy:DA /W:5 /xo /im /IPG:8 /log+:$Logfile /RH:$runtime /tee}

        1 {robocopy $Source $Destination /e /z /copy:DAT /dcopy:DA /W:5 /xo /im /IPG:8 /log+:$Logfile /tee}

        2 {robocopy $Source $Destination /e /z /copy:DAT /dcopy:DA /W:5 /xo /im /IPG:8 /log+:$Logfile /tee /L}

        3 {robocopy $Source $Destination /e /z /copy:DAT /dcopy:DA /W:5 /xo /im /IPG:8 /log+:$Logfile /RH:$runtime /tee}

        Default {Write-Host "No Mode has been chosen. Exiting script..."; Exit}

    }

    Remove-PSDrive -Name "TempMount"

}

#-- Main Method

function main {

    Write-Host "Source Directory: $Source"
    Write-Host "Destination Directory: $Destination"

    $Current_User = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    Logging "User who's executing this script: $Current_User"

    #-- Create Log Directory if it does not exist yet

    if (! (Test-Path "$Root\Logs")) {

        Logging "Creating Log Directory`n"
        
        New-Item -Path $Root -Name "Logs" -Type "Directory"

    }

    else {

        Logging "Log Directory already exists. Proceed.. `n"

    }

    $Modes = 
    "(0) - Normal run (requires runtime)`n",
    "(1) - run only once`n",
    "(2) - Dry run once`n",
    "(3) - run without bandwidth limit (requires runtime)"

    Write-Host "`nYou got the following exectuion modes:`n`n $Modes`n"
    Write-Host "You have chosen the following Mode: $Mode"

    #-- Endless loop for repetetive sync
    #-- Sleepduration is set by the Sleepduration variable

    $i = 1

    while ($i -eq 1) {

        Write-Host "===============================================================================`n"
        Write-Output "===============================================================================`n" >> $Logfile

        try {

            Logging "Starting Sync between $Source and $Destination `n"
            sync-folder $Source $Destination $Mode

            switch ($Mode) {

                0 {Logging "Sync complete. Waiting $Sleepduration Seconds for the next Sync`n"; Start-Sleep $Sleepduration}
                1 {Logging "Mode = run once, sync complete. Stoping script...`n"; Write-Host "`n===============================================================================`n"; Write-Output "`n===============================================================================`n" >> $Logfile; Exit}
                2 {Logging "Mode = Dry run once, test complete. Stopping script..."; Write-Host "`n===============================================================================`n"; Write-Output "`n===============================================================================`n" >> $Logfile; Exit}
                3 {Logging "Mode = no throttle, sync complete. Waiting $Sleepduration Seconds for the next Sync`n"; Start-Sleep $Sleepduration}

            }

        }

        catch {

            Logging "There was a Problem with the sync. Following Error message may be helpful:`n"
            Logging "$_`n"

            Write-Host "`n===============================================================================`n"
            Write-Output "`n===============================================================================`n" >> $Logfile

        }

    }

}

main

问题原因及修复方案

核心原因

脚本内启动的作业默认属于脚本本地作用域,而你在外部PowerShell会话(或当前会话的全局作用域)执行Get-Job时,只能读取当前作用域下的作业,因此无法看到脚本内创建的作业。

具体修复步骤

  1. 让作业全局可见(可选)
    在启动作业时添加-Scope Global参数,这样外部会话就能通过Get-Job查到:

    Start-Job -Name Robocopy_Throttled -Scope Global -Filepath ".\sync-job.ps1" -ArgumentList "$Source", "$Destination", $Script_Root, $Sleepduration, "0", "$runtime_throttled_start-$runtime_throttled_end", $cred
    

    注意:全局作业容易和其他脚本的作业冲突,更推荐在脚本内部管理作业。

  2. 修复监控脚本的日志语法错误
    原脚本中最后一段日志代码未闭合字符串,且未实际执行作业查询命令,修改为:

    $runningJobs = Get-Job | Where-Object {$_.Command -match "sync-job"} | Out-String
    Logging "The following Jobs are currently running:`n$runningJobs"
    
  3. 修复作业脚本的驱动器判断逻辑
    原sync-folder函数的驱动器判断逻辑错误,会重复弹出凭据窗口,修改为:

    function sync-folder ($Source, $Destination, $Mode) {
        # 检查TempMount驱动器是否存在,不存在则创建
        if (-not (Get-PSDrive -Name TempMount -ErrorAction SilentlyContinue)) {
            New-PSDrive -Name "TempMount" -PSProvider "FileSystem" -Credential $Cred -Root $Source
        }
    
        # 保留原robocopy逻辑...
    }
    

    同时删除函数内的$cred = Get-Credential,避免重复弹出凭据窗口。

  4. 优化作业管理方式
    建议在监控脚本中保存作业对象,避免靠命令匹配查找作业:

    # 全局变量保存当前作业
    $currentJob = $null
    
    # 启动作业时保存对象
    $currentJob = Start-Job -Name Robocopy_Throttled -Filepath ".\sync-job.ps1" -ArgumentList "$Source", "$Destination", $Script_Root, $Sleepduration, "0", "$runtime_throttled_start-$runtime_throttled_end", $cred
    
    # 停止作业时直接使用保存的对象
    if ($currentJob) {
        Remove-Job $currentJob -Force
        $currentJob = $null
    }
    

内容的提问来源于stack exchange,提问作者Katzsuya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:55:33