Reputation: 37
I'm trying to configure SAML/ADFSRelyingPartyTrust remotely. I know the script itself works, because I can call the ScriptBlock part myself while logged onto the server, feed it the parameter, and it works.
I want to be able to do this remotely though, and I get the error
[blah20.blah.blah.com] Connecting to remote server blah20.blah.blah.com failed with the following error message : A specified logon session does not exist. It may already have been terminated. For more information, see the about_Remote_Troubleshooting Help topic. + CategoryInfo : OpenError: (blah20.blah.blah.com:String) [], PSRemotingTransportException + FullyQualifiedErrorId : 1312,PSSessionStateBroken
I haven't actually tried anything else on account of not really being sure where to tweak. It's my first time trying to do remote commands, but I think this is the right way to do so.
I've seen some mention of needing credentials, but ideally I just wanted it to run as the user that's logged in on their computer.
CLS
$Title = "SAML Server Choice"
$Info = "Please pick the server you wish to configure SAML on"
$options = [System.Management.Automation.Host.ChoiceDescription[]] @("&LIVE", "&TEST")
[int]$defaultchoice = 1
$opt = $host.UI.PromptForChoice($Title , $Info , $Options,$defaultchoice)
switch ($opt) {
0 { Write-Host "LIVE" -ForegroundColor Green}
1 { Write-Host "TEST" -ForegroundColor Green}
}
switch ($opt) {
0 {"SAML Server is blah20.blah.com"; $SAMLServer = "blah20.blah.blah.com"}
1 {"SAML Server is blah50.blah.com"; $SAMLServer = "blah50.blah.blah.com"}
}
$EnvironmentName = Read-Host "Please enter the customer name: "
$ScriptBlockContent = {
$EnvironmentURL = 'https://'+$EnvironmentName+'.blah.com';
$EndPoint = 'https://'+$EnvironmentName+'.blah.com/app_pages/admin/saml.aspx';
$folderPath = "C:\SAMLAutoSetup\";
$claimsFilePath = $folderPath + "claims.txt";
$rulesFilePath = $folderPath + "rules.txt";
$claims = '@RuleTemplate = "LdapClaims"
@RuleName = "LDAP"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.xmlsoap.org/claims/Group",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), query =
";userPrincipalName,displayName,tokenGroups,mail;{0}", param = c.Value); ';
$claims | Out-File $claimsFilePath -Force;
$rules = '@RuleTemplate = "AllowAllAuthzRule"
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");';
$rules | Out-File $rulesFilePath -Force;
Add-PSSnapin Microsoft.Adfs.PowerShell;
if (Get-ADFSRelyingPartyTrust -Name $EnvironmentName) {
Write-Host `n"$EnvironmentName Relying Party Trust already exists";
} else {
Write-Host `n"$EnvironmentName Relying Party Trust doesn't exist! Need to Create";
$samlEndPoint = New-ADFSSamlEndpoint -Protocol SAMLAssertionConsumer -Uri $EndPoint -Binding POST -IsDefault $false -Index 0;
Add-ADFSRelyingPartyTrust -Name $EnvironmentName -Identifier $EnvironmentURL -SamlEndpoint $samlEndPoint -IssuanceTransformRulesFile $claimsFilePath -IssuanceAuthorizationRulesFile $rulesFilePath;
Write-Host `n"$EnvironmentName Created successfully!";
}
}
Invoke-Command -ComputerName $SAMLServer -ScriptBlock $ScriptBlockContent -ArgumentList $EnvironmentName
I may have structured the script wholly wrong, pretty new to the whole thing, so open to suggestions on restructuring to make it work!
Upvotes: 1
Views: 2488
Reputation: 16116
This is not a PowerShell code issue. It's an environmental / Auth / permissions one on Windows proper.
PSRemoting must be properly setup on the remote host and you must be a local admin on the remote host to fully leverage PowerShell remoting.
You must properly use your code in an explicit or implicit PSRemoting session. That error message is very specific, please read up on PSRemoting as the message is stating.
As for this …
A specified logon session does not exist.
... it is not unique to PowerShell, this same error can happen for other use cases on Windows.
As for this...
ideally I just wanted it to run as the user that's logged in on their computer.
... you cannot run remote commands in the context of the current logged on user, using native PowerShell. PowerShell will always use the user context that ran the script. That is a Windows proper security boundary. So, if you start this script, it will always be in your user context.
Either the logged on user must run this script directly and have the proper credentials to do so, or you set a scheduled task to do this, again, using the user creds (which you won't know - so, they'd have to set this up).
If you are trying to run code in the context of another user. You need to use something like MS SysInternals PSExec in your script.
For what you are doing the looged on user would still need the ADDS cmdlets and ADFS cmdlets installed / proxied on their host to run this, or they'd need to be on the DC/ADFS server (physically or remotely (RDP/PSRemoting implicit / explicit)) to do so.
Lastly, variable use must be in scope, and you cannot use local variables in a remote session without them being visible in the scope of the calling code. See the help files on the topic.
You also, have a few things that are syntactically (how you are using the line break character is one of them) wrong and all the extra semi-colons are not needed for PowerShell in general. Their are a few cases where they are, but what you are doing is not really one of them.
So, ignoring the ...
A specified logon session does not exist.
... error for a moment. Tweaking your posted code, I'd suggest this. Others of course will have their take on the topic. BTW... untested and I an not in a environment that I can test at this time.
### configure SAML/ADFSRelyingPartyTrust
Clear-Host
<#
Import needed PowerShell modules and must be on the ADFS server and have the
ADDS cmdlets via the RSAT Tools installed and enabled locally or proxied via
PowerSehll Remoting
#>
Import-Module -Name ServerManager, ActiveDirectory, ADFS -Force
Add-PSSnapin Microsoft.Adfs.PowerShell
<#
Force environment specifications
about_Requires | Microsoft Docs
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires
#>
#Requires -Version 4
#Requires -PSSnapin Microsoft.Adfs.PowerShell
#Requires -Modules ServerManager, ActiveDirectory, ADFS
#Requires -RunAsAdministrator
<#
Ensure that any local variables are properly scoped for PSRemote sessions
about_scopes | Microsoft Docs
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes
The Using scope modifier
Using is a special scope modifier that identifies a local variable in a remote
command. Without a modifier, PowerShell expects variables in remote commands to
be defined in the remote
session.
The Using scope modifier is introduced in PowerShell 3.0.
For more information, see about_Remote_Variables.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_variables?view=powershell-6
Using local variables
You can also use local variables in remote commands, but you must indicate that
the variable is defined in the local session.
Beginning in Windows PowerShell 3.0, you can use the Using scope modifier to
identify a local variable in a remote command.
The syntax of Using is as follows:
$Using:<VariableName>
# Simple strings only need single quotes, variable / string expansion requires double quotes
about_Quoting_Rules | Microsoft Docs
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules
The Difference Between Single and Double Quotes in PowerShell
https://blog.techsnips.io/the-difference-between-single-and-double-quotes-in-powershell
https://www.sconstantinou.com/powershell-quotes/
#>
$Title = 'SAML Server Choice'
$Info = 'Please pick the server you wish to configure SAML on'
$options = [System.Management.Automation.Host.ChoiceDescription[]] @('&LIVE', '&TEST')
[int]$defaultchoice = 1
$opt = $host.UI.PromptForChoice($Title , $Info , $Options,$defaultchoice)
<#
Using write-Host for colorizing screen text - otherwise Write-Host is not needed.
Output to the screen is the PowerShell default, unless you:
- assign to a variable (and not using varialbe squeezing)
- not use Out-Host
- or use Out-NUll
#>
switch ($opt) {
0 { Write-Host 'LIVE' -ForegroundColor Green}
1 { Write-Host 'TEST' -ForegroundColor Green}
}
<#
Using variable squeezing to assign value to the variable and output to screen
Server names are hardcoded here, but the user domain is dynamically discovered
via PowerShell $ENv variable.
One could just as easily discover the DC/ADFS/SAML server FQDN from ADDS to
avoid this hard coding effort.
#>
switch ($opt) {
0 {"SAML Server is $(($SAMLServer = "blah20.$env:USERDNSDOMAIN"))"}
1 {"SAML Server is $(($SAMLServer = "blah50.$env:USERDNSDOMAIN"))"}
}
$EnvironmentName = Read-Host 'Please enter the customer name: '
$ScriptBlockContent = {
$EnvironmentURL = "https://$EnvironmentName.$env:USERDNSDOMAIN"
$EndPoint = "$EnvironmentURL/app_pages/admin/saml.aspx"
$folderPath = 'C:\SAMLAutoSetup\'
$claimsFilePath = "$folderPath claims.txt"
$claims = '@RuleTemplate = "LdapClaims"
@RuleName = "LDAP"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.xmlsoap.org/claims/Group",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), query =
";userPrincipalName,displayName,tokenGroups,mail;{0}", param = c.Value); ';
$claims |
Out-File $claimsFilePath -Force
$rules = '@RuleTemplate = "AllowAllAuthzRule"
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");';
$rulesFilePath = "$folderPath rules.txt"
$rules |
Out-File $rulesFilePath -Force
<#
Special formatting characters, like the new line `n, needs to be properly
quoted to be used. Avoid unnecessary string concatenation where possible.
https://leanpub.com/thebigbookofpowershellgotchas/read
https://leanpub.com/thebigbookofpowershellgotchas/read#leanpub-auto-dontconcatenatestrings
https://devops-collective-inc.gitbook.io/the-big-book-of-powershell-gotchas/dont-concatenate-strings
https://github.com/devops-collective-inc/big-book-of-powershell-gotchas
See also
PowerShell: Using the -F format Operator
https://social.technet.microsoft.com/wiki/contents/articles/7855.powershell-using-the-f-format-operator.aspx
The Unofficial PowerShell Best Practices and Style Guide
https://github.com/PoshCode/PowerShellPracticeAndStyle
#>
if (Get-ADFSRelyingPartyTrust -Name $EnvironmentName)
{ "`n$EnvironmentName Relying Party Trust already exists" }
else
{
"`n$EnvironmentName Relying Party Trust doesn't exist! Need to Create"
<#
Leveraging PowerShell Splatting for readability
about_Splatting | Microsoft Docs
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting
#>
$newADFSSamlEndpointSplat = @{
Protocol = 'SAMLAssertionConsumer'
IsDefault = $false
Index = 0
Uri = $EndPoint
Binding = 'POST'
}
$samlEndPoint = New-ADFSSamlEndpoint @newADFSSamlEndpointSplat
$addADFSRelyingPartyTrustSplat = @{
IssuanceAuthorizationRulesFile = $rulesFilePath
SamlEndpoint = $samlEndPoint
Name = $EnvironmentName
Identifier = $EnvironmentURL
IssuanceTransformRulesFile = $claimsFilePath
}
Add-ADFSRelyingPartyTrust @addADFSRelyingPartyTrustSplat
"`n$EnvironmentName Created successfully!"
}
}
$invokeCommandSplat = @{
Credential = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME")
ComputerName = $SAMLServer
ArgumentList = $EnvironmentName
ScriptBlock = $ScriptBlockContent
}
Invoke-Command @invokeCommandSplat
<#
If using Implicit PSRemoting to the DC or a server running the RSAT and ADFS tools,
from a remote workstation, then you'd not need to use Invoke-Command at all.
You'd just run the script as if you were on the DC/ADFS server directly.
An Introduction to PowerShell Remoting Part Four: Sessions and Implicit Remoting
https://devblogs.microsoft.com/scripting/an-introduction-to-powershell-remoting-part-four-sessions-and-implicit-remoting
https://devblogs.microsoft.com/scripting/remoting-the-implicit-way
PowerShell Implicit Remoting: Never Install a Module Again
https://www.itprotoday.com/powershell/powershell-implicit-remoting-never-install-module-again
#>
If you are not in an established Implicit / explicit PSRemote session, all that action item code must be in the scriptblock that needs to run on the remote host..
Upvotes: 1