Powershell Invoke-Command 远程手动工作,但不能通过 Jenkins

2024-05-13

我遇到了一个非常奇怪的情况,即从 Windows Server 2012 R2 手动运行相同的命令时可以工作,但从同一服务器上运行的 Jenkins 从属进程无法工作。

首先,手动运行的输出,管理 PowerShell 窗口:

PS C:\Users\Administrator> whoami
win-cm8utd1qfnc\administrator
PS C:\Users\Administrator> Invoke-Command -computername web.sandbox.MUNGED.com -scriptblock {iisreset /restart}
Attempting stop...
Internet services successfully stopped
Attempting start...
Internet services successfully restarted

伟大的。现在,Jenkins 管道代码的相关片段:

pipeline {
    stages {
        stage('Deploy web') {
            agent { label 'windows-server-2012' }
            environment {
                SERVER = 'web.sandbox.MUNGED.com'
            }
            steps {
                powershell """
                    whoami
                    Invoke-Command -computername ${SERVER} -scriptblock {iisreset /restart}
                """

            }
        }
    }
}

从 Jenkins 运行时的输出:

07:37:29 win-cm8utd1qfnc\administrator
07:37:29 [web.sandbox.MUNGED.com] Connecting to remote server web.sandbox.MUNGED.com failed with the following error message : Access is denied. For more information, see the 
07:37:29 about_Remote_Troubleshooting Help topic.
07:37:29     + CategoryInfo          : OpenError: (web.sandbox.MUNGED.com:String) [], PSRemotingTransportException
07:37:29     + FullyQualifiedErrorId : AccessDenied,PSSessionStateBroken

Windows 服务器(Jenkins 从属服务器和 Web 服务器)不属于域,但具有相同的管理员密码,这似乎使身份验证工作正常。

就其价值而言,这是 Jenkins 从属设备的 winrm 配置:

PS C:\Users\Administrator> winrm get winrm/config
Config
    MaxEnvelopeSizekb = 500
    MaxTimeoutms = 1800000
    MaxBatchItems = 32000
    MaxProviderRequests = 4294967295
    Client
        NetworkDelayms = 5000
        URLPrefix = wsman
        AllowUnencrypted = false
        Auth
            Basic = true
            Digest = true
            Kerberos = true
            Negotiate = true
            Certificate = true
            CredSSP = false
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        TrustedHosts = *
    Service
        RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
        MaxConcurrentOperations = 4294967295
        MaxConcurrentOperationsPerUser = 1500
        EnumerationTimeoutms = 240000
        MaxConnections = 300
        MaxPacketRetrievalTimeSeconds = 120
        AllowUnencrypted = true
        Auth
            Basic = true
            Kerberos = true
            Negotiate = true
            Certificate = false
            CredSSP = false
            CbtHardeningLevel = Relaxed
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        IPv4Filter = *
        IPv6Filter = *
        EnableCompatibilityHttpListener = false
        EnableCompatibilityHttpsListener = false
        CertificateThumbprint
        AllowRemoteAccess = true
    Winrs
        AllowRemoteShellAccess = true
        IdleTimeout = 7200000
        MaxConcurrentUsers = 10
        MaxShellRunTime = 2147483647
        MaxProcessesPerShell = 4096
        MaxMemoryPerShellMB = 8192
        MaxShellsPerUser = 30

并从网络服务器:

PS C:\Users\Administrator> winrm get winrm/config
Config
    MaxEnvelopeSizekb = 500
    MaxTimeoutms = 1800000
    MaxBatchItems = 32000
    MaxProviderRequests = 4294967295
    Client
        NetworkDelayms = 5000
        URLPrefix = wsman
        AllowUnencrypted = false
        Auth
            Basic = true
            Digest = true
            Kerberos = true
            Negotiate = true
            Certificate = true
            CredSSP = false
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        TrustedHosts = *
    Service
        RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
        MaxConcurrentOperations = 4294967295
        MaxConcurrentOperationsPerUser = 1500
        EnumerationTimeoutms = 240000
        MaxConnections = 300
        MaxPacketRetrievalTimeSeconds = 120
        AllowUnencrypted = true
        Auth
            Basic = true
            Kerberos = true
            Negotiate = true
            Certificate = false
            CredSSP = false
            CbtHardeningLevel = Relaxed
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        IPv4Filter = *
        IPv6Filter = *
        EnableCompatibilityHttpListener = false
        EnableCompatibilityHttpsListener = false
        CertificateThumbprint
        AllowRemoteAccess = true
    Winrs
        AllowRemoteShellAccess = true
        IdleTimeout = 7200000
        MaxConcurrentUsers = 10
        MaxShellRunTime = 2147483647
        MaxProcessesPerShell = 25
        MaxMemoryPerShellMB = 1024
        MaxShellsPerUser = 30

EDIT:我设法让它发挥作用。首先,在詹金斯奴隶上,我必须运行:

winrm set winrm/config/client '@{AllowUnencrypted="true"}'

然后我将管道更改为:

powershell """
    \$creds = Import-CliXml \$home\\creds.xml
     Invoke-Command -computername ${SERVER} -scriptblock {iisreset /restart} -Authentication Basic -Credential \$creds
"""

where creds.xml是之前生成的文件Get-Credentials | Export-CliXml creds.xml.

这仍然无法解释为什么手动 PowerShell 和 Jenkins Slave 之间的行为不同。这是一个有点烦人的解决方法,但至少我可以继续。


您可能遇到了 Jenkins 的远程执行脚本限制(安全是这里的原因)。您需要配置 Jenkins 服务器以便能够“正常”运行脚本,但您始终必须添加凭据。

您从 powershell 命令行运行的脚本使用您的默认凭据win-cm8utd1qfnc\administrator所以以下内容将按照您所写的那样工作:

PS C:\Users\Administrator> whoami
win-cm8utd1qfnc\administrator
PS C:\Users\Administrator> Invoke-Command -computername web.sandbox.MUNGED.com -scriptblock {iisreset /restart}
Attempting stop...
Internet services successfully stopped
Attempting start...
Internet services successfully restarted

然而,当从 Jenkins(本质上是一个插件)运行 Powershell 时,您就会遇到设计安全性的限制。您不想使用管理帐户运行“野生”脚本。

我发现的关于这个主题的最合理的指南是here http://www.tothenew.com/blog/running-powershell-scripts-using-jenkins/(以下内容摘自该页面:

远程执行Powershell脚本/命令

上述工作在 Jenkins 服务器本身上创建了一个文本文件。到 设置远程Powershell脚本我们首先需要配置Jenkins 用于远程 Powershell 脚本执行的服务器。启用远程 Windows 计算机进入 Jenkins 服务器上的 WS-Man 可信列表。 在 Jenkins 服务器上的 Powershell 窗口中执行以下命令。这 命令会将所有远程计算机添加到受信任列表中。

Set-Item WSMan:\localhost\Client\TrustedHosts *

除了命令之外,我们还需要启用远程脚本 执行也。启用远程执行 Powershell 脚本 在 Jenkins 服务器上的 Powershell 窗口中执行以下命令。

Set-ExecutionPolicy RemoteSigned –Force

我们必须安装一个名为 EnvInject Plugin 的新插件 传输变量,例如密码。

Login to Jenkins and navigate to Manage Jenkins > Manage Plugins
Click on the Available tab and Enter EnvInject in the filter box
Select the plugin showing by name PowerShell Plugin
Select Download now and install after restart

创建一个作业来重新启动 Windows 时间服务:

On Jenkins interface, click New Item
Enter Remote Powershell scripts for the job name. Select Freestyle project
Tick This build is parameterized. Create following parameters
    Type: String Parameter
    Name: ServerIp/Hostname
    Description: Remote machine’s IP address.
    Type: String Parameter
    Name: UserName
    Type: Password Parameter
    Name: Password
Now, Click Add Parameter list and select the Choice Parameter. Enter the options on new lines inside the Choices text box. Also,

提供上述选项的描述:

以下脚本基于上面的链接,但我不喜欢使用纯文本,因此我决定重写它以使用 Powershell 的SecureString

首先存储您的管理员密码:

read-host -AsSecureString | ConvertFrom-SecureString | Out-File C:\<your_path>\securestring.txt

然后有脚本:

# Configure build failure on errors on the remote machine similar to set -x on bash script 
$ErrorActionPreference = 'Stop'  

# Create a PSCredential Object using the "Username" and "Password" variables created on job 
$password = Get-Content 'C:\<your_path>\securestring.txt' | ConvertTo-SecureString
$creddentials = New-Object System.Management.Automation.PSCredential -ArgumentList $env:UserName, $password

# It depends on the type of job you are executing on the remote machine as to if you want to use "-ErrorAction Stop" on your Invoke-Command. 
Invoke-Command -ComputerName $env:Computer -Credential $credentials -ScriptBlock { Restart-Service -Name W32Time }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Powershell Invoke-Command 远程手动工作,但不能通过 Jenkins 的相关文章

随机推荐