環境:
CentOS 6.75(Ansible 2.0)
Windows Server 2012 (PowerShell 4.0)
1、確保PowerShell版本為3.0以上
ansible要控制windows,必須要求windows主機的PowerShell版本為3.0以上,如果版本不滿足要求需要升級PowerShell。
查看PowerShell版本可以使用以下命令
$PSVersionTable.PSVersion
如果版本不滿足要求,可以使用下面腳本進行升級(將腳本內容保存到一個powershell腳本中,)
首先啟動powershell必須是用超管權限啟動,然后 set-ExecutionPolicy RemoteSigned ,以后才能正確執行下面的腳本(腳本隨便放哪都行,找到放置的對應路徑就行)
[html] view plain copy print?
# Powershell script to upgrade a PowerShell 2.0 system to PowerShell 3.0
# based on http://occasionalutility.blogspot.com/2013/11/everyday-powershell-part-7-powershell.html
#
# some Ansible modules that may use Powershell 3 features, so systems may need
# to be upgraded. This may be used by a sample playbook. Refer to the windows
# documentation on docs.ansible.com for details.
#
# - hosts: windows
# tasks:
# - script: upgrade_to_ps3.ps1
# Get version of OS
# 6.0 is 2008
# 6.1 is 2008 R2
# 6.2 is 2012
# 6.3 is 2012 R2
if ($PSVersionTable.psversion.Major -ge 3)
{
write-host "Powershell 3 Installed already; You don't need this"
Exit
}
$powershellpath = "C:\powershell"
function download-file
{
param ([string]$path, [string]$local)
$client = new-object system.net.WebClient
$client.Headers.Add("user-agent", "PowerShell")
$client.downloadfile($path, $local)
}
if (!(test-path $powershellpath))
{
New-Item -ItemType directory -Path $powershellpath
}
# .NET Framework 4.0 is necessary.
#if (($PSVersionTable.CLRVersion.Major) -lt 2)
#{
# $DownloadUrl = "http://download.microsoft.com/download/B/A/4/BA4A7E71-2906-4B2D-A0E1-80CF16844F5F/dotNetFx45_Full_x86_x64.exe"
# $FileName = $DownLoadUrl.Split('/')[-1]
# download-file $downloadurl "$powershellpath\$filename"
# ."$powershellpath\$filename" /quiet /norestart
#}
#You may need to reboot after the .NET install if so just run the script again.
# If the Operating System is above 6.2, then you already have PowerShell Version > 3
if ([Environment]::OSVersion.Version.Major -gt 6)
{
write-host "OS is new; upgrade not needed."
Exit
}
$osminor = [environment]::OSVersion.Version.Minor
$architecture = $ENV:PROCESSOR_ARCHITECTURE
if ($architecture -eq "AMD64")
{
$architecture = "x64"
}
else
{
$architecture = "x86"
}
if ($osminor -eq 1)
{
$DownloadUrl = "http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-" + $architecture + ".msu"
}
elseif ($osminor -eq 0)
{
$DownloadUrl = "http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-" + $architecture + ".msu"
}
else
{
# Nothing to do; In theory this point will never be reached.
Exit
}
$FileName = $DownLoadUrl.Split('/')[-1]
download-file $downloadurl "$powershellpath\$filename"
write-host "$powershellpath\$filename"
Start-Process -FilePath "$powershellpath\$filename" -ArgumentList /quiet執行完了之后,需要重啟電腦(自動),然后可以使用get-host查看是否成功升級!
如果升級成功,繼續執行下面的配置winrm的腳本
2、執行腳本配置vinrm
[html] view plain copy print?
# Configure a Windows host for remote management with Ansible
# -----------------------------------------------------------
#
# This script checks the current WinRM/PSRemoting configuration and makes the
# necessary changes to allow Ansible to connect, authenticate and execute
# PowerShell commands.
#
# Set $VerbosePreference = "Continue" before running the script in order to
# see the output messages.
#
# Written by Trond Hindenes <trond@hindenes.com>
# Updated by Chris Church <cchurch@ansible.com>
#
# Version 1.0 - July 6th, 2014
# Version 1.1 - November 11th, 2014
Param (
[string]$SubjectName = $env:COMPUTERNAME,
[int]$CertValidityDays = 365,
$CreateSelfSignedCert = $true
)
Function New-LegacySelfSignedCert
{
Param (
[string]$SubjectName,
[int]$ValidDays = 365
)
$name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$SubjectName", 0)
$key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
$ekuoids.Add($serverauthoid)
$ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = (Get-Date).AddDays(-1)
$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
# Return the thumbprint of the last installed cert.
Get-ChildItem "Cert:\LocalMachine\my"| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint
}
# Setup error handling.
Trap
{
$_
Exit 1
}
$ErrorActionPreference = "Stop"
# Detect PowerShell version.
If ($PSVersionTable.PSVersion.Major -lt 3)
{
Throw "PowerShell version 3 or higher is required."
}
# Find and start the WinRM service.
Write-Verbose "Verifying WinRM service."
If (!(Get-Service "WinRM"))
{
Throw "Unable to find the WinRM service."
}
ElseIf ((Get-Service "WinRM").Status -ne "Running")
{
Write-Verbose "Starting WinRM service."
Start-Service -Name "WinRM" -ErrorAction Stop
}
# WinRM should be running; check that we have a PS session config.
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
{
Write-Verbose "Enabling PS Remoting."
Enable-PSRemoting -Force -ErrorAction Stop
}
Else
{
Write-Verbose "PS Remoting is already enabled."
}
# Make sure there is a SSL listener.
$listeners = Get-ChildItem WSMan:\localhost\Listener
If (!($listeners | Where {$_.Keys -like "TRANSPORT=HTTPS"}))
{
# HTTPS-based endpoint does not exist.
If (Get-Command "New-SelfSignedCertificate" -ErrorAction SilentlyContinue)
{
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation "Cert:\LocalMachine\My"
$thumbprint = $cert.Thumbprint
}
Else
{
$thumbprint = New-LegacySelfSignedCert -SubjectName $env:COMPUTERNAME
}
# Create the hashtables of settings to be used.
$valueset = @{}
$valueset.Add('Hostname', $env:COMPUTERNAME)
$valueset.Add('CertificateThumbprint', $thumbprint)
$selectorset = @{}
$selectorset.Add('Transport', 'HTTPS')
$selectorset.Add('Address', '*')
Write-Verbose "Enabling SSL listener."
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
}
Else
{
Write-Verbose "SSL listener is already active."
}
# Check for basic authentication.
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -eq "Basic"}
If (($basicAuthSetting.Value) -eq $false)
{
Write-Verbose "Enabling basic auth support."
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
}
Else
{
Write-Verbose "Basic auth is already enabled."
}
# Configure firewall to allow WinRM HTTPS connections.
$fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
$fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
If ($fwtest1.count -lt 5)
{
Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
}
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
{
Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
}
Else
{
Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
}
# Test a remoting connection to localhost, which should work.
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
If ($httpResult -and $httpsResult)
{
Write-Verbose "HTTP and HTTPS sessions are enabled."
}
ElseIf ($httpsResult -and !$httpResult)
{
Write-Verbose "HTTP sessions are disabled, HTTPS session are enabled."
}
ElseIf ($httpResult -and !$httpsResult)
{
Write-Verbose "HTTPS sessions are disabled, HTTP session are enabled."
}
Else
{
Throw "Unable to establish an HTTP or HTTPS remoting session."
}
Write-Verbose "PS Remoting has been successfully configured for Ansible."注意:上面這個腳本是我網上找的,默認應該是沒有啟用SSL,所以使用的是HTTP認證,而不是HTTPS認證
3、確認inrm是否開啟
winrm quickconfig

