Powershell Invoke-Command远程手动工作,但不能从Jenkins运行 [英] Powershell Invoke-Command remote works manually, but not from Jenkins

查看:121
本文介绍了Powershell Invoke-Command远程手动工作,但不能从Jenkins运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常奇怪的情况,当从Windows Server 2012 R2手动运行但从同一服务器上运行的Jenkins从属进程手动运行时,该命令起作用.

I have a really strange situation where the same command works when run manually from a Windows Server 2012 R2, but not from the Jenkins slave process running on the same server.

首先,手动运行的输出是admin PowerShell窗口:

First, the output from the manual run, an admin PowerShell window:

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管道代码的相关代码段:

Great. Now, the relevant snippet of Jenkins pipeline code:

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}
                """

            }
        }
    }
}

从詹金斯运行时的输出:

And the output when running from 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服务器)不是域的一部分,但是具有相同的管理员密码,这似乎使身份验证工作正常.

The Windows servers (Jenkins slave and web server) are not part of a domain, but have the same Administrator password, which seems to make the authentication work well.

对于它的价值,这是Jenkins奴隶的winrm配置:

For what it's worth, here's the winrm configuration for the Jenkins slave:

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

我试了一下就可以了.首先,在詹金斯奴隶上,我必须运行:

I got it to work after a fashion. Firstly, on the Jenkins slave, I had to run:

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
"""

其中creds.xml是先前使用Get-Credentials | Export-CliXml creds.xml生成的文件.

where creds.xml was a file previously generated with Get-Credentials | Export-CliXml creds.xml.

这仍然不能解释为什么手动PowerShell和Jenkins从站之间的行为不同.这是一个令人讨厌的解决方法,但至少我可以继续.

That still doesn't explain why the behaviour is different between manual PowerShell and Jenkins slave. It's a bit of an annoying workaround, but at least I can proceed.

推荐答案

您可能遇到了Jenkins的远程执行脚本限制(此处是安全原因).您需要将Jenkins服务器配置为能够正常"运行脚本,但始终必须添加凭据.

You are probably hitting the remote execution script limitation from Jenkins (security is the cause here). You need to configure the Jenkins server to be able to run the script "normally" but you will always have to add the credentials.

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

The script you are running from powershell command line uses the default credentials for your win-cm8utd1qfnc\administrator so the following will work as you wrote:

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插件时,您遇到的是按设计的安全性限制.您不想使用您的管理帐户运行野生"脚本.

However, when running Powershell from Jenkins, a plugin by its nature, you are hitting the security-by-design limitation. You don't want to run "wild" scripts with your Administration account.

我在此主题上找到的最合理的指南是此处(以下是该页面的摘录:

The most reasonable guide I have found on this topic was here (the following is excerpt from the page:

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

he above job creates a text file on the Jenkins server itself. To setup remote Powershell scripts we first need to configure Jenkins server for remote Powershell script execution. To enable remote Windows machine in to the WS-Man trusted list on Jenkins servers. Execute the below command on Powershell window on Jenkins server. The command will add all the remote machine to the trusted list.

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

除了这些命令,我​​们还需要启用远程脚本 执行也.启用远程执行Powershell脚本 在Jenkins服务器的Powershell窗口中执行以下命令.

Along with the commands, we would also need to enable remote script execution also. To enable execution of Powershell scripts remotely execute the following command in Powershell window on Jenkins server.

Set-ExecutionPolicy RemoteSigned –Force

我们将必须安装一个名为EnvInject Plugin的新插件,用​​于 传输变量密码.

We will have to install a new plugin named EnvInject Plugin for transferring variables e.g. passwords.

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时间服务:

Creating a job to restart Windows time service:

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,

提供所提及选项的描述:

provide description for the options mentioned:

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

The following script is based on the above link, but I did not like the plain text used so I have decided to rewrite it to use Powershell's SecureString

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

First to store your admin password:

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 }

这篇关于Powershell Invoke-Command远程手动工作,但不能从Jenkins运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