Add Remoting and Job tests (#4928)
This commit is contained in:
parent
d73e97464c
commit
1e271ea187
|
@ -785,13 +785,6 @@ namespace Microsoft.PowerShell.Commands
|
|||
throw new InvalidOperationException(RemotingErrorIdStrings.AsJobAndDisconnectedError);
|
||||
}
|
||||
|
||||
if (this.InvokeAndDisconnect &&
|
||||
(this.ComputerName == null || this.ComputerName.Length == 0) &&
|
||||
(this.ConnectionUri == null || this.ConnectionUri.Length == 0))
|
||||
{
|
||||
throw new InvalidOperationException(RemotingErrorIdStrings.InvokeDisconnectedWithoutComputerName);
|
||||
}
|
||||
|
||||
if (MyInvocation.BoundParameters.ContainsKey("SessionName") && !this.InvokeAndDisconnect)
|
||||
{
|
||||
throw new InvalidOperationException(RemotingErrorIdStrings.SessionNameWithoutInvokeDisconnected);
|
||||
|
|
|
@ -911,9 +911,6 @@ Do you want to continue?</value>
|
|||
<data name="JobIdentifierNull" xml:space="preserve">
|
||||
<value>The JobIdentifier provided must not be null. Please provide a valid JobIdentifier.</value>
|
||||
</data>
|
||||
<data name="InvokeDisconnectedWithoutComputerName" xml:space="preserve">
|
||||
<value>No computer names or connection Uris were specified. You must provide a computer name or connection Uri when invoking a command with the -Disconnected switch.</value>
|
||||
</data>
|
||||
<data name="JobBlockedSoWaitJobCannotContinue" xml:space="preserve">
|
||||
<value>The Wait-Job cmdlet cannot finish working, because one or more jobs are blocked waiting for user interaction. Process interactive job output by using the Receive-Job cmdlet, and then try again.</value>
|
||||
</data>
|
||||
|
|
|
@ -1,38 +1,285 @@
|
|||
Describe 'Basic Job Tests' -Tags 'CI' {
|
||||
|
||||
BeforeAll {
|
||||
$job = Start-Job {1}
|
||||
}
|
||||
# Make sure we do not have any jobs running
|
||||
Get-Job | Remove-Job -Force
|
||||
$timeBeforeStartedJob = Get-Date
|
||||
$startedJob = Start-Job -Name 'StartedJob' -ScriptBlock { 1 + 1 } | Wait-Job
|
||||
$timeAfterStartedJob = Get-Date
|
||||
|
||||
It 'Test job creation' {
|
||||
$job | should not be $null
|
||||
}
|
||||
function script:ValidateJobInfo($job, $state, $hasMoreData, $command)
|
||||
{
|
||||
$job.State | Should BeExactly $state
|
||||
$job.HasMoreData | Should Be $hasMoreData
|
||||
|
||||
It 'Test job State' {
|
||||
Wait-Job $job -Timeout 60
|
||||
$job.JobStateInfo.State -eq 'Completed' | should be $true
|
||||
}
|
||||
|
||||
It 'Job output test' {
|
||||
Receive-Job $job -wait | should be 1
|
||||
}
|
||||
|
||||
It "Create job with native command" {
|
||||
try {
|
||||
$nativeJob = Start-job { powershell -c 1+1 }
|
||||
$nativeJob | Wait-Job
|
||||
$nativeJob.State | Should BeExactly "Completed"
|
||||
$nativeJob.HasMoreData | Should Be $true
|
||||
Receive-Job $nativeJob | Should BeExactly 2
|
||||
Remove-Job $nativeJob
|
||||
{ Get-Job $nativeJob -ErrorAction Stop } | ShouldBeErrorId "JobWithSpecifiedNameNotFound,Microsoft.PowerShell.Commands.GetJobCommand"
|
||||
}
|
||||
finally {
|
||||
Remove-Job $nativeJob -Force -ErrorAction SilentlyContinue
|
||||
if($command -ne $null)
|
||||
{
|
||||
$job.Command | Should BeExactly $command
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Remove-Job $job -Force
|
||||
$startedJob | Remove-Job -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Basic tests' {
|
||||
|
||||
AfterEach {
|
||||
Get-Job | Where-Object { $_.Id -ne $startedJob.Id } | Remove-Job -ErrorAction SilentlyContinue -Force
|
||||
}
|
||||
|
||||
It 'Can start, wait and receive a Job' {
|
||||
$job = Start-Job -ScriptBlock { 1 + 1 }
|
||||
$result = $job | Wait-Job | Receive-Job
|
||||
ValidateJobInfo -job $job -state 'Completed' -hasMoreData $false -command ' 1 + 1 '
|
||||
$result | Should Be 2
|
||||
}
|
||||
|
||||
It 'Can run nested jobs' {
|
||||
$job = Start-Job -ScriptBlock { Start-Job -ScriptBlock { 1 + 1 } | Wait-Job | Receive-Job }
|
||||
ValidateJobInfo -job $job -state 'Running' -hasMoreData $true -command ' Start-Job -ScriptBlock { 1 + 1 } | Wait-Job | Receive-Job '
|
||||
$result = $job | Wait-Job | Receive-Job
|
||||
$result | Should Be 2
|
||||
}
|
||||
|
||||
It 'Can get errors messages from job' {
|
||||
$job = Start-Job -ScriptBlock { throw 'MyError' } | Wait-Job
|
||||
Receive-Job -Job $job -ErrorVariable ev -ErrorAction SilentlyContinue
|
||||
$ev[0].Exception.Message | Should BeExactly 'MyError'
|
||||
}
|
||||
|
||||
It 'Can get warning messages from job' {
|
||||
$job = Start-Job -ScriptBlock { Write-Warning 'MyWarning' } | Wait-Job
|
||||
Receive-Job -Job $job -WarningVariable wv -WarningAction SilentlyContinue
|
||||
$wv | Should BeExactly 'MyWarning'
|
||||
}
|
||||
|
||||
It 'Can get verbose message from job' {
|
||||
$job = Start-Job -ScriptBlock { Write-Verbose -Verbose 'MyVerbose' } | Wait-Job
|
||||
$VerboseMsg = $job.ChildJobs[0].verbose.readall()
|
||||
$VerboseMsg | Should BeExactly 'MyVerbose'
|
||||
}
|
||||
|
||||
It 'Can get progress message from job' {
|
||||
$job = Start-Job -ScriptBlock { Write-Progress -Activity 1 -Status 2 } | Wait-Job
|
||||
$ProgressMsg = $job.ChildJobs[0].progress.readall()
|
||||
$ProgressMsg[0].Activity | Should BeExactly 1
|
||||
$ProgressMsg[0].StatusDescription | Should BeExactly 2
|
||||
}
|
||||
|
||||
It "Create job with native command" {
|
||||
try {
|
||||
$nativeJob = Start-job { powershell -c 1+1 }
|
||||
$nativeJob | Wait-Job
|
||||
$nativeJob.State | Should BeExactly "Completed"
|
||||
$nativeJob.HasMoreData | Should Be $true
|
||||
Receive-Job $nativeJob | Should BeExactly 2
|
||||
Remove-Job $nativeJob
|
||||
{ Get-Job $nativeJob -ErrorAction Stop } | ShouldBeErrorId "JobWithSpecifiedNameNotFound,Microsoft.PowerShell.Commands.GetJobCommand"
|
||||
}
|
||||
finally {
|
||||
Remove-Job $nativeJob -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Wait-Job tests' {
|
||||
|
||||
BeforeAll {
|
||||
$waitJobTestCases = @(
|
||||
@{ parameters = @{ Name = $startedJob.Name } ; property = '-Name'},
|
||||
@{ parameters = @{ Id = $startedJob.Id } ; property = '-Id'},
|
||||
@{ parameters = @{ Job = $startedJob } ; property = '-Job'},
|
||||
@{ parameters = @{ InstanceId = $startedJob.InstanceId } ; property = '-InstanceId'},
|
||||
@{ parameters = @{ State = $startedJob.State } ; property = '-State'}
|
||||
)
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
Get-Job | Where-Object { $_.Id -ne $startedJob.Id } | Remove-Job -ErrorAction SilentlyContinue -Force
|
||||
}
|
||||
|
||||
It 'Can wait for jobs to complete using <property>' -TestCases $waitJobTestCases {
|
||||
param($parameters)
|
||||
$job = Wait-Job @parameters
|
||||
ValidateJobInfo -job $job -state 'Completed' -hasMoreData $true -command ' 1 + 1 '
|
||||
}
|
||||
|
||||
It 'Can wait for any job to complete' {
|
||||
$jobs = 1..3 | ForEach-Object { $seconds = $_ ; Start-Job -ScriptBlock { Start-Sleep -Seconds $using:seconds ; $using:seconds} }
|
||||
$waitedJob = Wait-Job -Job $jobs -Any
|
||||
ValidateJobInfo -job $waitedJob -state 'Completed' -hasMoreData $true -command ' Start-Sleep -Seconds $using:seconds ; $using:seconds'
|
||||
$result = $waitedJob | Receive-Job
|
||||
## We check for $result to be less than 4 so that any of the jobs completing first will considered a success.
|
||||
$result | Should BeLessThan 4
|
||||
## Check none of the jobs threw errors.
|
||||
$jobs.Error | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
It 'Can timeout waiting for a job' {
|
||||
$job = Start-Job -ScriptBlock { Start-Sleep -Seconds 10 }
|
||||
$job | Wait-Job -TimeoutSec 1
|
||||
ValidateJobInfo -job $job -state 'Running' -hasMoreData $true -command ' Start-Sleep -Seconds 10 '
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Receive-job tests' {
|
||||
It 'Can Receive-Job with state change events' {
|
||||
$result = Start-Job -Name 'ReceiveWriteEventsJob' -ScriptBlock { 1 + 1 } | Receive-Job -Wait -WriteEvents
|
||||
$result.Count | Should Be 3
|
||||
$result[0] | Should Be 2
|
||||
$result[1].GetType().FullName | Should BeExactly 'System.Management.Automation.JobStateEventArgs'
|
||||
}
|
||||
|
||||
It 'Can Receive-Job with job object and result' {
|
||||
$result = Start-Job -ScriptBlock { 1 + 1 } | Receive-Job -Wait -WriteJobInResults
|
||||
$result.Count | Should Be 2
|
||||
ValidateJobInfo -job $result[0] -command ' 1 + 1 ' -state 'Completed' -hasMoreData $false
|
||||
$result[1] | Should Be 2
|
||||
$result[0] | Remove-Job -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It 'Can Receive-Job and autoremove' {
|
||||
$result = Start-Job -Name 'ReceiveJobAutoRemove' -ScriptBlock { 1 + 1 } | Receive-Job -Wait -AutoRemoveJob
|
||||
$result | Should Be 2
|
||||
{ Get-Job -Name 'ReceiveJobAutoRemove' -ErrorAction Stop } | ShouldBeErrorId 'JobWithSpecifiedNameNotFound,Microsoft.PowerShell.Commands.GetJobCommand'
|
||||
}
|
||||
|
||||
It 'Can Receive-Job and keep results' {
|
||||
$job = Start-Job -ScriptBlock { 1 + 1 } | Wait-Job
|
||||
$result = Receive-Job -Keep -Job $job
|
||||
$result | Should Be 2
|
||||
$result2 = Receive-Job -Job $job
|
||||
$result2 | Should Be 2
|
||||
$result3 = Receive-Job -Job $job
|
||||
$result3 | Should BeNullOrEmpty
|
||||
$job | Remove-Job -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It 'Can Receive-Job with NoRecurse' {
|
||||
$job = Start-Job -ScriptBlock { 1 + 1 }
|
||||
$result = Receive-Job -Wait -NoRecurse -Job $job
|
||||
$result | Should BeNullOrEmpty
|
||||
$job | Remove-Job -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It 'Can Receive-Job using ComputerName' {
|
||||
$jobName = 'ReceiveUsingComputerName'
|
||||
$job = Start-Job -ScriptBlock { 1 + 1 } -Name $jobName | Wait-Job
|
||||
$result = Receive-Job -ComputerName localhost -Job $job
|
||||
$result | Should Be 2
|
||||
$job | Remove-Job -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It 'Can Receive-Job using Location' {
|
||||
$jobName = 'ReceiveUsingLocation'
|
||||
$job = Start-Job -ScriptBlock { 1 + 1 } -Name $jobName | Wait-Job
|
||||
$result = Receive-Job -Location localhost -Job $job
|
||||
$result | Should Be 2
|
||||
$job | Remove-Job -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It 'Can receive a job with -wait switch' {
|
||||
$job = Start-Job -ScriptBlock { 1 + 1 }
|
||||
$result = $job | Receive-Job -Wait
|
||||
ValidateJobInfo -job $job -state 'Completed' -hasMoreData $false -command ' 1 + 1 '
|
||||
$result | Should Be 2
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Get-Job tests' {
|
||||
BeforeAll {
|
||||
$getJobTestCases = @(
|
||||
@{ parameters = @{ Name = $startedJob.Name } ; property = 'Name'},
|
||||
@{ parameters = @{ Id = $startedJob.Id } ; property = 'Id'},
|
||||
@{ parameters = @{ InstanceId = $startedJob.InstanceId } ; property = 'InstanceId'},
|
||||
@{ parameters = @{ State = $startedJob.State } ; property = 'State'}
|
||||
)
|
||||
|
||||
$getJobSwitches = @(
|
||||
@{ parameters = @{ Before = $timeAfterStartedJob }; property = '-Before'},
|
||||
@{ parameters = @{ After = $timeBeforeStartedJob }; property = '-After'},
|
||||
@{ parameters = @{ HasMoreData = $true }; property = '-HasMoreData'}
|
||||
)
|
||||
|
||||
$getJobChildJobs = @(
|
||||
@{ parameters = @{ IncludeChildJob = $true }; property = '-IncludeChildJob'},
|
||||
@{ parameters = @{ ChildJobState = 'Completed' }; property = '-ChildJobState'}
|
||||
)
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
Get-Job | Where-Object { $_.Id -ne $startedJob.Id } | Remove-Job -ErrorAction SilentlyContinue -Force
|
||||
}
|
||||
|
||||
It 'Can Get-Job with <property>' -TestCases $getJobTestCases {
|
||||
param($parameters)
|
||||
$job = Get-Job @parameters
|
||||
ValidateJobInfo -job $job -state 'Completed' -hasMoreData $true -command ' 1 + 1 '
|
||||
}
|
||||
|
||||
It 'Can Get-Job with <property>' -TestCases $getJobSwitches {
|
||||
param($parameters)
|
||||
$job = Get-Job @parameters
|
||||
ValidateJobInfo -job $job -state 'Completed' -hasMoreData $true -Name 'StartedJob'
|
||||
}
|
||||
|
||||
It 'Can Get-Job with <property>' -TestCases $getJobChildJobs {
|
||||
param($parameters)
|
||||
$jobs = Get-Job @parameters
|
||||
$jobs.Count | Should Be 2
|
||||
ValidateJobInfo -job $jobs[0] -state 'Completed' -hasMoreData $true -Name 'StartedJob'
|
||||
ValidateJobInfo -job $jobs[1] -state 'Completed' -hasMoreData $true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Context 'Remove-Job tests' {
|
||||
# The test pattern used here is different from other tests since there is a scoping issue in Pester.
|
||||
# If BeforeEach is used then $removeJobTestCases does not bind when the It is called.
|
||||
# This implementation works around the problem by using a BeforeAll and creating a job inside the It.
|
||||
BeforeAll {
|
||||
$removeJobTestCases = @(
|
||||
@{ property = 'Name'}
|
||||
@{ property = 'Id'}
|
||||
@{ property = 'InstanceId'}
|
||||
@{ property = 'State'}
|
||||
)
|
||||
}
|
||||
|
||||
It 'Can Remove-Job with <property>' -TestCases $removeJobTestCases {
|
||||
param($property)
|
||||
$jobToRemove = Start-Job -ScriptBlock { 1 + 1 } -Name 'JobToRemove' | Wait-Job
|
||||
$splat = @{ $property = $jobToRemove.$property }
|
||||
Remove-Job @splat
|
||||
Get-Job $jobToRemove -ErrorAction SilentlyContinue | Should BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Stop-Job tests' {
|
||||
# The test pattern used here is different from other tests since there is a scoping issue in Pester.
|
||||
# If BeforeEach is used then $stopJobTestCases does not bind when the It is called.
|
||||
# This implementation works around the problem by using a BeforeAll and creating a job inside the It.
|
||||
BeforeAll {
|
||||
$stopJobTestCases = @(
|
||||
@{ property = 'Name'}
|
||||
@{ property = 'Id'}
|
||||
@{ property = 'InstanceId'}
|
||||
@{ property = 'State'}
|
||||
)
|
||||
# '-Seconds 100' is chosen to be substantially large, so that the job is in running state when Stop-Job is called.
|
||||
$jobToStop = Start-Job -ScriptBlock { Start-Sleep -Seconds 100 } -Name 'JobToStop'
|
||||
}
|
||||
|
||||
It 'Can Stop-Job with <property>' -TestCases $stopJobTestCases {
|
||||
param($property)
|
||||
$splat = @{ $property = $jobToStop.$property }
|
||||
Stop-Job @splat
|
||||
ValidateJobInfo -job $jobToStop -state 'Stopped' -hasMoreData $false
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Remove-Job $jobToStop -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
Describe "New-PSSession basic test" -Tag @("CI") {
|
||||
It "New-PSSession should not crash powershell" {
|
||||
try {
|
||||
|
@ -10,41 +9,78 @@ Describe "New-PSSession basic test" -Tag @("CI") {
|
|||
}
|
||||
}
|
||||
|
||||
Describe "JEA session Transcprit script test" -Tag @("Feature", 'RequireAdminOnWindows') {
|
||||
It "Configuration name should be in the transcript header" -Pending {
|
||||
Describe "JEA session Transcript script test" -Tag @("Feature", 'RequireAdminOnWindows') {
|
||||
BeforeAll {
|
||||
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
|
||||
|
||||
if ( ! $IsWindows )
|
||||
{
|
||||
$PSDefaultParameterValues["it:skip"] = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck
|
||||
}
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$global:PSDefaultParameterValues = $originalDefaultParameterValues
|
||||
}
|
||||
|
||||
It "Configuration name should be in the transcript header" {
|
||||
[string] $RoleCapDirectory = (New-Item -Path "$TestDrive\RoleCapability" -ItemType Directory -Force).FullName
|
||||
[string] $PSSessionConfigFile = "$RoleCapDirectory\TestConfig.pssc"
|
||||
[string] $transScriptFile = "$RoleCapDirectory\*.txt"
|
||||
try
|
||||
{
|
||||
New-PSSessionConfigurationFile -Path $PSSessionConfigFile -TranscriptDirectory $RoleCapDirectory -SessionType RestrictedRemoteServer
|
||||
Register-PSSessionConfiguration -Name JEA -Path $PSSessionConfigFile -Force -ErrorAction SilentlyContinue
|
||||
$scriptBlock = {Enter-PSSession -ComputerName Localhost -ConfigurationName JEA; Exit-PSSession}
|
||||
& $scriptBlock
|
||||
Register-PSSessionConfiguration -Name JEA -Path $PSSessionConfigFile -Force -ErrorAction SilentlyContinue
|
||||
$scriptBlock = {Enter-RemoteSession -ComputerName Localhost -ConfigurationName JEA; Exit-PSSession}
|
||||
# Invoke the script block in a different PowerShell instance so that when TestDrive tries to delete $RoleCapDirectory,
|
||||
# the transcription has finished and the files are not locked.
|
||||
[powershell]::Create().AddScript($scriptBlock).Invoke()
|
||||
$headerFile = Get-ChildItem $transScriptFile | Sort-Object LastWriteTime | Select-Object -Last 1
|
||||
$header = Get-Content $headerFile | Out-String
|
||||
$header | Should BeLike "Configuration Name: JEA"
|
||||
$header | Should Match "Configuration Name: JEA"
|
||||
}
|
||||
finally
|
||||
{
|
||||
Unregister-PSSessionConfiguration -Name JEA -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Describe "JEA session Get-Help test" -Tag @("CI", 'RequireAdminOnWindows') {
|
||||
It "Get-Help should work in JEA sessions" -Pending {
|
||||
BeforeAll {
|
||||
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
|
||||
|
||||
if ( ! $IsWindows )
|
||||
{
|
||||
$PSDefaultParameterValues["it:skip"] = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck
|
||||
}
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$global:PSDefaultParameterValues = $originalDefaultParameterValues
|
||||
}
|
||||
|
||||
It "Get-Help should work in JEA sessions" {
|
||||
[string] $RoleCapDirectory = (New-Item -Path "$TestDrive\RoleCapability" -ItemType Directory -Force).FullName
|
||||
[string] $PSSessionConfigFile = "$RoleCapDirectory\TestConfig.pssc"
|
||||
try
|
||||
{
|
||||
New-PSSessionConfigurationFile -Path $PSSessionConfigFile -TranscriptDirectory $RoleCapDirectory -SessionType RestrictedRemoteServer
|
||||
Register-PSSessionConfiguration -Name JEA -Path $PSSessionConfigFile -Force -ErrorAction SilentlyContinue
|
||||
$scriptBlock = {Enter-PSSession -ComputerName Localhost -ConfigurationName JEA; Get-Help Get-Command; Exit-PSSession}
|
||||
$helpContent = & $scriptBlock
|
||||
$helpContent | Should Not Be $null
|
||||
Register-PSSessionConfiguration -Name JEA -Path $PSSessionConfigFile -Force -ErrorAction SilentlyContinue
|
||||
$scriptBlock = {Enter-RemoteSession -ComputerName Localhost -ConfigurationName JEA; Get-Help Get-Command; Exit-PSSession}
|
||||
# Invoke the script block in a different PowerShell instance so that when TestDrive tries to delete $RoleCapDirectory,
|
||||
# the transcription has finished and the files are not locked.
|
||||
$helpContent = [powershell]::Create().AddScript($scriptBlock).Invoke()
|
||||
$helpContent | Should Not Be $null
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -52,5 +88,195 @@ Describe "JEA session Get-Help test" -Tag @("CI", 'RequireAdminOnWindows') {
|
|||
Remove-Item $RoleCapDirectory -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Remoting loopback tests" -Tags @('CI', 'RequireAdminOnWindows') {
|
||||
BeforeAll {
|
||||
|
||||
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
|
||||
|
||||
if ( ! $IsWindows )
|
||||
{
|
||||
$PSDefaultParameterValues["it:skip"] = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
Enable-PSRemoting -SkipNetworkProfileCheck
|
||||
$endPoint = (Get-PSSessionConfiguration -Name "PowerShell.$(${PSVersionTable}.GitCommitId)").Name
|
||||
$disconnectedSession = New-RemoteSession -ConfigurationName $endPoint -ComputerName localhost | Disconnect-PSSession
|
||||
$closedSession = New-RemoteSession -ConfigurationName $endPoint -ComputerName localhost
|
||||
$closedSession.Runspace.Close()
|
||||
$openSession = New-RemoteSession -ConfigurationName $endPoint
|
||||
|
||||
$ParameterError = @(
|
||||
@{
|
||||
parameters = @{
|
||||
'InDisconnectedSession' = $true
|
||||
'AsJob' = $true
|
||||
'ScriptBlock' = {1}
|
||||
'ComputerName' = 'localhost'
|
||||
'ConfigurationName' = $endpoint
|
||||
}
|
||||
expectedError = 'System.InvalidOperationException,Microsoft.PowerShell.Commands.InvokeCommandCommand'
|
||||
title = 'Cannot use InDisconnectedState and AsJob together'
|
||||
},
|
||||
@{
|
||||
parameters = @{
|
||||
'ScriptBlock' = {1}
|
||||
'SessionName' = 'SomeSessionName'
|
||||
}
|
||||
expectedError = 'System.InvalidOperationException,Microsoft.PowerShell.Commands.InvokeCommandCommand'
|
||||
title = 'Cannot use SessionName without InDisconnectedSession'
|
||||
},
|
||||
@{
|
||||
parameters = @{
|
||||
'ScriptBlock' = { 1 }
|
||||
'Session' = $disconnectedSession
|
||||
'ErrorAction' = 'Stop'
|
||||
}
|
||||
expectedError = 'InvokeCommandCommandInvalidSessionState,Microsoft.PowerShell.Commands.InvokeCommandCommand'
|
||||
title = 'Cannot use Invoke-Command on a disconnected session'
|
||||
}
|
||||
@{
|
||||
parameters = @{
|
||||
'ScriptBlock' = { 1 }
|
||||
'Session' = $closedSession
|
||||
'ErrorAction' = 'Stop'
|
||||
}
|
||||
expectedError = 'InvokeCommandCommandInvalidSessionState,Microsoft.PowerShell.Commands.InvokeCommandCommand'
|
||||
title = 'Cannot use Invoke-Command on a closed session'
|
||||
}
|
||||
)
|
||||
|
||||
function script:ValidateSessionInfo($session, $state)
|
||||
{
|
||||
$session.ComputerName | Should BeExactly 'localhost'
|
||||
$session.ConfigurationName | Should BeExactly $endPoint
|
||||
$session.State | Should Be $state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$global:PSDefaultParameterValues = $originalDefaultParameterValues
|
||||
|
||||
if($isWindows)
|
||||
{
|
||||
Remove-PSSession $disconnectedSession,$closedSession,$openSession -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
It 'Can connect to default endpoint' {
|
||||
$session = New-RemoteSession -ConfigurationName $endPoint
|
||||
|
||||
try
|
||||
{
|
||||
ValidateSessionInfo -session $session -state 'Opened'
|
||||
}
|
||||
finally
|
||||
{
|
||||
$session | Remove-PSSession -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
It 'Can execute command in a disconnected session' {
|
||||
$session = Invoke-RemoteCommand -InDisconnectedSession -ComputerName 'localhost' -ScriptBlock { 1 + 1 } -ConfigurationName $endPoint
|
||||
try
|
||||
{
|
||||
ValidateSessionInfo -session $session -state 'Disconnected'
|
||||
|
||||
$result = Receive-PSSession -Session $session
|
||||
$result | Should Be 2
|
||||
$result.PSComputerName | Should BeExactly 'localhost'
|
||||
}
|
||||
finally
|
||||
{
|
||||
$session | Remove-PSSession -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
It 'Can disconnect and connect to PSSession' {
|
||||
$session = New-RemoteSession -ConfigurationName $endPoint
|
||||
try
|
||||
{
|
||||
ValidateSessionInfo -session $session -state 'Opened'
|
||||
Disconnect-PSSession -Session $session
|
||||
|
||||
ValidateSessionInfo -session $session -state 'Disconnected'
|
||||
Connect-RemoteSession -Session $session
|
||||
|
||||
$result = Invoke-Command -Session $session -ScriptBlock { 1 + 1 }
|
||||
$result | Should Be 2
|
||||
$result.PSComputerName | Should BeExactly 'localhost'
|
||||
}
|
||||
finally
|
||||
{
|
||||
$session | Remove-PSSession -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
It "<title>" -TestCases $ParameterError {
|
||||
param($parameters, $expectedError)
|
||||
|
||||
{ Invoke-Command @parameters } | ShouldBeErrorId $expectedError
|
||||
}
|
||||
|
||||
It 'Can execute command if one of the sessions is available' {
|
||||
try
|
||||
{
|
||||
$result = Invoke-Command -Session $openSession,$disconnectedSession,$closedSession -ScriptBlock { 1+1 } -ErrorAction SilentlyContinue
|
||||
}
|
||||
catch
|
||||
{
|
||||
if($_.FullyQualifiedErrorId -ne 'InvokeCommandCommandInvalidSessionState,Microsoft.PowerShell.Commands.InvokeCommandCommand')
|
||||
{
|
||||
# We expect the error from $disconnectedSession and $closedSession. Hence, throw otherwise.
|
||||
throw $_
|
||||
}
|
||||
}
|
||||
|
||||
$result.Count | Should Be 1
|
||||
$result | Should Be 2
|
||||
}
|
||||
|
||||
It 'Can execute command without creating new scope' {
|
||||
Invoke-Command -NoNewScope -ScriptBlock { $sameScopeVariable = 'SetInCurrentScope' }
|
||||
$sameScopeVariable | Should BeExactly 'SetInCurrentScope'
|
||||
}
|
||||
|
||||
It 'Can execute command from a file' {
|
||||
$fileName = "$testdrive/remotingscript.ps1"
|
||||
'1 + 1' | Out-File $fileName
|
||||
$result = Invoke-Command -FilePath $fileName -Session $openSession
|
||||
$result | Should Be 2
|
||||
}
|
||||
|
||||
It 'Can invoke-command as job' {
|
||||
$result = Invoke-Command -ScriptBlock { 1 + 1 } -Session $openSession -AsJob | Receive-Job -AutoRemoveJob -Wait
|
||||
$result | Should Be 2
|
||||
}
|
||||
|
||||
It 'Can connect to all disconnected sessions by name' {
|
||||
$connectionNames = @("DiscPSS$(Get-Random)", "DiscPSS$(Get-Random)")
|
||||
$connectionNames | ForEach-Object { $null = New-RemoteSession -ComputerName localhost -ConfigurationName $endpoint -Name $_ | Disconnect-PSSession}
|
||||
|
||||
Connect-RemoteSession -ComputerName localhost -Name $connectionNames -ConfigurationName $endpoint
|
||||
$sessions = Get-PSSession -Name $connectionNames
|
||||
try
|
||||
{
|
||||
$sessions | ForEach-Object {
|
||||
ValidateSessionInfo -session $_ -state 'Opened'
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
$sessions | Remove-PSSession -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
It 'Can pass values through $using' {
|
||||
$number = 100
|
||||
$result = Invoke-Command -Session $openSession -ScriptBlock { $using:number }
|
||||
$result | Should Be 100
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,6 @@ Copyright = 'Copyright (C) Microsoft Corporation, All rights reserved.'
|
|||
|
||||
Description = 'Temporary module for remoting tests'
|
||||
|
||||
FunctionsToExport = 'New-RemoteRunspace', 'New-RemoteSession'
|
||||
FunctionsToExport = 'New-RemoteRunspace', 'New-RemoteSession', 'Enter-RemoteSession', 'Invoke-RemoteCommand', 'Connect-RemoteSession'
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ if ($IsWindows) {
|
|||
try { $Script:AppVeyorRemoteCred = Import-Clixml -Path "$env:TEMP\AppVeyorRemoteCred.xml" } catch { }
|
||||
}
|
||||
|
||||
|
||||
function New-RemoteRunspace
|
||||
{
|
||||
$wsmanConInfo = [System.Management.Automation.Runspaces.WSManConnectionInfo]::new()
|
||||
|
@ -29,16 +28,30 @@ function New-RemoteRunspace
|
|||
return $remoteRunspace
|
||||
}
|
||||
|
||||
|
||||
function New-RemoteSession
|
||||
function CreateParameters
|
||||
{
|
||||
param (
|
||||
[string] $Name,
|
||||
[string] $ComputerName,
|
||||
[string[]] $Name,
|
||||
[string] $ConfigurationName,
|
||||
[switch] $CimSession,
|
||||
[System.Management.Automation.Remoting.PSSessionOption] $SessionOption)
|
||||
[System.Management.Automation.Remoting.PSSessionOption] $SessionOption,
|
||||
[System.Management.Automation.Runspaces.PSSession[]] $Session)
|
||||
|
||||
$parameters = @{ ComputerName = "."; }
|
||||
if($ComputerName)
|
||||
{
|
||||
$parameters = @{ComputerName = $ComputerName}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($Session)
|
||||
{
|
||||
$parameters = @{Session = $Session}
|
||||
}
|
||||
else
|
||||
{
|
||||
$parameters = @{ComputerName = '.'}
|
||||
}
|
||||
}
|
||||
|
||||
if ($Name) {
|
||||
$parameters["Name"] = $Name
|
||||
|
@ -52,7 +65,8 @@ function New-RemoteSession
|
|||
$parameters["SessionOption"] = $SessionOption
|
||||
}
|
||||
|
||||
if ($Script:AppVeyorRemoteCred)
|
||||
## If a PSSession is provided, do not add credentials.
|
||||
if ($Script:AppVeyorRemoteCred -and (-not $Session))
|
||||
{
|
||||
Write-Verbose "Using Global AppVeyor Credential" -Verbose
|
||||
$parameters["Credential"] = $Script:AppVeyorRemoteCred
|
||||
|
@ -62,6 +76,18 @@ function New-RemoteSession
|
|||
Write-Verbose "Using Implicit Credential" -Verbose
|
||||
}
|
||||
|
||||
return $parameters
|
||||
}
|
||||
function New-RemoteSession
|
||||
{
|
||||
param (
|
||||
[string] $Name,
|
||||
[string] $ConfigurationName,
|
||||
[switch] $CimSession,
|
||||
[System.Management.Automation.Remoting.PSSessionOption] $SessionOption)
|
||||
|
||||
$parameters = CreateParameters -Name $Name -ConfigurationName $ConfigurationName -SessionOption $SessionOption
|
||||
|
||||
if ($CimSession) {
|
||||
$session = New-CimSession @parameters
|
||||
} else {
|
||||
|
@ -70,3 +96,50 @@ function New-RemoteSession
|
|||
|
||||
return $session
|
||||
}
|
||||
|
||||
function Invoke-RemoteCommand
|
||||
{
|
||||
param (
|
||||
[string] $ComputerName,
|
||||
[scriptblock] $ScriptBlock,
|
||||
[string] $ConfigurationName,
|
||||
[switch] $InDisconnectedSession)
|
||||
|
||||
$parameters = CreateParameters -ComputerName $ComputerName -ConfigurationName $ConfigurationName
|
||||
|
||||
if($ScriptBlock)
|
||||
{
|
||||
$parameters.Add('ScriptBlock', $ScriptBlock)
|
||||
}
|
||||
|
||||
if($InDisconnectedSession)
|
||||
{
|
||||
$parameters.Add('InDisconnectedSession', $InDisconnectedSession.IsPresent)
|
||||
}
|
||||
|
||||
Invoke-Command @parameters
|
||||
}
|
||||
|
||||
function Enter-RemoteSession
|
||||
{
|
||||
param(
|
||||
[string] $Name,
|
||||
[string] $ConfigurationName,
|
||||
[System.Management.Automation.Remoting.PSSessionOption] $SessionOption)
|
||||
|
||||
$parameters = CreateParameters -Name $Name -ConfigurationName $ConfigurationName -SessionOption $SessionOption
|
||||
Enter-PSSession @parameters
|
||||
}
|
||||
|
||||
function Connect-RemoteSession
|
||||
{
|
||||
param(
|
||||
[string] $ComputerName,
|
||||
[string[]] $Name,
|
||||
[System.Management.Automation.Runspaces.PSSession[]] $Session,
|
||||
[string] $ConfigurationName
|
||||
)
|
||||
|
||||
$parameters = CreateParameters -ComputerName $ComputerName -Name $Name -Session $Session -ConfigurationName $ConfigurationName
|
||||
Connect-PSSession @parameters
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue