about_Remote_Jobs — 원격 컴퓨터에서 배경 작업 실행하기
about_Remote_Jobs — 원격 컴퓨터에서 배경 작업 실행하기
PowerShell로 원격 컴퓨터에서 백그라운드 작업(background job)을 실행하는 방법을 다루는 문서예요. 로컬에서 백그라운드 작업을 돌려 본 분이라면, 원리 자체는 거의 같다는 걸 먼저 말씀드릴게요. 차이가 있다면 작업이 "어디서" 도는지와, 그 결과를 "어디로" 가져오는지 정도예요. 이 문서를 따라가다 보면 원격 작업의 세 가지 실행 방식과, 그중에서 특히 결과를 어디에 보관하느냐에 따른 차이를 자연스럽게 정리할 수 있을 거예요.
본문
간단한 설명
원격 컴퓨터에서 백그라운드 작업을 실행하는 방법을 설명합니다.
자세한 설명
PowerShell은 작업(job)을 통해 명령과 스크립트를 동시에 실행해요. PowerShell이 동시성을 지원하려고 제공하는 작업 유형은 세 가지가 있어요.
RemoteJob— 명령과 스크립트가 원격 세션에서 실행돼요.BackgroundJob— 명령과 스크립트가 로컬 컴퓨터의 별도 프로세스에서 실행돼요. 자세한 내용은 about_Jobs를 참고하세요.PSTaskJob또는ThreadJob— 명령과 스크립트가 로컬 컴퓨터의 같은 프로세스 안에서 별도 스레드로 실행돼요. 자세한 내용은 about_Thread_Jobs를 참고하세요.
별도의 컴퓨터나 별도의 프로세스에서 스크립트를 실행하면 격리(isolation)가 잘 돼요. 원격 작업에서 에러가 나도, 다른 실행 중인 작업이나 작업을 시작한 부모(parent) 세션에는 영향을 주지 않거든요. 다만 원격 계층(remoting layer)은 객체 직렬화(object serialization) 같은 부담이 추가돼요. 모든 객체는 부모 세션과 원격(작업) 세션 사이를 오갈 때 직렬화되고 역직렬화되는데, 크고 복잡한 데이터 객체를 직렬화하면 컴퓨팅·메모리 자원을 많이 쓰고 네트워크로 많은 데이터를 옮기게 돼요.
중요
작업을 만든 부모 세션은 작업 상태를 계속 주시하고 파이프라인 데이터를 수집해요. 작업이 완료된 상태에 도달하면 부모 프로세스가 작업 자식 프로세스를 종료해요. 부모 세션이 종료되면, 실행 중인 모든 자식 작업도 그 자식 프로세스와 함께 종료돼요.
이 상황을 우회하는 방법은 두 가지가 있어요.
Invoke-Command를 사용해 연결이 끊긴(disconnected) 세션에서 실행되는 작업을 만들기. 이 문서의 "분리 프로세스로 실행하기" 섹션을 참고하세요.- 작업 대신
Start-Process로 새 프로세스를 만들기. 자세한 내용은 Start-Process를 참고하세요.
원격 작업
원격 컴퓨터에서 작업을 실행하는 방법은 세 가지가 있어요.
- 원격 컴퓨터에서 대화형 세션을 시작한 뒤, 그 대화형 세션 안에서 작업 시작하기. 절차는 로컬 작업을 실행하는 것과 같지만, 모든 동작이 원격 컴퓨터에서 이뤄져요.
- 결과를 로컬 컴퓨터로 되돌려 주는 원격 작업 실행하기. 여러 작업의 결과를 모아서 로컬 컴퓨터의 한 곳에서 관리하고 싶을 때 이 방법을 써요.
- 결과를 원격 컴퓨터에 유지하는 원격 작업 실행하기. 작업 데이터를 원래 컴퓨터에 더 안전하게 보관하고 싶을 때 이 방법을 써요.
대화형 세션에서 작업 시작하기
원격 컴퓨터와 대화형 세션을 시작한 뒤, 그 세션 안에서 작업을 시작할 수 있어요. 대화형 세션에 대한 자세한 내용은 about_Remote와 Enter-PSSession을 참고하세요.
대화형 세션에서 작업을 시작하는 절차는 로컬 컴퓨터에서 백그라운드 작업을 시작하는 절차와 거의 같아요. 다만 모든 동작이 로컬 컴퓨터가 아니라 원격 컴퓨터에서 이뤄진다는 점만 다르죠.
-
Enter-PSSessioncmdlet으로 원격 컴퓨터와 대화형 세션을 시작해요.Enter-PSSession의 ComputerName 매개 변수로 대화형 세션용 임시 연결을 만들 수도 있고, Session 매개 변수로 PowerShell 세션(PSSession) 안에서 대화형 세션을 실행할 수도 있어요.다음 명령은 Server01 컴퓨터에서 대화형 세션을 시작해요.
C:\PS> Enter-PSSession -ComputerName Server01명령 프롬프트가 바뀌면서 지금 Server01 컴퓨터에 연결되어 있다는 걸 보여줘요.
Server01\C:> -
세션 안에서 원격 작업을 시작하려면
Start-Jobcmdlet을 써요. 다음 명령은 Server01 컴퓨터의 Windows PowerShell 이벤트 로그에서 이벤트를 가져오는 원격 작업을 실행해요.Start-Jobcmdlet은 작업을 나타내는 객체를 반환해요.이 명령은 작업 객체를
$job변수에 저장해요.Server01\C:> $job = Start-Job -ScriptBlock { Get-EventLog "Windows PowerShell" }작업이 실행되는 동안 대화형 세션에서 다른 명령을, 다른 작업까지도 실행할 수 있어요. 단, 작업이 완료될 때까지 대화형 세션을 계속 열어 두어야 해요. 세션을 끝내면 작업이 중단되고 결과가 사라져요.
-
작업이 완료됐는지 확인하려면
$job변수의 값을 표시하거나Get-Jobcmdlet으로 작업을 가져와요. 다음 명령은Get-Jobcmdlet으로 작업을 표시해요.Server01\C:> Get-Job $job SessionId Name State HasMoreData Location Command --------- ---- ----- ----------- -------- ------- 1 Job1 Complete True localhost Get-EventLog "Windows...Get-Job출력을 보면 작업이 "localhost" 컴퓨터에서 실행 중이라고 나와요. 작업이 시작된 컴퓨터(여기서는 Server01)에서 그대로 실행되고 있으니까요. -
작업 결과를 가져오려면
Receive-Jobcmdlet을 써요. 결과를 대화형 세션에 표시하거나 원격 컴퓨터의 파일로 저장할 수 있어요. 다음 명령은 $job 변수의 작업 결과를 가져와요. 리디렉션 연산자(>)를 사용해 작업 결과를 Server01 컴퓨터의 PsLog.txt 파일로 저장하죠.Server01\C:> Receive-Job $job > C:\logs\PsLog.txt -
대화형 세션을 끝내려면
Exit-PSSessioncmdlet을 써요. 명령 프롬프트가 바뀌면서 로컬 컴퓨터의 원래 세션으로 돌아왔다는 걸 보여줘요.Server01\C:> Exit-PSSession C:\PS> -
Server01 컴퓨터의
PsLog.txt파일 내용을 아무 때나 보려면 대화형 세션을 다시 시작하거나 원격 명령을 실행하면 돼요. 이런 종류의 명령은PsLog.txt파일의 데이터를 여러 명령으로 조사하고 관리하고 싶을 때 쓸 수 있으니, PSSession(영구 연결)에서 실행하는 게 좋아요. PSSession에 대한 자세한 내용은 about_PSSessions를 참고하세요.다음 명령들은
New-PSSessioncmdlet으로 Server01 컴퓨터에 연결된 PSSession을 만들고,Invoke-Commandcmdlet으로 그 PSSession 안에서Get-Content명령을 실행해 파일 내용을 보여줘요.$s = New-PSSession -ComputerName Server01 Invoke-Command -Session $s -ScriptBlock { Get-Content C:\logs\pslog.txt}
결과를 로컬 컴퓨터로 되돌려 주는 원격 작업 시작하기 (AsJob)
원격 컴퓨터에서 작업을 시작하되 그 명령 결과를 로컬 컴퓨터로 되돌려 주려면, Invoke-Command 같은 cmdlet의 AsJob 매개 변수를 써요.
AsJob 매개 변수를 쓰면 작업이 원격 컴퓨터에서 실행되긴 하지만, 작업 객체는 실제로 로컬 컴퓨터에 만들어져요. 작업이 완료되면 결과가 로컬 컴퓨터로 반환되죠.
Job 명사를 포함한 cmdlet(Job cmdlet)을 사용하면 어떤 cmdlet이 만들었든 모든 작업을 관리할 수 있어요. AsJob 매개 변수가 있는 cmdlet 중에는 PowerShell 원격을 사용하지 않는 것도 많아서, 원격이 구성되지 않았거나 원격 요구 사항을 충족하지 못하는 컴퓨터에서도 쓸 수 있어요.
-
다음 명령은
Invoke-Command의 AsJob 매개 변수로 Server01 컴퓨터에서 작업을 시작해요. 이 작업은 System 로그의 이벤트를 가져오는Get-Eventlog명령을 실행해요. JobName 매개 변수로 작업에 표시 이름을 지정할 수도 있어요.Invoke-Command -ComputerName Server01 -ScriptBlock { Get-EventLog System} -AsJob명령 결과는 다음과 비슷한 출력이에요.
SessionId Name State HasMoreData Location Command --------- ---- ----- ----------- -------- ------- 1 Job1 Running True Server01 Get-EventLog SystemAsJob 매개 변수를 쓰면
Invoke-Command는Start-Job이 반환하는 것과 같은 유형의 작업 객체를 반환해요. 작업 객체를 변수에 저장하거나Get-Job명령으로 가져올 수 있어요.Location 속성 값을 보면 이 작업이 Server01 컴퓨터에서 실행됐다는 걸 알 수 있어요.
-
Invoke-Commandcmdlet의 AsJob 매개 변수로 시작한 작업을 관리하려면 Job cmdlet을 써요. 원격 작업을 나타내는 작업 객체가 로컬 컴퓨터에 있으니, 작업을 관리하려고 원격 명령을 실행할 필요가 없어요.작업이 완료됐는지 확인하려면
Get-Job명령을 써요. 다음 명령은 현재 세션에서 시작된 모든 작업을 가져와요.Get-Job원격 작업이 현재 세션에서 시작됐으니, 로컬
Get-Job명령으로도 작업을 가져올 수 있어요. 작업 객체의 State 속성은 명령이 성공적으로 완료됐음을 보여줘요.SessionId Name State HasMoreData Location Command --------- ---- ----- ----------- -------- ------- 1 Job1 Completed True Server01 Get-EventLog System -
작업 결과를 가져오려면
Receive-Jobcmdlet을 써요. 작업 결과는 작업 객체가 있는 컴퓨터로 자동 반환되므로, 로컬Receive-Job명령으로도 결과를 가져올 수 있어요.다음 명령은
Receive-Jobcmdlet으로 작업 결과를 가져와요. 세션 ID로 작업을 식별하죠. 이 명령은 작업 결과를 $results 변수에 저장해요. 결과를 파일로 리디렉션할 수도 있어요.$results = Receive-Job -Id 1
결과를 원격 컴퓨터에 유지하는 원격 작업 시작하기
명령 결과를 원격 컴퓨터에 유지하는 작업을 시작하려면, Invoke-Command cmdlet으로 원격 컴퓨터에서 Start-Job 명령을 실행해요. 이 방법으로 여러 컴퓨터에서 작업을 실행할 수 있어요.
Start-Job 명령을 원격으로 실행하면 작업 객체가 원격 컴퓨터에 만들어지고, 작업 결과도 원격 컴퓨터에 유지돼요. 작업 입장에서 보면 모든 동작이 로컬인 셈이죠. 원격 컴퓨터의 로컬 작업을 관리하려고, 그저 명령을 원격으로 실행하고 있을 뿐이에요.
-
Invoke-Commandcmdlet으로 원격 컴퓨터에서Start-Job명령을 실행해요.이 명령은 PSSession(영구 연결)이 필요해요.
Invoke-Command의 ComputerName 매개 변수로 임시 연결을 만들면, 작업 객체가 반환되는 순간Invoke-Command명령이 완료된 것으로 간주돼요. 그래서 임시 연결이 닫히고 작업이 취소돼 버려요.다음 명령은
New-PSSessioncmdlet으로 Server01 컴퓨터에 연결된 PSSession을 만들어요. 이 PSSession을$s변수에 저장하죠.$s = New-PSSession -ComputerName Server01다음 명령은
Invoke-Commandcmdlet으로 PSSession 안에서Start-Job명령을 실행해요.Start-Job명령과Get-Eventlog명령이 중괄호 안에 들어 있어요.Invoke-Command -Session $s -ScriptBlock { Start-Job -ScriptBlock {Get-EventLog System}}결과는 다음과 비슷한 출력이에요.
Id Name State HasMoreData Location Command -- ---- ----- ----------- -------- ------- 2 Job2 Running True Localhost Get-EventLog SystemStart-Job명령을 원격으로 실행하면Invoke-Command는Start-Job이 반환하는 것과 같은 유형의 작업 객체를 반환해요. 작업 객체를 변수에 저장하거나Get-Job명령으로 가져올 수 있어요.Location 속성 값을 보면 이 작업이 Server01 컴퓨터에서 실행됐는데도 로컬 컴퓨터, 그러니까 "LocalHost"에서 실행된 것으로 나와요. 작업 객체가 Server01 컴퓨터에 만들어지고 작업도 같은 컴퓨터에서 실행되니, 로컬 백그라운드 작업으로 간주되기 때문이에요.
-
원격 작업을 관리하려면 Job cmdlet을 써요. 작업 객체가 원격 컴퓨터에 있으니, 작업 결과를 가져오거나 중지·대기하려면 원격 명령을 실행해야 해요.
작업이 완료됐는지 확인하려면
Invoke-Command명령으로 Server01 컴퓨터에 연결된 PSSession 안에서Get-Job명령을 실행해요.Invoke-Command -Session $s -ScriptBlock {Get-Job}이 명령은 작업 객체를 반환해요. 작업 객체의 State 속성은 명령이 성공적으로 완료됐음을 보여줘요.
SessionId Name State HasMoreData Location Command --------- ---- ----- ----------- -------- ------- 2 Job2 Completed True LocalHost Get-EventLog System -
작업 결과를 가져오려면
Invoke-Commandcmdlet으로 Server01 컴퓨터에 연결된 PSSession 안에서Receive-Job명령을 실행해요.다음 명령은
Receive-Jobcmdlet으로 작업 결과를 가져와요. 세션 ID로 작업을 식별하죠. 작업 결과를$results변수에 저장해요.Receive-Job의 Keep 매개 변수로 결과를 원격 컴퓨터의 작업 캐시에 유지해요.$results = Invoke-Command -Session $s -ScriptBlock { Receive-Job -SessionId 2 -Keep }결과를 로컬 컴퓨터나 원격 컴퓨터의 파일로 리디렉션할 수도 있어요. 다음 명령은 리디렉션 연산자로 결과를 Server01 컴퓨터의 파일에 저장해요.
Invoke-Command -Session $s -Command { Receive-Job -SessionId 2 > C:\logs\pslog.txt }
분리 프로세스로 실행하기
앞에서 말했듯이 부모 세션이 종료되면, 실행 중인 모든 자식 작업이 그 자식 프로세스와 함께 종료돼요. 로컬 컴퓨터의 원격 기능을 사용하면 현재 PowerShell 세션에 붙어 있지 않은 작업을 실행할 수 있어요.
로컬 컴퓨터에서 새 PowerShell 세션을 만들고, 그 세션 안에서 Invoke-Command로 작업을 시작해요. Invoke-Command는 원격 세션의 연결을 끊고 부모 세션을 종료할 수 있게 해줘요. 나중에 새 PowerShell 세션을 시작해 아까 연결을 끊었던 세션에 다시 연결하면 작업 모니터링을 이어갈 수 있어요. 다만 원래 PowerShell 세션으로 반환됐던 데이터는 그 세션이 종료되면 사라져요. 다시 연결했을 때는 연결을 끊은 뒤에 새로 생성된 데이터 객체만 반환돼요.
# Create remote session on local machine
PS> $session = New-PSSession -Cn localhost
# Start remote job
PS> $job = Invoke-Command -Session $session -ScriptBlock { 1..60 | % { sleep 1; "Output $_" } } -AsJob
PS> $job
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 RemoteJob Running True localhost 1..60 | % { sleep 1; ...
# Disconnect the job session
PS> Disconnect-PSSession $session
Id Name Transport ComputerName ComputerType State ConfigurationName Availability
-- ---- --------- ------------ ------------ ----- ----------------- ------------
1 Runspace1 WSMan localhost RemoteMachine Disconnected Microsoft.PowerShell None
PS> $job
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 RemoteJob Disconnected True localhost 1..60 | % { sleep 1;
# Reconnect the session to a new job object
PS> $jobNew = Receive-PSSession -Session $session -OutTarget Job
PS> $job | Wait-Job | Receive-Job
Output 9
Output 10
Output 11
...
이 예시에서 작업들은 여전히 부모 PowerShell 세션에 붙어 있어요. 다만 그 부모 세션은 Invoke-Command가 실행됐던 원래 PowerShell 세션이 아니라는 점이 핵심이에요.