简体   繁体   English

Powershell 将计算机调用到在我的本地计算机重新启动后仍然存在的远程计算机?

[英]Powershell invoke-computer to a remote that survives a reboot of my local computer?

Is there a way to "invoke-command" to a remote computer such that I can reboot my computer and the job will still be running, and I can check the output log whenever I want?有没有办法“调用命令”到远程计算机,这样我就可以重新启动计算机并且作业仍将运行,并且我可以随时查看输出日志?

    PS> invoke-command -Computer Remote1 -File "ScriptThatRunsFor7days.ps1"
    PS> restart-computer
    PS> # Hey where's my job on remote computer?  Can i see it running and connect to
        # its output after rebooting my computer?

Isn't it easier to just register a scheduled task that runs the script on the remote computer?只是注册一个在远程计算机上运行脚本的计划任务不是更容易吗? For logging just use the cmdlet Start-Transcript at the top of the script.对于日志记录,只需使用脚本顶部的 cmdlet Start-Transcript。 I made a script not to long ago to easely register scheduled tasks on a remote computer.不久前我做了一个脚本来轻松地在远程计算机上注册计划任务。 Maybe you can try out and see if it works for you?也许您可以尝试一下,看看它是否适合您?

[CmdletBinding()]
param(
    [parameter(Mandatory=$true)]
    [string]
    $PSFilePath,

    [parameter(Mandatory=$true)]
    [string]
    $TaskName,

    [parameter(Mandatory=$true)]
    [string]
    $ComputerName
)

$VerbosePreference="Continue"

New-Variable -Name ScriptDestinationFolder -Value "Windows\PowershellScripts" -Option Constant -Scope Script

New-Variable -Name ScriptSourcePath -Value $PSFilePath -Option Constant -Scope Script
Write-Verbose "Script sourcepath: $ScriptSourcePath"

New-Variable -Name PSTaskName -Value $TaskName -Option Constant -Scope Script
Write-Verbose "TaskName: $TaskName"

$File = Split-Path $ScriptSourcePath -leaf
Write-Verbose "Filename: $File"
New-Variable -Name PSFileName -Value $File -Option Constant -Scope Script
Write-Verbose "PSFileName: $PSFileName"

$ExecutionTime = New-TimeSpan -Hours 8
Write-Verbose "Execution time: $ExecutionTime hours"

Invoke-Command -ComputerName $ComputerName -ScriptBlock {
    $VerbosePreference="Continue"        
    #Removing old Scheduled Task 
    Write-Verbose "Unregistering old scheduled task.."
    Stop-ScheduledTask -TaskName $Using:PSTaskName -ErrorAction SilentlyContinue
    Unregister-ScheduledTask -TaskName $Using:PSTaskName -Confirm:$false -ErrorAction SilentlyContinue


     #Creating destination directory for Powershell script
     $PSFolderPath = "C:" , $Using:ScriptDestinationFolder -join "\"
     Write-Verbose "Creating folder for script file on client: $PSFolderPath"
     New-Item -Path $PSFolderPath -ItemType Directory -Force

     #Scheduled Task definitions
    
     $Trigger = New-ScheduledTaskTrigger -Daily -At "8am" 
     $PSFilePath = "C:", $Using:ScriptDestinationFolder , $Using:PSFileName -join "\"  
     Write-Verbose "Setting path for script file to destination folder on client: $PSFilePath"
     $Action = New-ScheduledTaskAction -Execute PowerShell -Argument "-File $PSFilePath"
     $Principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType S4U
     $Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -DontStopOnIdleEnd -ExecutionTimeLimit $Using:ExecutionTime -StartWhenAvailable
     $Task = Register-ScheduledTask -TaskName $Using:PSTaskName -Principal $Principal -Action $Action -Settings $Settings -Trigger $Trigger
     $Task = Get-ScheduledTask -TaskName $Using:PSTaskName   
     $Task.Triggers[0].EndBoundary = [DateTime]::Now.AddDays(90).ToString("yyyyMMdd'T'HH:mm:ssZ") 
     Write-Verbose "Trigger expiration date set to: $Task.Triggers[0].EndBoundary"
     $Task.Settings.DeleteExpiredTaskAfter = 'P1D'
     Write-Verbose "Scheduled task will be deleted after $Task.Settings.DeleteExpiredTaskAfter after expiry."     
     $Task | Set-ScheduledTask -ErrorAction SilentlyContinue

 } #End Invoke-Command

#Copy script file from source to the computer
$ScriptDestination = "\" , $ComputerName , "C$",  $ScriptDestinationFolder  -join "\"
Write-Verbose "Script destination is set to: $ScriptDestination"

Write-Verbose "Copying script file: `"$ScriptSourcePath`" to `"$ScriptDestination`""
Copy-Item -Path $ScriptSourcePath -Destination $ScriptDestination -Force

Usage:用法:

Create-ScheduledTask-Test.ps1 -ComputerName MyRemoteComputer -PSFilePath "ScriptToRun.ps1" -TaskName DoSomeWork

Something with scheduled jobs.有预定工作的东西。 I'm copying the script to the remote computer using a pssession.我正在使用 pssession 将脚本复制到远程计算机。

$s = new-pssession remote1
copy-item script.ps1 c:\users\admin\documents -tosession $s
invoke-command $s { Register-ScheduledJob test script.ps1 -Runnow }

And then later, only when it finishes, it will automatically appear as a regular job on the remote computer:然后,只有当它完成时,它才会自动显示为远程计算机上的常规作业:

invoke-command remote1 { get-job | receive-job -keep }
function remote_nohup {
    param(
        [string]$Machine,
        [string]$Cmd
    )       
    
        $job_tstamp     = $(get-date -f MMdd_HHmm_ss)
        $job_name       = "${job_tstamp}"
        $job_dir_start  = (Get-Location).Path
        $job_dir_sched  = "$env:userprofile/Documents/jobs"
        $job_file       = "${job_dir_sched}/${job_name}.run.ps1"
        $job_log        = "${job_dir_sched}/${job_name}.log"
        $job_computer   = $Machine
        $job_cmd        = $Cmd

        # Create Job File
        $job_ps1 = @(
            "`$ErrorActionPreference  = `"Stop`""
            ""
            "Start-Transcript -path $job_log -append"
            ""
            "try {"
            "    write-host 'job_begin:($job_name)'"
            "    "
            "    set-location $job_dir_start -EA 0"
            "    "
            "    write-host 'job_cmd:($job_cmd)'"
            "    $job_cmd | out-host"
            ""
            "    write-host 'job_end:($job_name)'"
            "}"
            "catch {"
            "    `$msg = `$_"
            "    write-host  `$msg"
            "    write-error `$msg"
            "}"
            "finally {"
            "    Stop-Transcript"
            "}"
            ""
            "Exit-PSSession"
        )
        
        try {
            New-Item -ItemType Directory -Force -EA:0 -Path $job_dir_sched | out-null
            copy-Item $remote_profile_ps1 $job_profile 
            
            write-host "Creating File: $job_file"
            $f1 = open_w $job_file -fatal
            foreach ($line in $job_ps1) {
                $f1.WriteLine($line)
            }           
        }
        finally {
            $f1.close()
        }   

        # Create Jobs Dir
        write-host "Creating remote job Directory"
        Invoke-Command -Computer $job_computer -ScriptBlock { 
            New-Item -ItemType Directory -Force -EA:0 -Path $using:job_dir_sched | out-null
        }
        
        # Copy Job File
        write-host "copy-Item -recurse -ToSession `$s2  $job_file $job_file"
        $s2 = New-PSSession -Computer $job_computer
        copy-Item -ToSession $s2  $job_file $job_file    
        Receive-PSSession -Session $s2
        Remove-PSSession -Session $s2

        # Create Persistent Background Job
        write-host "Submitting job to remote scheduler"
        Invoke-Command -Computer $job_computer -ScriptBlock {
            Register-ScheduledJob -RunNow -Name $using:job_name -File $using:job_file
            Exit-PSSession          
        }

        # NOTE: Log file from run is placed on 
        #    remote computer under jobs dir     
}

