天天看點

Ansible控制Windows操作步驟

環境:

CentOS 6.75(Ansible 2.0)

Windows Server 2012 (PowerShell 4.0)

1、確定PowerShell版本為3.0以上

ansible要控制windows,必須要求windows主機的PowerShell版本為3.0以上,如果版本不滿足要求需要更新PowerShell。

檢視PowerShell版本可以使用以下指令

1

<code>$PSVersionTable.PSVersion</code>

如果版本不滿足要求,可以使用下面腳本進行更新(将腳本内容儲存到一個powershell腳本中,)

首先啟動powershell必須是用超管權限啟動,然後 set-ExecutionPolicy RemoteSigned ,以後才能正确執行下面的腳本(腳本随便放哪都行,找到放置的對應路徑就行)

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

<code>[html] view plain copy print?</code>

<code># Powershell script to upgrade a PowerShell 2.0 system to PowerShell 3.0  </code>

<code># based on http://occasionalutility.blogspot.com/2013/11/everyday-powershell-part-7-powershell.html  </code>

<code>#  </code>

<code># some Ansible modules that may use Powershell 3 features, so systems may need  </code>

<code># to be upgraded.  This may be used by a sample playbook.  Refer to the windows  </code>

<code># documentation on docs.ansible.com for details.  </code>

<code>#   </code>

<code># - hosts: windows  </code>

<code>#   tasks:  </code>

<code>#     - script: upgrade_to_ps3.ps1  </code>

<code>  </code> 

<code># Get version of OS  </code>

<code># 6.0 is 2008  </code>

<code># 6.1 is 2008 R2  </code>

<code># 6.2 is 2012  </code>

<code># 6.3 is 2012 R2  </code>

<code>if</code> <code>($PSVersionTable.psversion.Major -</code><code>ge</code> <code>3)  </code>

<code>{  </code>

<code>    </code><code>write-host </code><code>"Powershell 3 Installed already; You don't need this"</code>  

<code>    </code><code>Exit  </code>

<code>}  </code>

<code>$powershellpath = </code><code>"C:\powershell"</code>  

<code>function</code> <code>download-</code><code>file</code>  

<code>    </code><code>param ([string]$path, [string]$</code><code>local</code><code>)  </code>

<code>    </code><code>$client = new-object system.net.WebClient  </code>

<code>    </code><code>$client.Headers.Add(</code><code>"user-agent"</code><code>, </code><code>"PowerShell"</code><code>)  </code>

<code>    </code><code>$client.downloadfile($path, $</code><code>local</code><code>)  </code>

<code>if</code> <code>(!(</code><code>test</code><code>-path $powershellpath))  </code>

<code>    </code><code>New-Item -ItemType directory -Path $powershellpath  </code>

<code># .NET Framework 4.0 is necessary.  </code>

<code>#if (($PSVersionTable.CLRVersion.Major) -lt 2)  </code>

<code>#{  </code>

<code>#    $DownloadUrl = "http://download.microsoft.com/download/B/A/4/BA4A7E71-2906-4B2D-A0E1-80CF16844F5F/dotNetFx45_Full_x86_x64.exe"  </code>

<code>#    $FileName = $DownLoadUrl.Split('/')[-1]  </code>

<code>#    download-file $downloadurl "$powershellpath\$filename"  </code>

<code>#    ."$powershellpath\$filename" /quiet /norestart  </code>

<code>#}  </code>

<code>#You may need to reboot after the .NET install if so just run the script again.  </code>

<code># If the Operating System is above 6.2, then you already have PowerShell Version &gt; 3  </code>

<code>if</code> <code>([Environment]::OSVersion.Version.Major -gt 6)  </code>

<code>    </code><code>write-host </code><code>"OS is new; upgrade not needed."</code>  

<code>$osminor = [environment]::OSVersion.Version.Minor  </code>

<code>$architecture = $ENV:PROCESSOR_ARCHITECTURE  </code>

<code>if</code> <code>($architecture -</code><code>eq</code> <code>"AMD64"</code><code>)  </code>

<code>    </code><code>$architecture = </code><code>"x64"</code>  

<code>}    </code>

