[英]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-Command
和Get-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.