Skip to content
This repository was archived by the owner on Dec 8, 2021. It is now read-only.

Added node hash instead of machineConfig.csv. #18

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 19 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
Note
============
See forked project at https://github.com/DexterPOSH/PSRemotely.

Synopsis
============
Executes a script block against a remote runspace. Remotely can be used with Pester for executing script blocks on a remote system.

Description
======================
The contents on the Remotely block are executed on a remote runspace. The connection information of the runspace is supplied in a CSV file of the format:

```
ComputerName,Username,Password
ComputerName1,Username1,Password1
ComputerName2,Username2,Password2
```

The filename must be `machineConfig.csv`.

The CSV file is expected to be placed next to this file.

If the CSV file is not found or username is not specified, the machine name is ignored and runspace to localhost
is created for executing the script block.

If the password has a ',' then it needs to be escaped by using quotes like:

```
ComputerName,Username,Password
ComputerName1,Username1,Password1
ComputerName2,Username2,"Some,other,password"
```
The contents on the Remotely block are executed on a remote runspace. The connection information of the runspace is supplied using the -Nodes parameter or as the argument to the first positional parameter. By default, this assumes the local credentials have access to the remote session configuration on the target nodes.

To get access to the streams, use GetVerbose, GetDebugOutput, GetError, GetProgressOutput,
GetWarning on the resultant object.
Expand All @@ -35,19 +18,28 @@ Example
Usage in Pester:

```powershell
$my_creds = Get-Credential
$node1_hash = @{}
$node1_hash.add("authentication","credssp")
$node1_hash.add("credential",$my_creds)

# All k,v pairs in $node1_hash are passed to New-PSSession for the specific node.
$remotely_nodes = @{}
$remotely_nodes.add("localhost",$node1_hash)

Describe "Add-Numbers" {
It "adds positive numbers" {
Remotely { 2 + 3 } | Should Be 5
It "adds positive numbers on a remote system" {
Remotely -Nodes $remotely_nodes -ScriptBlock { 2 + 3 } | Should Be 5
}

It "gets verbose message" {
$sum = Remotely { Write-Verbose -Verbose "Test Message" }
$sum = Remotely -Nodes $remotely_nodes -ScriptBlock { Write-Verbose -Verbose "Test Message" }
$sum.GetVerbose() | Should Be "Test Message"
}

It "can pass parameters to remote block" {
It "can pass parameters to remote block with different credentials" {
$num = 10
$process = Remotely { param($number) $number + 1 } -ArgumentList $num
$process = Remotely -Nodes $remotely_nodes -ScriptBlock { Param($number) $number + 1 } -ArgumentList $num
$process | Should Be 11
}
}
Expand All @@ -65,5 +57,3 @@ Pester-based tests are located in ```<branch>/Remotely.Tests.ps1```
* Ensure Pester is installed on the machine
* Run tests:
.\Remotely.Tests.ps1

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
229 changes: 47 additions & 182 deletions Remotely.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,106 +1,45 @@
# Function to update the table that defines the machineconfig.csv
# based on test environment variables
Function Update-ConfigContentTable
{
param(
[parameter(Mandatory=$true)]
[HashTable]$configContentTable

)
$VerbosePreference = "continue"

if($global:AppveyorRemotelyUserName -or $global:AppveyorRemotelyPassword)
{
$computername = $configContentTable.ComputerName
if($computername -ieq 'localhost')
{
$computername = '127.0.0.1'
}
elseif ( $computername -ieq '.')
{
$computername = '::1'
}

$configContentTable.ComputerName = $computername
}

if($global:AppveyorRemotelyUserName)
{
$configContentTable['Username']=$global:AppveyorRemotelyUserName
}

if($global:AppveyorRemotelyPassword)
{
$configContentTable['Password']=$global:AppveyorRemotelyPassword
}

return $configContentTable
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
If((Get-Module | Select-Object Name -ExpandProperty Name) -contains "Remotely") {
Remove-Module "Remotely"
}
$mod_path = $here.trimend("\") + "\Remotely.psm1"
Import-Module $mod_path

Describe "Add-Numbers" {
BeforeAll {
$configFile = (join-path $PSScriptRoot 'machineConfig.csv')
$configContentTable = @{ComputerName = "localhost" }
Update-ConfigContentTable -configContentTable $configContentTable
$configContent = @([pscustomobject] $configContentTable) | ConvertTo-Csv -NoTypeInformation
$configContent | Out-File -FilePath $configFile -Force
}
$testcases = @( @{NoSessionValue = $true}, @{NoSessionValue = $false})

It "can execute script with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)

$expectedRemotelyTarget = 'localhost'
if($configContentTable['Computername'])
{
$expectedRemotelyTarget = $configContentTable['Computername']
}

$output = Remotely { 1 + 1 } -NoSession:$NoSessionValue
$output | Should Be 2

if($NoSessionValue -eq $true)
{
$output.RemotelyTarget | Should BeNullOrEmpty
}
else
{
$output.RemotelyTarget | Should Be $expectedRemotelyTarget
}
}
It "can execute script" {
Remotely { 1 + 1 } | Should Be 2
}

It "can return an array with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$returnObjs = Remotely { 1..10 } -NoSession:$NoSessionValue
It "can return an array" {
$returnObjs = Remotely { 1..10 }
$returnObjs.count | Should Be 10
}

It "can return a hashtable with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$returnObjs = Remotely { @{Value = 2} } -NoSession:$NoSessionValue
It "can return a hashtable" {
$returnObjs = Remotely { @{Value = 2} }
$returnObjs["Value"] | Should Be 2
}

It "can get verbose message with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$output = Remotely { Write-Verbose -Verbose "Verbose Message" } -NoSession:$NoSessionValue
It "can get verbose message" {
$output = Remotely { Write-Verbose -Verbose "Verbose Message" }
$output.GetVerbose() | Should Be "Verbose Message"
}

It "can get error message with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$output = Remotely { Write-Error "Error Message" } -NoSession:$NoSessionValue
It "can get error message" {
$output = Remotely { Write-Error "Error Message" }
$output.GetError() | Should Be "Error Message"
}

It "can get warning message with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$output = Remotely { Write-Warning "Warning Message" } -NoSession:$NoSessionValue
It "can get warning message" {
$output = Remotely { Write-Warning "Warning Message" }
$output.GetWarning() | Should Be "Warning Message"
}

It "can get debug message with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$output = Remotely -NoSession:$NoSessionValue {
It "can get debug message" {
$output = Remotely {
$originalPreference = $DebugPreference
$DebugPreference = "continue"
Write-Debug "Debug Message"
Expand All @@ -109,49 +48,39 @@ Describe "Add-Numbers" {
$output.GetDebugOutput() | Should Be "Debug Message"
}

It "can get progress message with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$output = Remotely -NoSession:$NoSessionValue { Write-Progress -Activity "Test" -Status "Testing" -Id 1 -PercentComplete 100 -SecondsRemaining 0 }
It "can get progress message" {
$output = Remotely { Write-Progress -Activity "Test" -Status "Testing" -Id 1 -PercentComplete 100 -SecondsRemaining 0 }
$output.GetProgressOutput().Activity | Should Be "Test"
$output.GetProgressOutput().StatusDescription | Should Be "Testing"
$output.GetProgressOutput().ActivityId | Should Be 1
}

It 'can return $false as a value with NoSessionValue : <NoSessionValue>' -TestCases $testcases {
param($NoSessionValue)
$output = Remotely { $false } -NoSession:$NoSessionValue
It 'can return $false as a value' {
$output = Remotely { $false }
$output | Should Be $false
}

It 'can return throw messages with NoSessionValue : <NoSessionValue>' -TestCases $testcases {
param($NoSessionValue)
$output = Remotely { throw 'bad' } -NoSession:$NoSessionValue
It 'can return throw messages' {
$output = Remotely { throw 'bad' }
$output.GetError().FullyQualifiedErrorId | Should Be 'bad'
}

It "can pass parameters to remote block with NoSessionValue : <NoSessionValue>" -TestCases $testcases {
param($NoSessionValue)
$num = 10
$process = Remotely { param($number) $number + 1 } -ArgumentList $num -NoSession:$NoSessionValue
$process | Should Be 11
}

It "can get remote sessions" {
It "can get remote sessions" {
Remotely { 1 + 1 } | Should Be 2
$remoteSessions = Get-RemoteSession

$remoteSessions | % { $remoteSessions.Name -match "Remotely" | Should Be $true}
$remoteSessions | ForEach-Object { $remoteSessions.Name -match "Remotely" | Should Be $true}
}

It "can pass parameters to remote block" {
$num = 10
$process = Remotely { param($number) $number + 1 } -ArgumentList $num
$process | Should Be 11
}

It "can get target of the remotely block" {
$expectedRemotelyTarget = 'localhost'
if($configContentTable['Computername'])
{
$expectedRemotelyTarget = $configContentTable['Computername']
}

$output = Remotely { 1 }
$output.RemotelyTarget | Should Be $expectedRemotelyTarget
$output.RemotelyTarget | Should Be "localhost"
}

It "can handle delete sessions" {
Expand All @@ -166,91 +95,27 @@ Describe "Add-Numbers" {
}

It "can execute against more than 1 remote machines" {
# Testing with no configuration name for compatibility
$configFile = (join-path $PSScriptRoot 'machineConfig.csv')
$configContentTable = @{ComputerName = "localhost" }
Update-ConfigContentTable -configContentTable $configContentTable
$configContentTable2 = @{ComputerName = "." }
Update-ConfigContentTable -configContentTable $configContentTable2
$configContent = @([pscustomobject] $configContentTable, [pscustomobject] $configContentTable2) | ConvertTo-Csv -NoTypeInformation
$configContent | Out-File -FilePath $configFile -Force
$nodes = @{}
$nodes.add('localhost',$null)
$nodes.add([string]$env:computername,$null)

try
{
$results = Remotely { 1 + 1 }
try {
$results = Remotely { 1 + 1 } -Nodes $nodes
$results.Count | Should Be 2

foreach($result in $results)
{
foreach($result in $results) {
$result | Should Be 2
}
}
catch
{
catch{
$_.FullyQualifiedErrorId | Should Be $null
}
finally
{
Remove-Item $configFile -ErrorAction SilentlyContinue -Force
}
}
}

Describe "ConfigurationName" {
BeforeAll {
$configFile = (join-path $PSScriptRoot 'machineConfig.csv')
}
AfterAll {
Remove-Item $configFile -ErrorAction SilentlyContinue -Force
}
Context "Default configuration name" {
$configContentTable = @{
ComputerName = "localhost"
Username = $null
Password = $null
ConfigurationName = "Microsoft.PowerShell"
}
Update-ConfigContentTable -configContentTable $configContentTable
$configContent = @([pscustomobject] $configContentTable) | ConvertTo-Csv -NoTypeInformation
$configContent | Out-File -FilePath $configFile -Force

it "Should connect when a configurationName is specified" {

$results = Remotely { 1 + 1 }

$results | Should Be 2
}
}

Context "Invalid configuration name" {

Write-Verbose "Clearing remote session..." -Verbose
Clear-RemoteSession
$configContentTable = @{
ComputerName = "localhost"
Username = $null
Password = $null
ConfigurationName = "Microsoft.PowerShell2"
finally {
}
Update-ConfigContentTable -configContentTable $configContentTable
$configContent = @([pscustomobject] $configContentTable) | ConvertTo-Csv -NoTypeInformation
$configContent | Out-File -FilePath $configFile -Force

$expectedRemotelyTarget = 'localhost'
if($configContentTable['Computername'])
{
$expectedRemotelyTarget = $configContentTable['Computername']
}


it "Should not connect to an invalid ConfigurationName" {
{$results = Remotely { 1 + 1 }} | should throw "Connecting to remote server $expectedRemotelyTarget failed with the following error message : The WS-Management service cannot process the request. Cannot find the Microsoft.PowerShell2 session configuration in the WSMan: drive on the $expectedRemotelyTarget computer. For more information, see the about_Remote_Troubleshooting Help topic."
}
}
}
Describe "Clear-RemoteSession" {

It "can clear remote sessions" {
Clear-RemoteSession
Get-PSSession -Name Remotely* | Should Be $null
}
}
}
2 changes: 1 addition & 1 deletion Remotely.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
ModuleToProcess = 'Remotely.psm1'

# Version number of this module.
ModuleVersion = '1.0.0'
ModuleVersion = '1.0.1'

# ID used to uniquely identify this module
GUID = 'a20c9efd-077e-4c53-a500-f74dec071799'
Expand Down
Loading