<code>else</code>  

<code>    </code><code>$architecture = </code><code>"x86"</code>   

<code>}   </code>

<code>if</code> <code>($osminor -</code><code>eq</code> <code>1)  </code>

<code>    </code><code>$DownloadUrl = </code><code>"http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-"</code> <code>+ $architecture + </code><code>".msu"</code>  

<code>elseif ($osminor -</code><code>eq</code> <code>0)  </code>

<code>    </code><code>$DownloadUrl = </code><code>"http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-"</code> <code>+ $architecture + </code><code>".msu"</code>  

<code>    </code><code># Nothing to do; In theory this point will never be reached.  </code>

<code>$FileName = $DownLoadUrl.Split(</code><code>'/'</code><code>)[-1]  </code>

<code>download-</code><code>file</code> <code>$downloadurl </code><code>"$powershellpath\$filename"</code>  

<code> </code><code>write-host </code><code>"$powershellpath\$filename"</code>  

<code>Start-Process -FilePath </code><code>"$powershellpath\$filename"</code> <code>-ArgumentList </code><code>/quiet</code>

執行完了之後,需要重新開機電腦(自動),然後可以使用get-host檢視是否成功更新!

如果更新成功,繼續執行下面的配置winrm的腳本

2、執行腳本配置vinrm

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

<code># Configure a Windows host for remote management with Ansible  </code>

<code># -----------------------------------------------------------  </code>

<code># This script checks the current WinRM/PSRemoting configuration and makes the  </code>

<code># necessary changes to allow Ansible to connect, authenticate and execute  </code>

<code># PowerShell commands.  </code>

<code># Set $VerbosePreference = "Continue" before running the script in order to  </code>

<code># see the output messages.  </code>

<code># Written by Trond Hindenes &lt;[email protected]&gt;  </code>

<code># Updated by Chris Church &lt;[email protected]&gt;  </code>

<code># Version 1.0 - July 6th, 2014  </code>

<code># Version 1.1 - November 11th, 2014  </code>

<code>Param (  </code>

<code>    </code><code>[string]$SubjectName = $</code><code>env</code><code>:COMPUTERNAME,  </code>

<code>    </code><code>[int]$CertValidityDays = 365,  </code>

<code>    </code><code>$CreateSelfSignedCert = $</code><code>true</code>  

<code>)  </code>

<code>Function New-LegacySelfSignedCert  </code>

<code>    </code><code>Param (  </code>

<code>        </code><code>[string]$SubjectName,  </code>

<code>        </code><code>[int]$ValidDays = 365  </code>

<code>    </code><code>)  </code>

<code>      </code> 

<code>    </code><code>$name = New-Object -COM </code><code>"X509Enrollment.CX500DistinguishedName.1"</code>  

<code>    </code><code>$name.Encode(</code><code>"CN=$SubjectName"</code><code>, 0)  </code>

<code>    </code><code>$key = New-Object -COM </code><code>"X509Enrollment.CX509PrivateKey.1"</code>  

<code>    </code><code>$key.ProviderName = </code><code>"Microsoft RSA SChannel Cryptographic Provider"</code>  

<code>    </code><code>$key.KeySpec = 1  </code>

<code>    </code><code>$key.Length = 1024  </code>

<code>    </code><code>$key.SecurityDescriptor = </code><code>"D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"</code>  

<code>    </code><code>$key.MachineContext = 1  </code>

<code>    </code><code>$key.Create()  </code>

<code>    </code><code>$serverauthoid = New-Object -COM </code><code>"X509Enrollment.CObjectId.1"</code>  

<code>    </code><code>$serverauthoid.InitializeFromValue(</code><code>"1.3.6.1.5.5.7.3.1"</code><code>)  </code>

<code>    </code><code>$ekuoids = New-Object -COM </code><code>"X509Enrollment.CObjectIds.1"</code>  

<code>    </code><code>$ekuoids.Add($serverauthoid)  </code>

<code>    </code><code>$ekuext = New-Object -COM </code><code>"X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"</code>  

<code>    </code><code>$ekuext.InitializeEncode($ekuoids)  </code>