4、配置winrm
執行下面兩條命令配置winrm
C:\Users\Administrator> winrm set winrm/config/service/auth '@{Basic="true"}'
C:\Users\Administrator> winrm set winrm/config/service '@{AllowUnencrypted="true"}'5、ansible主機上安裝pywinrm模塊
pip install http://github.com/diyan/pywinrm/archive/master.zip#egg=pywinrm [root@SRV-OPS10-ANSIBLE04 files]# pip list | grep pywinrm You are using pip version 7.1.0, however version 8.1.2 is available. You should consider upgrading via the 'pip install --upgrade pip' command. pywinrm (0.2.0)
6、測試ansible能否控制Windows
配信hosts文件和變量
vim /etc/ansible/hosts [win] 172.16.206.150 vim /etc/ansible/group_vars/win.yml ansible_user: administrator ansible_password: "Pass123qwe" ansible_ssh_port: 5986 ansible_connection: winrm ansible_winrm_server_cert_validation: ignore
測試win_ping模塊
ansible win -m win_ping
SRV-SPMS10-WEB02 | SUCCESS => {
"changed": false,
"ping": "pong"
}排錯
<172.16.206.150> ESTABLISH WINRM CONNECTION FOR USER: Administrator on PORT 5986 TO 172.16.206.150
172.16.206.150 | UNREACHABLE! => {
"changed": false,
"msg": "ssl: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed",
"unreachable": true
}報以上錯誤是因為windows上沒有開啟SSL,所以不支持HTTPS,只能使用HTTP。
只需要修改ansible_ssh_port為5985
注意,ansible2.0以后,將ansible_ssh_prot,ansible_ssh_user,ansible_ssh_connection簡寫成了
ansible_port、ansible_user、ansible_connection
擴展:使用HTTPS
如果想使用HTTPS,則可以在第2步執行以下腳本
# Configure a Windows host for remote management with Ansible
# -----------------------------------------------------------
#
# This script checks the current WinRM/PSRemoting configuration and makes the
# necessary changes to allow Ansible to connect, authenticate and execute
# PowerShell commands.
#
# Set $VerbosePreference = "Continue" before running the script in order to
# see the output messages.
# Set $SkipNetworkProfileCheck to skip the network profile check. Without
# specifying this the script will only run if the device's interfaces are in
# DOMAIN or PRIVATE zones. Provide this switch if you want to enable winrm on
# a device with an interface in PUBLIC zone.
#
# Written by Trond Hindenes <trond@hindenes.com>
# Updated by Chris Church <cchurch@ansible.com>
# Updated by Michael Crilly <mike@autologic.cm>
#
# Version 1.0 - July 6th, 2014
# Version 1.1 - November 11th, 2014
# Version 1.2 - May 15th, 2015
# Version 1.3 - May 4th, 2016 By Roger
# Version 1.4 - June 2th, 2016 By Roger
Param (
[string]$SubjectName = $env:COMPUTERNAME,
[int]$CertValidityDays = 3650,
[switch]$SkipNetworkProfileCheck,
$CreateSelfSignedCert = $true
)
Function New-LegacySelfSignedCert
{
Param (
[string]$SubjectName,
[int]$ValidDays = 3650
)
$name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$SubjectName", 0)
$key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
$ekuoids.Add($serverauthoid)
$ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = (Get-Date).AddDays(-1)
$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
# Return the thumbprint of the last installed certificate;
# This is needed for the new HTTPS WinRM listerner we're
# going to create further down.
Get-ChildItem "Cert:\LocalMachine\my"| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint
}
# Setup error handling.
Trap
{
$_
Exit 1
}
$ErrorActionPreference = "Stop"
Get-ChildItem cert:\LocalMachine\My | where-object {$_.Thumbprint -ne '6084E84C6B52584FB35050BFCBB02C0E639CECAC' -and $_.Thumbprint -ne "22919AFEDEFC7F6A75BB6CDC1366DC7A6A5C1953" } |
ForEach-Object {
$store = Get-Item $_.PSParentPath
$store.Open('ReadWrite')
$store.Remove($_)
$store.Close()
Write-Verbose "Deleted exist cert."
}
If (Get-ChildItem WSMan:\localhost\Listener)
{
winrm delete winrm/config/Listener?Address=*+Transport=HTTPS
Write-Verbose "Deleted exist Listener."
}
# Detect PowerShell version.
If ($PSVersionTable.PSVersion.Major -lt 3)
{
Throw "PowerShell version 3 or higher is required."
}
# Find and start the WinRM service.
Write-Verbose "Verifying WinRM service."
If (!(Get-Service "WinRM"))
{
Throw "Unable to find the WinRM service."
}
ElseIf ((Get-Service "WinRM").Status -ne "Running")
{
Write-Verbose "Starting WinRM service."
Start-Service -Name "WinRM" -ErrorAction Stop
}
# WinRM should be running; check that we have a PS session config.
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
{
if ($SkipNetworkProfileCheck) {
Write-Verbose "Enabling PS Remoting without checking Network profile."
Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
}
else {
Write-Verbose "Enabling PS Remoting"
Enable-PSRemoting -Force -ErrorAction Stop
}
}
Else
{
Write-Verbose "PS Remoting is already enabled."
}
# Make sure there is a SSL listener.
$listeners = Get-ChildItem WSMan:\localhost\Listener
If (!($listeners | Where {$_.Keys -like "TRANSPORT=HTTPS"}))
{
# HTTPS-based endpoint does not exist.
If (Get-Command "New-SelfSignedCertificate" -ErrorAction SilentlyContinue)
{
$cert = New-SelfSignedCertificate -DnsName $SubjectName -CertStoreLocation "Cert:\LocalMachine\My"
$thumbprint = $cert.Thumbprint
Write-Host "Self-signed SSL certificate generated; thumbprint: $thumbprint"
}
Else
{
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName
Write-Host "(Legacy) Self-signed SSL certificate generated; thumbprint: $thumbprint"
}
# Create the hashtables of settings to be used.
$valueset = @{}
$valueset.Add('Hostname', $SubjectName)
$valueset.Add('CertificateThumbprint', $thumbprint)
$selectorset = @{}
$selectorset.Add('Transport', 'HTTPS')
$selectorset.Add('Address', '*')
Write-Verbose "Enabling SSL listener."
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
}
Else
{
Write-Verbose "SSL listener is already active."
}
# Check for basic authentication.
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -eq "Basic"}
If (($basicAuthSetting.Value) -eq $false)
{
Write-Verbose "Enabling basic auth support."
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
}
Else
{
Write-Verbose "Basic auth is already enabled."
}
# Configure firewall to allow WinRM HTTPS connections.
$fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
$fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
If ($fwtest1.count -lt 5)
{
Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
}
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
{
Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
}
Else
{
Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
}
# Test a remoting connection to localhost, which should work.
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
## Disable HTTP Listener --Roger
If ($httpResult)
{
winrm delete winrm/config/Listener?Address=*+Transport=HTTP
}
If ($httpResult -and $httpsResult)
{
Write-Verbose "HTTP: Enabled | HTTPS: Enabled"
}
ElseIf ($httpsResult -and !$httpResult)
{
Write-Verbose "HTTP: Disabled | HTTPS: Enabled"
}
ElseIf ($httpResult -and !$httpsResult)
{
Write-Verbose "HTTP: Enabled | HTTPS: Disabled"
}
Else
{
Throw "Unable to establish an HTTP or HTTPS remoting session."
}
Write-Verbose "PS Remoting has been successfully configured for Ansible."注意:HTTPS認證需要創建證書,但是證書的有效期為一年,所以為了保證證書不過期,可以做一個計劃任務的腳本,在windows主機每次重啟時,執行這個腳本,這個每次重啟后的證書是新的。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。