After a lot of trial and error, I finally found a way to make it work. Here is what I did.
As noted before, rather than trying to run an installer from a share,
I simply copied it on to the local disc of the VM.
Before running Ansible on windows, the operating system has to be configured using (for example) the
ConfigureRemotingForAnsible.ps1
script. I took the defaults. I didn’t bother setting up any of the advanced options like CredSSP, as in practice there didn’t seem to be
any benefit.
I assume you are pretty familiar with Ansible. The structure is what you will recognise.
1
2
3
4
5
6
7
8
9
10
| |____inventory
| |____inventory
|____win
| |____tasks
| | |____main.yml
| |____files
| | |____schedrun.ps1
| |____templates
| | |____copyinstaller.bat
|____win.yml
|
Inventory File
1
2
3
4
5
6
7
8
| [win]
winhost
[win:vars]
ansible_user="ansible_user"
ansible_password="Password1"
ansible_connection="winrm"
ansible_winrm_server_cert_validation=ignore
|
I use password authentication. It’s all very low tech.
Now, the playbook. This copies the file to the local location.
win.yml
1
2
3
4
5
| ---
- name: Windows
hosts: winpsu
roles:
- psw
|
This just calls the role.
main.yml
1
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
| - name: Create directories for use by the install
win_file:
path: "{{ item }}"
state: directory
with_items:
- "{{ install_base }}"
- "{{ ansibletmp }}"
- "{{ scriptdir }}"
- name: Deploy copy script
win_template:
src: templates/copyinstaller.bat.j2
dest: "{{ ansibletmp }}\\copyinstaller.bat"
- name: Copy install files to local VM
script: 'files/schedbat.ps1 -script {{ ansibletmp }}\\copyinstaller.bat'
register: copy
- debug: var=copy
- name: Install puppet from the MSI file
win_package:
path: "{{ puppet_installer }}"
state: present
- name: Stop the puppet agent service from running to stop all the error messages.
win_service:
name: "Puppet Agent"
state: Stopped
start_mode: disabled
- name: Run the installer
script: "files/scheduleps1.ps1 -script \"{{ install_path }}\\psft-dpk-setup.ps1 -env_type midtier -deploy_only -silent\" -logfile {{ ansibletmp }}\\install.log"
args:
creates: "{{ ps_home }}\\appserv\\psadmin.exe"
register: installfiles
- debug: var=installfiles
|
The first step creates some directories. The next copies across a batch file, which is used to copy
the installer from the share where it is downloaded.
copyinstaller.bat
1
2
3
4
5
6
| #jinja2:newline_sequence:'\r\n'
{{ '>' }} "{{ ansibletmp }}\copy.txt" {{ '2>&1' }} (
net use Z: \\internal\general\Peoplesoft_Applications /USER:{{ win_user }} {{ win_pass }}
mkdir "{{ install_base }}"
robocopy "z:\{{ install_dir }}" "{{ install_base }}\{{ install_dir }}" /MIR
)
|
This is a template because it was easier to pass the directories this way. Different
versions of the installer are in different directories. The bash script is simply a
few commands wrapped in brackets, and the output is all redirected to a file.
This script is copied with the variables replaced.
Next we run a powershell script.
1
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
| param(
[string]$script
)
function Invoke-Script {
param(
[string]$script
)
$invokeScript = {
param(
[string]$script
)
$f=[system.io.fileinfo]$script ;
$baseFile = join-path $f.DirectoryName $f.BaseName
if (Test-Path("$baseFile.DONE")) {
Move-Item "$baseFile.DONE" "$baseFile.$((Get-Date -Format O) -replace ':','').BAK" ;
}
Set-ExecutionPolicy Bypass -Force | Out-File "$baseFile.PROCESSING" -Append;
Get-ExecutionPolicy -list | Out-File "$baseFile.PROCESSING" -Append;
$Out=Start-Process -FilePath "$env:comspec" -ArgumentList "/c $script" -Verb runAs -Wait;
Write-Output "$?" | Out-File "$baseFile.PROCESSING" -Append ;
Write-Output $Out | Out-File "$baseFile.PROCESSING" -Append ;
Move-Item "$baseFile.PROCESSING" "$baseFile.DONE" ;
} ;
# remove the job (if exists), create a new one.
# NOTE: this will clobber any previous job
$jobName = "Invoke-Script" ;
$result = Get-ScheduledJob | Where { $_.Name -eq "$jobName" } ;
if ($result) {
Unregister-ScheduledJob -Name "$jobName" ;
}
$O = New-ScheduledJobOption -RunElevated
Register-ScheduledJob -Name "$jobName" -RunNow -ScriptBlock $invokeScript -ArgumentList $script -ScheduledJobOption $O ;
}
# when passed in from ansible, be sure to wrap windows path in ''
$script = $script -replace "'","" ;
$f=[system.io.fileinfo]$script ;
$baseFile = join-path $f.DirectoryName $f.BaseName
Write-Host "Running: $script" ;
Invoke-Script -script $script ;
# monitor for DONE file and report
$doneFile = "$baseFile.DONE" ;
Start-Sleep -s 5 ;
while(!(Test-Path $doneFile)) {
Start-Sleep -s 5 ;
}
write-output "Base file $baseFile" ;
Get-Content $doneFile ;
|
This is based on a script by Jason Huggins in an
ansible bug report
Thanks Jason!
This is because a Windows share is mounted as part of a session. The RDP connection is not
allowed a session. But a scheduled task is. The RDP connection is allowed to create
a task. So that is what we do.
The job is scheduled to call the contents of the $invokeScript variable. This sets the
execution policy to allow the file to be run, then runs the batch file. Lastly it
renames a file to .DONE. The rest of the script waits for this rename, so we know
once the script completes, the scheduled task has completed. Once it is complete, it
writes the two files to standard output. Ansible can be told to register the output and
write it out using a debug statement.
The next step installs puppet, which is what Oracle have chosen to manage PeopleSoft.
This creates a job which keeps trying to talk to the puppet master (Puppet has an agent
installed on the node which talks to a controller, the puppet master, to get instructions.
Since we don’t have a master, this continually errors, so it is best to switch it off.
Lastly the installer is run from from the folders that were copied across using the same script
as before to create it a session. I am not sure if this is necessary, it was left over
from when I was trying to run it from the share, which proved rather painful. If you
do want to try running from a share, you have to change Internet Explorer security to allow it.
There is more in my playbook, but this is the difficult part. The rest is just doing
the same I would in unix, but replacing modules where necessary with the
windows equivalents.