<code>    </code><code>$cert = New-Object -COM </code><code>"X509Enrollment.CX509CertificateRequestCertificate.1"</code>  

<code>    </code><code>$cert.InitializeFromPrivateKey(2, $key, </code><code>""</code><code>)  </code>

<code>    </code><code>$cert.Subject = $name  </code>

<code>    </code><code>$cert.Issuer = $cert.Subject  </code>

<code>    </code><code>$cert.NotBefore = (Get-Date).AddDays(-1)  </code>

<code>    </code><code>$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)  </code>

<code>    </code><code>$cert.X509Extensions.Add($ekuext)  </code>

<code>    </code><code>$cert.Encode()  </code>

<code>    </code><code>$enrollment = New-Object -COM </code><code>"X509Enrollment.CX509Enrollment.1"</code>  

<code>    </code><code>$enrollment.InitializeFromRequest($cert)  </code>

<code>    </code><code>$certdata = $enrollment.CreateRequest(0)  </code>

<code>    </code><code>$enrollment.InstallResponse(2, $certdata, 0, </code><code>""</code><code>)  </code>

<code>    </code><code># Return the thumbprint of the last installed cert.  </code>

<code>    </code><code>Get-ChildItem </code><code>"Cert:\LocalMachine\my"</code><code>| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint  </code>

<code># Setup error handling.  </code>

<code>Trap  </code>

<code>    </code><code>$_  </code>

<code>    </code><code>Exit 1  </code>

<code>$ErrorActionPreference = </code><code>"Stop"</code>  

<code># Detect PowerShell version.  </code>

<code>If ($PSVersionTable.PSVersion.Major -lt 3)  </code>

<code>    </code><code>Throw </code><code>"PowerShell version 3 or higher is required."</code>  

<code># Find and start the WinRM service.  </code>

<code>Write-Verbose </code><code>"Verifying WinRM service."</code>  

<code>If (!(Get-Service </code><code>"WinRM"</code><code>))  </code>

<code>    </code><code>Throw </code><code>"Unable to find the WinRM service."</code>  

<code>ElseIf ((Get-Service </code><code>"WinRM"</code><code>).Status -</code><code>ne</code> <code>"Running"</code><code>)  </code>

<code>    </code><code>Write-Verbose </code><code>"Starting WinRM service."</code>  

<code>    </code><code>Start-Service -Name </code><code>"WinRM"</code> <code>-ErrorAction Stop  </code>

<code># WinRM should be running; check that we have a PS session config.  </code>

<code>If (!(Get-PSSessionConfiguration -Verbose:$</code><code>false</code><code>) -or (!(Get-ChildItem WSMan:\localhost\Listener)))  </code>

<code>    </code><code>Write-Verbose </code><code>"Enabling PS Remoting."</code>  

<code>    </code><code>Enable-PSRemoting -Force -ErrorAction Stop  </code>

<code>Else  </code>

<code>    </code><code>Write-Verbose </code><code>"PS Remoting is already enabled."</code>  

<code># Make sure there is a SSL listener.  </code>

<code>$listeners = Get-ChildItem WSMan:\localhost\Listener  </code>

<code>If (!($listeners | Where {$_.Keys -like </code><code>"TRANSPORT=HTTPS"</code><code>}))  </code>

<code>    </code><code># HTTPS-based endpoint does not exist.  </code>

<code>    </code><code>If (Get-Command </code><code>"New-SelfSignedCertificate"</code> <code>-ErrorAction SilentlyContinue)  </code>

<code>    </code><code>{  </code>

<code>        </code><code>$cert = New-SelfSignedCertificate -DnsName $</code><code>env</code><code>:COMPUTERNAME -CertStoreLocation </code><code>"Cert:\LocalMachine\My"</code>  

<code>        </code><code>$thumbprint = $cert.Thumbprint  </code>

<code>    </code><code>}  </code>

<code>    </code><code>Else  </code>

<code>        </code><code>$thumbprint = New-LegacySelfSignedCert -SubjectName $</code><code>env</code><code>:COMPUTERNAME  </code>

<code>    </code><code># Create the hashtables of settings to be used.  </code>

<code>    </code><code>$valueset = @{}  </code>