function open_w {
    param([string]$path, [switch]$fatal)

    try {
        write-host "path: $path"  
        $pathfix = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
        $handle = [System.IO.StreamWriter]::new($pathfix, $false) #false:over-write, true:append
    }
    catch {
        if ($fatal) {
            write-host -ForegroundColor Red "EXCEPTION: " + $PSItem.ToString()      
            exit 1
        }
        return $null
    }
    return $handle
}

vonPryz provided the crucial pointer: vonPryz提供了关键的指针:

On Windows, PowerShell offers disconnected remote sessions that allow you to reconnect and collect output later, from any client session , even after a logoff or reboot - assuming that the disconnected session on the remote computer hasn't timed out.在 Windows 上, PowerShell 提供断开连接的远程会话允许您稍后从任何客户端会话重新连接和收集输出,即使在注销或重新启动后 - 假设远程计算机上断开连接的会话没有超时。

See the conceptual about_Remote_Disconnected_Sessions help topic.请参阅概念about_Remote_Disconnected_Sessions帮助主题。

The following sample script demonstrates the approach:以下示例脚本演示了该方法:

  • Save it to a *.ps1 file and adapt the $computerName and $sessionName variable values.将其保存到*.ps1文件并调整$computerName$sessionName变量值。

  • The script assumes that the current user identity can be used as-is to remote into the target computer;该脚本假定当前用户身份可以按原样用于远程访问目标计算机; if that is not the case, add a -Credential argument to the Invoke-Command and Get-PSSession calls.如果不是这种情况,请将-Credential参数添加到Invoke-CommandGet-PSSession调用。

  • Invoke the script and, when prompted, choose when to connect to the disconnected remote session that was created - including after a logoff / reboot, in which case the script is automatically reinvoked in order to connect to the disconnected session and retrieve its output.调用脚本,并在出现提示时选择何时连接到已创建的断开连接的远程会话 - 包括在注销/重新启动后,在这种情况下,脚本会自动重新调用以连接到断开连接的会话并检索其输出。

  • See the source-code comments for details, particularly with respect to the idle timeout.有关详细信息,尤其是有关空闲超时的信息,请参阅源代码注释。

  • One aspect not covered below is output buffering : a disconnected session that runs for a long time without having its output retrieved can potentially accumulate a lot of output.下面没有涉及的一个方面是输出缓冲:长时间运行而没有检索其输出的断开连接的会话可能会积累大量输出。 By default, if the output buffer fills up, execution is suspended.默认情况下,如果输出缓冲区填满,则暂停执行。 The OutputBufferingMode session option controls the behavior - see the New-PSSessionOption cmdlet. OutputBufferingMode会话选项控制行为 - 请参阅New-PSSessionOption cmdlet。

$ErrorActionPreference = 'Stop'

# ADAPT THESE VALUES AS NEEDED
$computer = '???'
$sessionName = 'ReconnectMe'

# See if the target session already exists.
$havePreviousSession = Get-PSSession -ComputerName $computer -Name $sessionName

