From ad9552a681f850a6b389bb817e3ab9947f6cc92f Mon Sep 17 00:00:00 2001 From: PaulHigin Date: Fri, 27 Jan 2017 16:01:07 -0800 Subject: [PATCH 1/5] Changes to implement remote endpoint RoleDefinition RoleCapabilityFiles keyword --- .../commands/NewPSSessionConfigurationFile.cs | 2 +- .../fanin/InitialSessionStateProvider.cs | 47 ++++++++++- .../resources/RemotingErrorIdStrings.resx | 11 ++- .../Remoting/RoleCapabilityFiles.Tests.ps1 | 84 +++++++++++++++++++ 4 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 diff --git a/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs b/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs index 74c394ddb64..503a17e5b3d 100644 --- a/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs +++ b/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs @@ -735,7 +735,7 @@ protected override void ProcessRecord() if (_roleDefinitions == null) { result.Append(SessionConfigurationUtils.ConfigFragment(ConfigFileConstants.RoleDefinitions, RemotingErrorIdStrings.DISCRoleDefinitionsComment, - "@{ 'CONTOSO\\SqlAdmins' = @{ RoleCapabilities = 'SqlAdministration' }; 'CONTOSO\\ServerMonitors' = @{ VisibleCmdlets = 'Get-Process' } } ", streamWriter, true)); + "@{ 'CONTOSO\\SqlAdmins' = @{ RoleCapabilities = 'SqlAdministration' }; 'CONTOSO\\SqlManaged' = @{ RoleCapabilityFiles = 'C:\\RoleCapability\\SqlManaged.psrc' }; 'CONTOSO\\ServerMonitors' = @{ VisibleCmdlets = 'Get-Process' } } ", streamWriter, true)); } else { diff --git a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs index b2e20c02073..59a6ac952b3 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs @@ -947,6 +947,7 @@ internal static class ConfigFileConstants internal static readonly string ScriptsToProcess = "ScriptsToProcess"; internal static readonly string SessionType = "SessionType"; internal static readonly string RoleCapabilities = "RoleCapabilities"; + internal static readonly string RoleCapabilityFiles = "RoleCapabilityFiles"; internal static readonly string RunAsVirtualAccount = "RunAsVirtualAccount"; internal static readonly string RunAsVirtualAccountGroups = "RunAsVirtualAccountGroups"; internal static readonly string TranscriptDirectory = "TranscriptDirectory"; @@ -981,6 +982,7 @@ internal static class ConfigFileConstants new ConfigTypeEntry(PowerShellVersion, new ConfigTypeEntry.TypeValidationCallback(StringTypeValidationCallback)), new ConfigTypeEntry(RequiredGroups, new ConfigTypeEntry.TypeValidationCallback(HashtableTypeValidationCallback)), new ConfigTypeEntry(RoleCapabilities, new ConfigTypeEntry.TypeValidationCallback(StringArrayTypeValidationCallback)), + new ConfigTypeEntry(RoleCapabilityFiles, new ConfigTypeEntry.TypeValidationCallback(StringArrayTypeValidationCallback)), new ConfigTypeEntry(RoleDefinitions, new ConfigTypeEntry.TypeValidationCallback(HashtableTypeValidationCallback)), new ConfigTypeEntry(RunAsVirtualAccount, new ConfigTypeEntry.TypeValidationCallback(BooleanTypeValidationCallback)), new ConfigTypeEntry(RunAsVirtualAccountGroups, new ConfigTypeEntry.TypeValidationCallback(StringArrayTypeValidationCallback)), @@ -1391,6 +1393,7 @@ internal static class DISCUtils private static readonly HashSet s_allowedRoleCapabilityKeys = new HashSet(StringComparer.OrdinalIgnoreCase) { "RoleCapabilities", + "RoleCapabilityFiles", "ModulesToImport", "VisibleAliases", "VisibleCmdlets", @@ -1808,8 +1811,11 @@ private void MergeRoleRulesIntoConfigHash(Func roleVerifier) } // Takes the "RoleCapabilities" node in the config hash, and merges its values into the base configuration. + private const string PSRCExtension = ".psrc"; private void MergeRoleCapabilitiesIntoConfigHash() { + List psrcFiles = new List(); + if (_configHash.ContainsKey(ConfigFileConstants.RoleCapabilities)) { string[] roleCapabilities = TryGetStringArray(_configHash[ConfigFileConstants.RoleCapabilities]); @@ -1821,18 +1827,51 @@ private void MergeRoleCapabilitiesIntoConfigHash() string roleCapabilityPath = GetRoleCapabilityPath(roleCapability); if (String.IsNullOrEmpty(roleCapabilityPath)) { - string message = StringUtil.Format(RemotingErrorIdStrings.CouldNotFindRoleCapability, roleCapability, roleCapability + ".psrc"); + string message = StringUtil.Format(RemotingErrorIdStrings.CouldNotFindRoleCapability, roleCapability, roleCapability + PSRCExtension); PSInvalidOperationException ioe = new PSInvalidOperationException(message); ioe.SetErrorId("CouldNotFindRoleCapability"); throw ioe; } - DISCPowerShellConfiguration roleCapabilityConfiguration = new DISCPowerShellConfiguration(roleCapabilityPath, null); - IDictionary roleCapabilityConfigurationItems = roleCapabilityConfiguration.ConfigHash; - MergeConfigHashIntoConfigHash(roleCapabilityConfigurationItems); + psrcFiles.Add(roleCapabilityPath); } } } + + if (ConfigHash.ContainsKey(ConfigFileConstants.RoleCapabilityFiles)) + { + string[] roleCapabilityFiles = TryGetStringArray(ConfigHash[ConfigFileConstants.RoleCapabilityFiles]); + if (roleCapabilityFiles != null) + { + foreach (var roleCapabilityFilePath in roleCapabilityFiles) + { + if (!Path.GetExtension(roleCapabilityFilePath).Equals(psrcExtenstion, StringComparison.OrdinalIgnoreCase)) + { + string message = StringUtil.Format(RemotingErrorIdStrings.InvalidRoleCapabilityFileExtension, roleCapabilityFilePath); + PSInvalidOperationException ioe = new PSInvalidOperationException(message); + ioe.SetErrorId("InvalidRoleCapabilityFileExtension"); + throw ioe; + } + + if (!File.Exists(roleCapabilityFilePath)) + { + string message = StringUtil.Format(RemotingErrorIdStrings.CouldNotFindRoleCapabilityFile, roleCapabilityFilePath); + PSInvalidOperationException ioe = new PSInvalidOperationException(message); + ioe.SetErrorId("CouldNotFindRoleCapabilityFile"); + throw ioe; + } + + psrcFiles.Add(roleCapabilityFilePath); + } + } + } + + foreach (var roleCapabilityFile in psrcFiles) + { + DISCPowerShellConfiguration roleCapabilityConfiguration = new DISCPowerShellConfiguration(roleCapabilityFile, null); + IDictionary roleCapabilityConfigurationItems = roleCapabilityConfiguration.ConfigHash; + MergeConfigHashIntoConfigHash(roleCapabilityConfigurationItems); + } } // Merge a role / role capability hashtable into the master configuration hashtable diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index 69c3a356605..f5cbae86e71 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -936,7 +936,7 @@ Do you want to continue? {0} may need to restart the WinRM service if a configuration using this name has recently been unregistered, certain system data structures may still be cached. In that case, a restart of WinRM may be required. All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session configurations that are created with the Register-PSSessionConfiguration cmdlet, are disconnected. - + You are running in a remote session and have selected the Force option which means the WinRM service may restart.If the WinRM service restarts then this remote session will be terminated and you will need to create a new session to continue @@ -1359,9 +1359,6 @@ All WinRM sessions connected to Windows PowerShell session configurations, such The remote session command is currently stopped in the debugger. Use the Enter-PSSession cmdlet to connect interactively to the remote session and automatically enter into the console debugger. - - Session {0} with instance ID {1} on computer {2} has been disconnected because the script running on the session has stopped at a breakpoint. Use the Enter-PSSession cmdlet on this session to connect back to the session and begin interactive debugging. - The remote session to which you are connected does not support remote debugging. You must connect to a remote computer that is running Windows PowerShell {0} or greater. @@ -1636,4 +1633,10 @@ All WinRM sessions connected to Windows PowerShell session configurations, such The provided SSHConnection hashtable contains both a KeyFilePath and IdentityFilePath parameter. Only one can be specified. + + Could not find the provided role capability file {0}. + + + The provided role capability file {0} does not have the required .psrc extension. + \ No newline at end of file diff --git a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 new file mode 100644 index 00000000000..201e82f5731 --- /dev/null +++ b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 @@ -0,0 +1,84 @@ +## +## PowerShell Remoting Endpoint Role Capability Files Tests +## + +Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tests" -Tags "Feature" { + + BeforeAll { + + if (!$IsWindows) + { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + $PSDefaultParameterValues["it:skip"] = $true + } + else + { + [string] $RoleCapDirectory = (New-Item -Path "$TestDrive\RoleCapability" -ItemType Directory -Force).FullName + + [string] $GoodRoleCapFile = "$RoleCapDirectory\TestGoodRoleCap.psrc" + New-PSRoleCapabilityFile -Path $GoodRoleCapFile -VisibleCmdlets 'Get-Command','Get-Process','Clear-Host','Out-Default','Select-Object','Get-FormatData','Get-Help' + + [string] $BadRoleCapFile = "$RoleCapDirectory\TestBadRoleCap.psrc" + New-PSRoleCapabilityFile -Path $BadRoleCapFile -VisibleCmdlets * + [string] $BadRoleCapFile = $BadRoleCapFile.Replace('.psrc', 'psbad') + + [string] $PSSessionConfigFile = "$RoleCapDirectory\TestConfig.pssc" + } + } + + AfterAll { + + if (!$IsWindows) + { + $global:PSDefaultParameterValues = $originalDefaultParameterValues + } + } + + It "Verifies missing role capability file error" { + + New-PSSessionConfigurationFile -Path $PSSessionConfigFile -RoleDefinitions @{ + Administrators = @{ RoleCapabilityFiles = "$RoleCapDirectory\NoFile.psrc" } + } + + try + { + $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) + throw 'Should have thrown CouldNotFindRoleCapabilityFile exception' + } + catch [System.Management.Automation.MethodInvocationException] + { + ([System.Management.Automation.PSInvalidOperationException] $_.Exception.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' + } + } + + It "Verifies incorrect role capability file extenstion error" { + + New-PSSessionConfigurationFile -Path $PSSessionConfigFile -RoleDefinitions @{ + Administrators = @{ RoleCapabilityFiles = "$BadRoleCapFile" } + } + + try + { + $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) + throw 'Should have thrown InvalidRoleCapabilityFileExtension exception' + } + catch [System.Management.Automation.MethodInvocationException] + { + ([System.Management.Automation.PSInvalidOperationException] $_.Exception.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' + } + } + + It "Verifies good role capability file" { + + New-PSSessionConfigurationFile -Path $PSSessionConfigFile -RoleDefinitions @{ + Administrators = @{ RoleCapabilityFiles = "$GoodRoleCapFile" } + } + + $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) + [powershell] $ps = [powershell]::Create($iss) + $result = $ps.AddCommand('Get-Process').AddParameter('Name', 'PowerShell*').Invoke() + + $result.Count | Should Not Be 0 + $ps.Dispose() + } +} From 913cce7902410f83e6a944c834f618928d4cba5a Mon Sep 17 00:00:00 2001 From: PaulHigin Date: Fri, 27 Jan 2017 16:17:53 -0800 Subject: [PATCH 2/5] Fixed spelling error. Added back missing resource string --- .../engine/remoting/fanin/InitialSessionStateProvider.cs | 2 +- .../resources/RemotingErrorIdStrings.resx | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs index 59a6ac952b3..c11c23ffebc 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs @@ -1845,7 +1845,7 @@ private void MergeRoleCapabilitiesIntoConfigHash() { foreach (var roleCapabilityFilePath in roleCapabilityFiles) { - if (!Path.GetExtension(roleCapabilityFilePath).Equals(psrcExtenstion, StringComparison.OrdinalIgnoreCase)) + if (!Path.GetExtension(roleCapabilityFilePath).Equals(PSRCExtension, StringComparison.OrdinalIgnoreCase)) { string message = StringUtil.Format(RemotingErrorIdStrings.InvalidRoleCapabilityFileExtension, roleCapabilityFilePath); PSInvalidOperationException ioe = new PSInvalidOperationException(message); diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index f5cbae86e71..306e9dcadef 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -1359,6 +1359,9 @@ All WinRM sessions connected to Windows PowerShell session configurations, such The remote session command is currently stopped in the debugger. Use the Enter-PSSession cmdlet to connect interactively to the remote session and automatically enter into the console debugger. + + Session {0} with instance ID {1} on computer {2} has been disconnected because the script running on the session has stopped at a breakpoint. Use the Enter-PSSession cmdlet on this session to connect back to the session and begin interactive debugging. + The remote session to which you are connected does not support remote debugging. You must connect to a remote computer that is running Windows PowerShell {0} or greater. From ae9eada8bb7e86f347029e28650d8b8c9cd58f23 Mon Sep 17 00:00:00 2001 From: PaulHigin Date: Mon, 30 Jan 2017 09:32:14 -0800 Subject: [PATCH 3/5] Updated tests from CR comments --- .../Remoting/RoleCapabilityFiles.Tests.ps1 | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 index 201e82f5731..746b46333c0 100644 --- a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 +++ b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 @@ -43,11 +43,19 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes try { $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) - throw 'Should have thrown CouldNotFindRoleCapabilityFile exception' + throw 'No Exception!' } - catch [System.Management.Automation.MethodInvocationException] + catch { - ([System.Management.Automation.PSInvalidOperationException] $_.Exception.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' + [System.Management.Automation.MethodInvocationException] $expectedException = [System.Management.Automation.MethodInvocationException] $_.Exception + if ($expectedException -ne $null) + { + ([System.Management.Automation.PSInvalidOperationException] $expectedException.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' + } + else + { + throw 'Unexpected Exception' + } } } @@ -60,25 +68,51 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes try { $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) - throw 'Should have thrown InvalidRoleCapabilityFileExtension exception' + throw 'No Exception!' } - catch [System.Management.Automation.MethodInvocationException] + catch { - ([System.Management.Automation.PSInvalidOperationException] $_.Exception.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' + [System.Management.Automation.MethodInvocationException] $expectedException = [System.Management.Automation.MethodInvocationException] $_.Exception + if ($expectedException -ne $null) + { + ([System.Management.Automation.PSInvalidOperationException] $expectedException.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' + } + else + { + throw 'Unexpected Exception' + } } } - It "Verifies good role capability file" { + It "Verifies restriction on good role capability file" { New-PSSessionConfigurationFile -Path $PSSessionConfigFile -RoleDefinitions @{ Administrators = @{ RoleCapabilityFiles = "$GoodRoleCapFile" } } + # 'Get-Service' is not included in the session. $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) [powershell] $ps = [powershell]::Create($iss) - $result = $ps.AddCommand('Get-Process').AddParameter('Name', 'PowerShell*').Invoke() + $null = $ps.AddCommand('Get-Service') + + try + { + $ps.Invoke() + throw 'No Exception!' + } + catch + { + [System.Management.Automation.MethodInvocationException] $expectedException = [System.Management.Automation.MethodInvocationException] $_.Exception + if ($expectedException -ne $null) + { + ($expectedException.InnerException.GetType().FullName) | Should Be 'System.Management.Automation.CommandNotFoundException' + } + else + { + throw 'Unexpected Exception' + } + } - $result.Count | Should Not Be 0 $ps.Dispose() } } From 132b36a3f1715ac6154455a24bc5bbe7baa02674 Mon Sep 17 00:00:00 2001 From: PaulHigin Date: Wed, 1 Feb 2017 14:08:07 -0800 Subject: [PATCH 4/5] Simplified error tests per Code Review --- .../Remoting/RoleCapabilityFiles.Tests.ps1 | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 index 746b46333c0..e65dd92ddac 100644 --- a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 +++ b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 @@ -47,15 +47,7 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes } catch { - [System.Management.Automation.MethodInvocationException] $expectedException = [System.Management.Automation.MethodInvocationException] $_.Exception - if ($expectedException -ne $null) - { - ([System.Management.Automation.PSInvalidOperationException] $expectedException.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' - } - else - { - throw 'Unexpected Exception' - } + ([System.Management.Automation.PSInvalidOperationException] ($_.Exception).InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' } } @@ -72,15 +64,7 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes } catch { - [System.Management.Automation.MethodInvocationException] $expectedException = [System.Management.Automation.MethodInvocationException] $_.Exception - if ($expectedException -ne $null) - { - ([System.Management.Automation.PSInvalidOperationException] $expectedException.InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' - } - else - { - throw 'Unexpected Exception' - } + ([System.Management.Automation.PSInvalidOperationException] ($_.Exception).InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' } } @@ -102,15 +86,7 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes } catch { - [System.Management.Automation.MethodInvocationException] $expectedException = [System.Management.Automation.MethodInvocationException] $_.Exception - if ($expectedException -ne $null) - { - ($expectedException.InnerException.GetType().FullName) | Should Be 'System.Management.Automation.CommandNotFoundException' - } - else - { - throw 'Unexpected Exception' - } + ($_.Exception).InnerException.GetType().FullName | Should Be 'System.Management.Automation.CommandNotFoundException' } $ps.Dispose() From 37ab39c29e29448ac377630a4c257b13fba3048f Mon Sep 17 00:00:00 2001 From: PaulHigin Date: Thu, 2 Feb 2017 08:32:44 -0800 Subject: [PATCH 5/5] Test change from Code Review --- .../Remoting/RoleCapabilityFiles.Tests.ps1 | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 index e65dd92ddac..8ced5d266c4 100644 --- a/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 +++ b/test/powershell/engine/Remoting/RoleCapabilityFiles.Tests.ps1 @@ -40,6 +40,7 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes Administrators = @{ RoleCapabilityFiles = "$RoleCapDirectory\NoFile.psrc" } } + $fullyQualifiedErrorId = "" try { $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) @@ -47,7 +48,12 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes } catch { - ([System.Management.Automation.PSInvalidOperationException] ($_.Exception).InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' + $psioe = [System.Management.Automation.PSInvalidOperationException] ($_.Exception).InnerException + if ($psioe -ne $null) + { + $fullyQualifiedErrorId = $psioe.ErrorRecord.FullyQualifiedErrorId + } + $fullyQualifiedErrorId | Should Be 'CouldNotFindRoleCapabilityFile' } } @@ -57,6 +63,7 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes Administrators = @{ RoleCapabilityFiles = "$BadRoleCapFile" } } + $fullyQualifiedErrorId = "" try { $iss = [initialsessionstate]::CreateFromSessionConfigurationFile($PSSessionConfigFile, { $true }) @@ -64,7 +71,12 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes } catch { - ([System.Management.Automation.PSInvalidOperationException] ($_.Exception).InnerException).ErrorRecord.FullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' + $psioe = [System.Management.Automation.PSInvalidOperationException] ($_.Exception).InnerException + if ($psioe -ne $null) + { + $fullyQualifiedErrorId = $psioe.ErrorRecord.FullyQualifiedErrorId + } + $fullyQualifiedErrorId | Should Be 'InvalidRoleCapabilityFileExtension' } } @@ -79,6 +91,7 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes [powershell] $ps = [powershell]::Create($iss) $null = $ps.AddCommand('Get-Service') + $exceptionTypeName = "" try { $ps.Invoke() @@ -86,7 +99,11 @@ Describe "Remote session configuration RoleDefintion RoleCapabilityFiles key tes } catch { - ($_.Exception).InnerException.GetType().FullName | Should Be 'System.Management.Automation.CommandNotFoundException' + if ($_.Exception.InnerException -ne $null) + { + $exceptionTypeName = $_.Exception.InnerException.GetType().FullName + } + $exceptionTypeName | Should Be 'System.Management.Automation.CommandNotFoundException' } $ps.Dispose()