<code>    </code><code>$valueset.Add(</code><code>'Hostname'</code><code>, $</code><code>env</code><code>:COMPUTERNAME)  </code>

<code>    </code><code>$valueset.Add(</code><code>'CertificateThumbprint'</code><code>, $thumbprint)  </code>

<code>    </code><code>$selectorset = @{}  </code>

<code>    </code><code>$selectorset.Add(</code><code>'Transport'</code><code>, </code><code>'HTTPS'</code><code>)  </code>

<code>    </code><code>$selectorset.Add(</code><code>'Address'</code><code>, </code><code>'*'</code><code>)  </code>

<code>    </code><code>Write-Verbose </code><code>"Enabling SSL listener."</code>  

<code>    </code><code>New-WSManInstance -ResourceURI </code><code>'winrm/config/Listener'</code> <code>-SelectorSet $selectorset -ValueSet $valueset  </code>

<code>    </code><code>Write-Verbose </code><code>"SSL listener is already active."</code>  

<code># Check for basic authentication.  </code>

<code>$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -</code><code>eq</code> <code>"Basic"</code><code>}  </code>

<code>If (($basicAuthSetting.Value) -</code><code>eq</code> <code>$</code><code>false</code><code>)  </code>

<code>    </code><code>Write-Verbose </code><code>"Enabling basic auth support."</code>  

<code>    </code><code>Set-Item -Path </code><code>"WSMan:\localhost\Service\Auth\Basic"</code> <code>-Value $</code><code>true</code>  

<code>    </code><code>Write-Verbose </code><code>"Basic auth is already enabled."</code>  

<code># Configure firewall to allow WinRM HTTPS connections.  </code>

<code>$fwtest1 = netsh advfirewall firewall show rule name=</code><code>"Allow WinRM HTTPS"</code>  

<code>$fwtest2 = netsh advfirewall firewall show rule name=</code><code>"Allow WinRM HTTPS"</code> <code>profile=any  </code>

<code>If ($fwtest1.count -lt 5)  </code>

<code>    </code><code>Write-Verbose </code><code>"Adding firewall rule to allow WinRM HTTPS."</code>  

<code>    </code><code>netsh advfirewall firewall add rule profile=any name=</code><code>"Allow WinRM HTTPS"</code> <code>dir</code><code>=</code><code>in</code> <code>localport=5986 protocol=TCP action=allow  </code>

<code>ElseIf (($fwtest1.count -</code><code>ge</code> <code>5) -and ($fwtest2.count -lt 5))  </code>

<code>    </code><code>Write-Verbose </code><code>"Updating firewall rule to allow WinRM HTTPS for any profile."</code>  

<code>    </code><code>netsh advfirewall firewall </code><code>set</code> <code>rule name=</code><code>"Allow WinRM HTTPS"</code> <code>new profile=any  </code>

<code>    </code><code>Write-Verbose </code><code>"Firewall rule already exists to allow WinRM HTTPS."</code>  

<code># Test a remoting connection to localhost, which should work.  </code>