if (-not $havePreviousSession) {

  # Create a disconnected session with a distinct custom name 
  # with a command that runs an output loop indefinitely.
  # The command returns instantly and outputs a session-information object 
  # for the disconnected session.
  # Note that [int]::MaxValue is used to get the maximum idle timeout, 
  # but the effective value is capped by the value of the remote machine's 
  # MaxIdleTimeoutMs WSMan configuration item, which defaults to 12 hours.
  Write-Verbose -vb "Creating a disconnected session named $sessionName on computer $computer..."
  $disconnectedSession = 
    Invoke-Command -ComputerName $computer -SessionName $sessionName -InDisconnectedSession -SessionOption @{ IdleTimeout=[int]::MaxValue } { while ($true) { Write-Host -NoNewLine .; Start-Sleep 1 } }

  # Prompt the user for when to connect and retrieve the output 
  # from the disconnected session.
  do {
    $response = Read-Host @"
---

Disconnected session $sessionName created on computer $computer.

You can connect to it and retrieve its output from any session on this machine,
even after a reboot.

* If you choose to log off or reboot now, this script re-runs automatically 
  when you log back in, in order to connect to the remote session and collect its output.

* To see open sessions on the target computer on demand, run the following
  (append | Remove-PSSession to remove them):

   Get-PSSession -ComputerName $computer

---

Do you want to (L)og off, (R)eboot, (C)onnect right now, or (Q)uit (submit with ENTER)? [l/r/c/q] 
"@
  } while (($response = $response.Trim()) -notin 'l', 'r', 'c', 'q')


  $autoRelaunchCmd = { 
   Set-ItemProperty registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce 'ReconnectDemo' "$((Get-Command powershell.exe).Path) -noexit -command `"Set-Location '$PWD'; . '$PSCommandPath'`"" 
  }

  switch ($response) {
    'q' { Write-Verbose -vb 'Aborted.'; exit 2 }
    'c' { break } # resume below
    'l' { 
       Write-Verbose -vb "Logging off..."
       & $autoRelaunchCmd
       logoff.exe
       exit
    }
    'r' {
       Write-Verbose -vb "Rebooting..."
       & $autoRelaunchCmd
       Restart-Computer
       exit
     } 
  }

}

# Getting here means that a remote disconnection session was previously created.
# Reconnect and retrieve its output.

# Implicitly reconnect to the session by name,
# and receive a job object representing the remotely running command.
# Note: Despite what the docs say, -OutTarget Job seems to be the default.
#       Use -Output Host to directly output the results of the running command.
Write-Verbose -vb "Connecting to previously created session $sessionName on computer $computer and receiving its output..."
$job = Receive-PSSession -ComputerName $computer -Name $sessionName -OutTarget Job

# Get the output from the job, timing out after a few seconds.
$job | Wait-Job -Timeout 3
$job | Remove-Job -Force # Forcefully terminate the job with the indefinitely running command.

# Remove the session.
Write-Host
Write-Verbose -Verbose "Removing remote session..."
Get-PSSession -ComputerName $computer -Name $sessionName | Remove-PSSession

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过重启在远程计算机上调用命令 - Invoke-command on remote computer with reboot 在 PowerShell 中的调用命令 session 中将文件从远程计算机复制到本地计算机 - Copy file from remote computer to local computer within an Invoke-command session in PowerShell 如何通过Invoke-Command在远程计算机上调用Powershell版本2 - How to invoke Powershell version 2 on remote computer via Invoke-Command 在远程计算机上执行Powershell代码,然后在本地计算机上使用结果 - Execute Powershell code on remote computer and then use result on local computer PowerShell从远程计算机上我的计算机上的位置运行bat - PowerShell run bat from location on my computer on remote computer Powershell远程计算机会话 - Powershell Remote Computer Session Powershell:如何使用Invoke-WmiMethod来唤醒远程计算机? - Powershell: How to use Invoke-WmiMethod to Beep a Remote Computer? PowerShell Invoke-Command 与本地计算机上的 FilePath - 参数模糊错误? - PowerShell Invoke-Command with FilePath on local computer - vague parameters error? 尝试在远程计算机上调用脚本 - Trying to Invoke a Script on a Remote Computer Powershell:使用带有自定义功能的invoke-command在远程计算机上执行并在主机中显示输出 - Powershell: use invoke-command with custom function to execute at remote computer and display output in the host computer
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM