远程PowerShell的登录会话问题(调用命令)

时间:2019-07-04 15:34:51

标签: powershell powershell-4.0 powershell-remoting

我正在尝试远程配置SAML / ADFSRelyingPartyTrust。 我知道脚本本身可以工作,因为登录到服务器时我可以自己调用ScriptBlock部分,将参数提供给它,然后它就可以工作。

虽然我希望能够远程执行此操作,但出现错误

[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

由于实际上不确定要在哪里进行调整,因此我实际上没有尝试过其他任何操作。这是我第一次尝试执行远程命令,但是我认为这是正确的方法。

我已经看到有人提到需要凭据,但理想情况下,我只是希望它以登录其计算机的用户身份运行。

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

我可能对脚本的结构完全错了,对整个事情来说还很陌生,所以欢迎提出有关重组的建议,以使其正常工作!

1 个答案:

答案 0 :(得分:0)

这不是PowerShell代码问题。在Windows上,这是一种环境/身份验证/权限。

PSRemoting必须在远程主机上正确设置,并且您必须是远程主机上的本地管理员才能充分利用PowerShell远程处理。

您必须在显式或隐式PSRemoting会话中正确使用代码。该错误消息是非常具体的,请在消息提示时仔细阅读PSRemoting。

至此……

  

指定的登录会话不存在。

... PowerShell并非唯一,在Windows上的其他用例中也可能发生相同的错误。

至此...

  

理想情况下,我只是希望它以登录其用户的用户身份运行   电脑。

...您不能使用本机PowerShell在当前登录用户的上下文中运行远程命令。 PowerShell将始终使用运行脚本的用户上下文。这是Windows适当的安全边界。因此,如果启动此脚本,它将始终处于您的用户上下文中。

或者登录的用户必须直接运行此脚本并具有适当的凭据才能执行此操作,或者再次使用用户凭据(您不知道-因此,他们设置了计划任务来执行此操作) d必须进行设置)。

如果您试图在另一个用户的上下文中运行代码。您需要在脚本中使用MS SysInternals PSExec之类的东西。

对于正在执行的操作,被盗用户仍然需要在其主机上安装/代理的ADDS cmdlet和ADFS cmdlet才能运行此操作,或者它们需要位于DC / ADFS服务器上(物理或远程(RDP) / PSRemoting隐式/显式))。

最后,变量的使用必须在范围内,并且您不能在远程会话中使用局部变量,除非它们在调用代码的范围内不可见。请参阅有关该主题的帮助文件。

您也有一些语法上的错误(如何使用换行符是其中之一),PowerShell通常不需要所有多余的分号。在少数情况下会出现这种情况,但是您所做的并不是其中之一。

因此,忽略...

  

指定的登录会话不存在。

...暂时出现错误。调整您发布的代码,我建议这样做。其他人当然也会对此话题有所了解。顺便说一句...未经测试,我现在还不能测试环境。

### 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://docs.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://docs.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://docs.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://docs.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://docs.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
#>

如果您不在已建立的隐式/显式PSRemote会话中,则所有操作项代码都必须位于需要在远程主机上运行的脚本块中。