<code>$httpResult = Invoke-Command -ComputerName </code><code>"localhost"</code> <code>-ScriptBlock {$</code><code>env</code><code>:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue  </code>

<code>$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck  </code>

<code>$httpsResult = New-PSSession -UseSSL -ComputerName </code><code>"localhost"</code> <code>-SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue  </code>

<code>If ($httpResult -and $httpsResult)  </code>

<code>    </code><code>Write-Verbose </code><code>"HTTP and HTTPS sessions are enabled."</code>  

<code>ElseIf ($httpsResult -and !$httpResult)  </code>

<code>    </code><code>Write-Verbose </code><code>"HTTP sessions are disabled, HTTPS session are enabled."</code>  

<code>ElseIf ($httpResult -and !$httpsResult)  </code>

<code>    </code><code>Write-Verbose </code><code>"HTTPS sessions are disabled, HTTP session are enabled."</code>  

<code>    </code><code>Throw </code><code>"Unable to establish an HTTP or HTTPS remoting session."</code>  

<code>Write-Verbose </code><code>"PS Remoting has been successfully configured for Ansible."</code>

注意:上面這個腳本是我網上找的,預設應該是沒有啟用SSL,是以使用的是HTTP認證,而不是HTTPS認證

3、确認inrm是否開啟

winrm quickconfig

<a href="http://s4.51cto.com/wyfs02/M02/89/5A/wKiom1gQWRvSyySiAAFVpP7oHSM558.png" target="_blank"></a>

4、配置winrm

執行下面兩條指令配置winrm

<code>C:\Users\Administrator&gt; winrm </code><code>set</code> <code>winrm</code><code>/config/service/auth</code> <code>'@{Basic="true"}'</code>

<code>C:\Users\Administrator&gt; winrm </code><code>set</code> <code>winrm</code><code>/config/service</code> <code>'@{AllowUnencrypted="true"}'</code>

5、ansible主機上安裝pywinrm子產品

<code>pip </code><code>install</code> <code>http:</code><code>//github</code><code>.com</code><code>/diyan/pywinrm/archive/master</code><code>.zip</code><code>#egg=pywinrm</code>

<code>[root@SRV-OPS10-ANSIBLE04 files]</code><code># pip list | grep pywinrm</code>

<code>You are using pip version 7.1.0, however version 8.1.2 is available.</code>

<code>You should consider upgrading via the </code><code>'pip install --upgrade pip'</code> <code>command</code><code>.</code>

<code>pywinrm (0.2.0)</code>

6、測試ansible能否控制Windows

配信hosts檔案和變量

<code>vim </code><code>/etc/ansible/hosts</code>

<code>[win]</code>

<code>172.16.206.150</code>

<code>vim </code><code>/etc/ansible/group_vars/win</code><code>.yml</code>

<code>ansible_user: administrator</code>

<code>ansible_password: </code><code>"Pass123qwe"</code>

<code>ansible_ssh_port: 5986</code>

<code>ansible_connection: winrm</code>

<code>ansible_winrm_server_cert_validation: ignore</code>

測試win_ping子產品

<code>ansible win -m win_ping</code>

<code>SRV-SPMS10-WEB02 | SUCCESS =&gt; {</code>

<code>    </code><code>"changed"</code><code>: </code><code>false</code><code>, </code>

<code>    </code><code>"ping"</code><code>: </code><code>"pong"</code>

<code>}</code>

排錯

<code>&lt;172.16.206.150&gt; ESTABLISH WINRM CONNECTION FOR USER: Administrator on PORT 5986 TO 172.16.206.150</code>

<code>172.16.206.150 | UNREACHABLE! =&gt; {</code>

<code>    </code><code>"msg"</code><code>: </code><code>"ssl: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed"</code><code>, </code>

<code>    </code><code>"unreachable"</code><code>: </code><code>true</code>

報以上錯誤是因為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步執行以下腳本

197

198

199

200

201

202

203

<code># Configure a Windows host for remote management with Ansible</code>

<code># -----------------------------------------------------------</code>

<code>#</code>

<code># This script checks the current WinRM/PSRemoting configuration and makes the</code>

<code># necessary changes to allow Ansible to connect, authenticate and execute</code>

<code># PowerShell commands.</code>

<code># Set $VerbosePreference = "Continue" before running the script in order to</code>

<code># see the output messages.</code>

<code># Set $SkipNetworkProfileCheck to skip the network profile check.  Without</code>

<code># specifying this the script will only run if the device's interfaces are in</code>

<code># DOMAIN or PRIVATE zones.  Provide this switch if you want to enable winrm on</code>

<code># a device with an interface in PUBLIC zone.</code>

<code># Written by Trond Hindenes &lt;[email protected]&gt;</code>

<code># Updated by Chris Church &lt;[email protected]&gt;</code>

<code># Updated by Michael Crilly &lt;[email protected]&gt;</code>

<code># Version 1.0 - July 6th, 2014</code>

<code># Version 1.1 - November 11th, 2014</code>

<code># Version 1.2 - May 15th, 2015</code>

<code># Version 1.3 - May 4th, 2016  By Roger</code>

<code># Version 1.4 - June 2th, 2016 By Roger</code>

<code>Param (</code>

<code>    </code><code>[string]$SubjectName = $</code><code>env</code><code>:COMPUTERNAME,</code>

<code>    </code><code>[int]$CertValidityDays = 3650,</code>

<code>    </code><code>[switch]$SkipNetworkProfileCheck,</code>

<code>    </code><code>$CreateSelfSignedCert = $</code><code>true</code>

<code>)</code>

<code>Function New-LegacySelfSignedCert</code>

<code>{</code>

<code>    </code><code>Param (</code>

<code>        </code><code>[string]$SubjectName,</code>

<code>        </code><code>[int]$ValidDays = 3650</code>

<code>    </code><code>)</code>

<code>    </code><code>$name = New-Object -COM </code><code>"X509Enrollment.CX500DistinguishedName.1"</code>

<code>    </code><code>$name.Encode(</code><code>"CN=$SubjectName"</code><code>, 0)</code>

<code>    </code><code>$key = New-Object -COM </code><code>"X509Enrollment.CX509PrivateKey.1"</code>

<code>    </code><code>$key.ProviderName = </code><code>"Microsoft RSA SChannel Cryptographic Provider"</code>

<code>    </code><code>$key.KeySpec = 1</code>

<code>    </code><code>$key.Length = 1024</code>

<code>    </code><code>$key.SecurityDescriptor = </code><code>"D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"</code>

<code>    </code><code>$key.MachineContext = 1</code>

<code>    </code><code>$key.Create()</code>

<code>    </code><code>$serverauthoid = New-Object -COM </code><code>"X509Enrollment.CObjectId.1"</code>

<code>    </code><code>$serverauthoid.InitializeFromValue(</code><code>"1.3.6.1.5.5.7.3.1"</code><code>)</code>

<code>    </code><code>$ekuoids = New-Object -COM </code><code>"X509Enrollment.CObjectIds.1"</code>

<code>    </code><code>$ekuoids.Add($serverauthoid)</code>

<code>    </code><code>$ekuext = New-Object -COM </code><code>"X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"</code>

<code>    </code><code>$ekuext.InitializeEncode($ekuoids)</code>

<code>    </code><code>$cert = New-Object -COM </code><code>"X509Enrollment.CX509CertificateRequestCertificate.1"</code>

<code>    </code><code>$cert.InitializeFromPrivateKey(2, $key, </code><code>""</code><code>)</code>

<code>    </code><code>$cert.Subject = $name</code>

<code>    </code><code>$cert.Issuer = $cert.Subject</code>

<code>    </code><code>$cert.NotBefore = (Get-Date).AddDays(-1)</code>

<code>    </code><code>$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)</code>

<code>    </code><code>$cert.X509Extensions.Add($ekuext)</code>

<code>    </code><code>$cert.Encode()</code>

<code>    </code><code>$enrollment = New-Object -COM </code><code>"X509Enrollment.CX509Enrollment.1"</code>

<code>    </code><code>$enrollment.InitializeFromRequest($cert)</code>

<code>    </code><code>$certdata = $enrollment.CreateRequest(0)</code>

<code>    </code><code>$enrollment.InstallResponse(2, $certdata, 0, </code><code>""</code><code>)</code>

<code>    </code><code># Return the thumbprint of the last installed certificate;</code>

<code>    </code><code># This is needed for the new HTTPS WinRM listerner we're</code>

<code>    </code><code># going to create further down.</code>

<code>    </code><code>Get-ChildItem </code><code>"Cert:\LocalMachine\my"</code><code>| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint</code>

<code># Setup error handling.</code>

<code>Trap</code>

<code>    </code><code>$_</code>

<code>    </code><code>Exit 1</code>

<code>$ErrorActionPreference = </code><code>"Stop"</code>

<code>Get-ChildItem cert:\LocalMachine\My | where-object {$_.Thumbprint -</code><code>ne</code> <code>'6084E84C6B52584FB35050BFCBB02C0E639CECAC'</code> <code>-and $_.Thumbprint -</code><code>ne</code> <code>"22919AFEDEFC7F6A75BB6CDC1366DC7A6A5C1953"</code> <code>} |</code>

<code>ForEach-Object { </code>

<code>    </code><code>$store = Get-Item $_.PSParentPath </code>

<code>    </code><code>$store.Open(</code><code>'ReadWrite'</code><code>) </code>

<code>    </code><code>$store.Remove($_) </code>

<code>    </code><code>$store.Close() </code>

<code>Write-Verbose </code><code>"Deleted exist cert."</code>

<code>    </code><code>}</code>

<code>If (Get-ChildItem WSMan:\localhost\Listener)</code>

<code>    </code><code>winrm delete winrm</code><code>/config/Listener</code><code>?Address=*+Transport=HTTPS</code>

<code>    </code><code>Write-Verbose </code><code>"Deleted exist Listener."</code>

<code># Detect PowerShell version.</code>

<code>If ($PSVersionTable.PSVersion.Major -lt 3)</code>

<code>    </code><code>Throw </code><code>"PowerShell version 3 or higher is required."</code>

<code># Find and start the WinRM service.</code>

<code>Write-Verbose </code><code>"Verifying WinRM service."</code>

<code>If (!(Get-Service </code><code>"WinRM"</code><code>))</code>

<code>    </code><code>Throw </code><code>"Unable to find the WinRM service."</code>

<code>ElseIf ((Get-Service </code><code>"WinRM"</code><code>).Status -</code><code>ne</code> <code>"Running"</code><code>)</code>

<code>    </code><code>Write-Verbose </code><code>"Starting WinRM service."</code>

<code>    </code><code>Start-Service -Name </code><code>"WinRM"</code> <code>-ErrorAction Stop</code>

<code># WinRM should be running; check that we have a PS session config.</code>

<code>If (!(Get-PSSessionConfiguration -Verbose:$</code><code>false</code><code>) -or (!(Get-ChildItem WSMan:\localhost\Listener)))</code>

<code>  </code><code>if</code> <code>($SkipNetworkProfileCheck) {</code>

<code>    </code><code>Write-Verbose </code><code>"Enabling PS Remoting without checking Network profile."</code>

<code>    </code><code>Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop</code>

<code>  </code><code>}</code>

<code>  </code><code>else</code> <code>{</code>

<code>    </code><code>Write-Verbose </code><code>"Enabling PS Remoting"</code>

<code>    </code><code>Enable-PSRemoting -Force -ErrorAction Stop</code>

<code>Else</code>

<code>    </code><code>Write-Verbose </code><code>"PS Remoting is already enabled."</code>

<code># Make sure there is a SSL listener.</code>

<code>$listeners = Get-ChildItem WSMan:\localhost\Listener</code>

<code>If (!($listeners | Where {$_.Keys -like </code><code>"TRANSPORT=HTTPS"</code><code>}))</code>

<code>    </code><code># HTTPS-based endpoint does not exist.</code>

<code>    </code><code>If (Get-Command </code><code>"New-SelfSignedCertificate"</code> <code>-ErrorAction SilentlyContinue)</code>

<code>    </code><code>{</code>

<code>        </code><code>$cert = New-SelfSignedCertificate -DnsName $SubjectName -CertStoreLocation </code><code>"Cert:\LocalMachine\My"</code>

<code>        </code><code>$thumbprint = $cert.Thumbprint</code>

<code>        </code><code>Write-Host </code><code>"Self-signed SSL certificate generated; thumbprint: $thumbprint"</code>

<code>    </code><code>Else</code>

<code>        </code><code>$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName</code>

<code>        </code><code>Write-Host </code><code>"(Legacy) Self-signed SSL certificate generated; thumbprint: $thumbprint"</code>

<code>    </code><code># Create the hashtables of settings to be used.</code>

<code>    </code><code>$valueset = @{}</code>

<code>    </code><code>$valueset.Add(</code><code>'Hostname'</code><code>, $SubjectName)</code>

<code>    </code><code>$valueset.Add(</code><code>'CertificateThumbprint'</code><code>, $thumbprint)</code>

<code>    </code><code>$selectorset = @{}</code>

<code>    </code><code>$selectorset.Add(</code><code>'Transport'</code><code>, </code><code>'HTTPS'</code><code>)</code>

<code>    </code><code>$selectorset.Add(</code><code>'Address'</code><code>, </code><code>'*'</code><code>)</code>

<code>    </code><code>Write-Verbose </code><code>"Enabling SSL listener."</code>

<code>    </code><code>New-WSManInstance -ResourceURI </code><code>'winrm/config/Listener'</code> <code>-SelectorSet $selectorset -ValueSet $valueset</code>

<code>    </code><code>Write-Verbose </code><code>"SSL listener is already active."</code>

<code># Check for basic authentication.</code>

<code>$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -</code><code>eq</code> <code>"Basic"</code><code>}</code>

<code>If (($basicAuthSetting.Value) -</code><code>eq</code> <code>$</code><code>false</code><code>)</code>

<code>    </code><code>Write-Verbose </code><code>"Enabling basic auth support."</code>

<code>    </code><code>Set-Item -Path </code><code>"WSMan:\localhost\Service\Auth\Basic"</code> <code>-Value $</code><code>true</code>

<code>    </code><code>Write-Verbose </code><code>"Basic auth is already enabled."</code>

<code># Configure firewall to allow WinRM HTTPS connections.</code>

<code>$fwtest1 = netsh advfirewall firewall show rule name=</code><code>"Allow WinRM HTTPS"</code>

<code>$fwtest2 = netsh advfirewall firewall show rule name=</code><code>"Allow WinRM HTTPS"</code> <code>profile=any</code>

<code>If ($fwtest1.count -lt 5)</code>

<code>    </code><code>Write-Verbose </code><code>"Adding firewall rule to allow WinRM HTTPS."</code>

<code>    </code><code>netsh advfirewall firewall add rule profile=any name=</code><code>"Allow WinRM HTTPS"</code> <code>dir</code><code>=</code><code>in</code> <code>localport=5986 protocol=TCP action=allow</code>

<code>ElseIf (($fwtest1.count -</code><code>ge</code> <code>5) -and ($fwtest2.count -lt 5))</code>

<code>    </code><code>Write-Verbose </code><code>"Updating firewall rule to allow WinRM HTTPS for any profile."</code>

<code>    </code><code>netsh advfirewall firewall </code><code>set</code> <code>rule name=</code><code>"Allow WinRM HTTPS"</code> <code>new profile=any</code>

<code>    </code><code>Write-Verbose </code><code>"Firewall rule already exists to allow WinRM HTTPS."</code>

<code># Test a remoting connection to localhost, which should work.</code>

<code>$httpResult = Invoke-Command -ComputerName </code><code>"localhost"</code> <code>-ScriptBlock {$</code><code>env</code><code>:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue</code>

<code>$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck</code>

<code>$httpsResult = New-PSSession -UseSSL -ComputerName </code><code>"localhost"</code> <code>-SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue</code>

<code>## Disable HTTP Listener --Roger</code>

<code>If ($httpResult)</code>

<code>    </code><code>winrm delete winrm</code><code>/config/Listener</code><code>?Address=*+Transport=HTTP</code>

<code>If ($httpResult -and $httpsResult)</code>

<code>   </code><code>Write-Verbose </code><code>"HTTP: Enabled | HTTPS: Enabled"</code>

<code>ElseIf ($httpsResult -and !$httpResult)</code>

<code>    </code><code>Write-Verbose </code><code>"HTTP: Disabled | HTTPS: Enabled"</code>

<code>ElseIf ($httpResult -and !$httpsResult)</code>

<code>    </code><code>Write-Verbose </code><code>"HTTP: Enabled | HTTPS: Disabled"</code>

<code>    </code><code>Throw </code><code>"Unable to establish an HTTP or HTTPS remoting session."</code>

注意:HTTPS認證需要建立證書,但是證書的有效期為一年,是以為了保證證書不過期,可以做一個計劃任務的腳本,在windows主機每次重新開機時,執行這個腳本,這個每次重新開機後的證書是新的。

本文轉自 曾哥最愛 51CTO部落格,原文連結:http://blog.51cto.com/zengestudy/1865946,如需轉載請自行聯系原作者

繼續閱讀