Ansible playbook stuck indefinitely on remotely executing a PowerShell script - windows

I have an issue when trying to remotely execute a PowerShell script with Ansible. The PowerShell script (which works on its own without Ansible) essentially creates a virtual machine and copies a sysprepped VHD which is located in our NAS. It needs 3 arguments from the user (on which server do you want to create the virtual machine in, on which partition should the vhd and vm data be located in and what will be the name of the VM).
This is how the playbook looks like:
- hosts: windows_host
tasks:
- name: Run remote PowerShell script
win_shell: powershell.exe -ExecutionPolicy ByPass -File C:/Path/To/Script/Script.ps1 {{ server }} {{ partition }} {{ hostname }}
This is how I execute the playbook:
ansible-playbook /etc/ansible/playbook.yml --extra-var "server=server.mydomain.local partition=E: hostname=devtest" -vvvv
The connection gets established, but the playbook never finishes it just stays stuck. Enabling debug and verbose does not give any additional information. This is the last line I get when using debugging:
<windows_host.MYDOMAIN.LOCAL> ESTABLISH WINRM CONNECTION FOR USER: user#MYDOMAIN.LOCAL on PORT 5985 TO windows_host.MYDOMAIN.LOCAL
1058240 1669392256.73059: checking if winrm_host windows_host.MYDOMAIN.LOCAL is an IPv6 address
calling kinit with pexpect for principal user#MYDOMAIN.LOCAL
EXEC (via pipeline wrapper)
I created a different playbook and PowerShell script (creates a file which name gets assigned by the user)
$name=$args[0]
New-Item -Path "C:\Temp$name.txt"
and I am able to successfully execute the playbook which starts the PowerShell script without error.
Below is my ansible configuration (if needed):
user#ansible:/etc/ansible$ ansible -i hosts windows_host -m setup
HOSTNAME.MYDOMAIN.LOCAL | SUCCESS => {
"ansible_facts": {
"ansible_architecture": "64-bit",
"ansible_architecture2": "x86_64",
"ansible_bios_date": "05/23/2012",
"ansible_bios_version": "090006",
"ansible_date_time": {
[more data]
"ansible_distribution": "Microsoft Windows Server 2022 Datacenter",
"ansible_distribution_major_version": "10",
"ansible_distribution_version": "10.0.20348.0",
"ansible_domain": "MYDOMAIN.LOCAL",
[[more data]]
},
"ansible_fqdn": "HOSTNAME.MYDOMAIN.LOCAL",
"ansible_hostname": "HOSTNAME",
"ansible_interfaces": [
{
"connection_name": "Ethernet",
"default_gateway": "192.168.0.254",
"dns_domain": null,
"interface_index": 5,
"interface_name": "Microsoft Hyper-V Network Adapter",
"ipv4": {
"address": "192.168.0.100",
"prefix": "24"
},
"ipv6": {},
"mtu": 1500,
"speed": 10000
}
],
"ansible_ip_addresses": [
"192.168.0.100"
],
user#ansible:/etc/ansible$ ansible --version
ansible [core 2.12.10]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0]
jinja version = 2.10.1
libyaml = True
user#ansible:/etc/ansible$ sudo nano hosts
[windows_host]
windows_host.MYDOMAIN.LOCAL
[windows_host:vars]
ansible_user=windows_user#MYDOMAIN.LOCAL
ansible_password= {{ password }}
ansible_connection=winrm
ansible_port=5985
ansible_winrm_transport=kerberos
ansible_winrm_server_cert_validation=ignore
ansible_winrm_read_timeout_sec: 60
ansible_winrm_operation_timeout_sec: 58
Any advice?
EDIT: This is the content of the PowerShell script:
$userName="user"
$File="C:\Path\To\User\user.txt"
$hyperv_host=$args[0]
$partition=$args[1]
$host_name=$args[2]
$credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "$userName", (Get-Content $File | ConvertTo-SecureString)
$PSDefaultParameterValues = #{'Invoke-Command:ConfigurationName'='remote_host' }
$nas_location = "Microsoft.PowerShell.Core\FileSystem::\\path\in\NAS\location\VHD\sysprep.vhdx"
Invoke-Command -Credential $credentials -ScriptBlock {
(New-Item -Verbose "$using:partition\$using:host_name" -type directory)
(Copy-Item -Verbose -Path "$using:nas_location" -Destination "$using:partition\$using:host_name")
(Write-Host "VHD successfully copied from \\NAS\")
(Rename-Item -Verbose -Path "$using:partition\$using:host_name\sysprep.vhdx" -NewName "$using:host_name.vhdx")
(New-VM -Verbose -Name "$using:host_name" -MemoryStartupBytes 16GB -Generation 2 -Path "$using:partition\$using:host_name" -BootDevice VHD -VHDPath "$using:partition\$using:host_name\$using:host_name.vhdx")
(Set-VMProcessor -Verbose "$using:host_name" -Count 4)
} -ComputerName $hyperv_host
And this is how I execute it:
powershell.exe -ExecutionPolicy ByPass -File C:/Path/To/Script/Script.ps1 hypervhost.mylocal.domain F: dev-vm

Related

Ansible win_shell printing wrong output

Ansible win_shell/win_command prints logo output instead of actual output of the command:
- name: get Ps1 files
win_shell: get-ChildItem -path $testFolder -Filter *.ps1 -Recurse -File -Name -Depth 0
register: ps1_files
args:
executable: powershell
Should print a list of *.ps1 folders but instead prints wrong output (command works when running directly on powershell on the server):
"msg": {
2022-12-22T02:30:46.455812-0500 info: "changed": true,
2022-12-22T02:30:46.455867-0500 info: "cmd": "get-ChildItem -path $realProcessesFolder -Filter *.ps1 -Recurse -File -Name -Depth 0",
2022-12-22T02:30:46.455917-0500 info: "delta": "0:00:00.954839",
2022-12-22T02:30:46.455969-0500 info: "end": "2022-12-22 07:30:46.385668",
2022-12-22T02:30:46.456017-0500 info: "failed": false,
2022-12-22T02:30:46.456065-0500 info: "rc": 0,
2022-12-22T02:30:46.456115-0500 info: "start": "2022-12-22 07:30:45.430828",
2022-12-22T02:30:46.456165-0500 info: "stderr": "",
2022-12-22T02:30:46.456237-0500 info: "stderr_lines": [],
2022-12-22T02:30:46.456289-0500 info: "stdout": "\r\n\r\nComputerName : SL143312\r\nBuilddate : 2019-Aug-26 13:43:8\r\nProfile : Standard Application Server\r\nOS : Windows Server 2016 Standard Edition\r\nMachineType : VMware Virtual Platform\r\nModel : VMware, Inc.\r\nServerAppCode : TVP0\r\n\r\n\r\n\r\n",
2022-12-22T02:30:46.456343-0500 info: "stdout_lines": [
2022-12-22T02:30:46.456393-0500 info: "",
2022-12-22T02:30:46.456445-0500 info: "",
2022-12-22T02:30:46.456504-0500 info: "ComputerName : SL143312",
2022-12-22T02:30:46.456556-0500 info: "Builddate : 2019-Aug-26 13:43:8",
2022-12-22T02:30:46.456615-0500 info: "Profile : Standard Application Server",
2022-12-22T02:30:46.456663-0500 info: "OS : Windows Server 2016 Standard Edition",
2022-12-22T02:30:46.456718-0500 info: "MachineType : VMware Virtual Platform",
2022-12-22T02:30:46.456767-0500 info: "Model : VMware, Inc.",
2022-12-22T02:30:46.456816-0500 info: "ServerAppCode : TT00",
2022-12-22T02:30:46.456866-0500 info: "",
2022-12-22T02:30:46.456916-0500 info: "",
2022-12-22T02:30:46.456977-0500 info: ""
2022-12-22T02:30:46.457027-0500 info: ]
2022-12-22T02:30:46.457079-0500 info: }
This looks to me more like a logo.
I have used also the win_command module with nologo and came up with same result:
win_command: powershell -noninteractive -nologo -command "get-ChildItem -path $env:realProcessesFolder -Filter *.ps1 -Recurse -File -Name -Depth 0"
It would be great if you would have any suggestions.
Many thanks!

Ansible Playbook | Need to execute powershell script

I am wondering if someone can help. I am trying to find a way to run a powershell script within an ansible playbook.
I found a module that seems to allow it but I am unable to make it work.
https://docs.ansible.com/ansible/latest/collections/ansible/windows/win_powershell_module.html
The PS script that I need to run within the ansible playbook is the following:
# Step 1
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("X:", "\\fileserver", $true, $USER, $PASS)
Copy-Item "x:\*" -Destination c:\scripts -recurse -force
# Replace user and run installer
$GenericPath = "C:\pts\Install.bat"
$name = (Get-Content C:\pts\file.txt)
$pos = $name.IndexOf("#")
$User = $name.Substring(0, $pos)
#$Domain = $name.Substring($pos+1)
if ($name -match 'dom1.al.com')
{
$Domain = "al"
}
if ($name -match 'dom2.al.com')
{
$Domain = "al2"
}
if ($name -match 'dom3.al.com')
{
$Domain = "al3"
}
if ($name -match 'dom4.al.com')
{
$Domain = "al4"
}
$ReplaceUser = $Domain + '\' + $User
(Get-Content $GenericPath) | Foreach-Object {$_ -replace "ReplaceUser","$ReplaceUser"} | Set-Content $GenericPath
F:\pts\reconfigure.bat
Can someone please let me know how should the ansible playbook needs to look like in order to get this to work. The target VMs where the PS will be executed via ansible are Windows OS. I understand I can run PS directly on those servers but the execution for this workflow needs to happen from within an ansible playbook.
Thank you
Well, it worked with RHEL, so the same might work in Windoze. Try this:
---
- name: Run PowerShell script
hosts: all
become: no
gather_facts: no
tasks:
- win_shell: "{{ item }}"
with_file:
- my_kewel_powershell_script.ps
...

Running a powershell from rundeck(linux) display different result

I'm trying to run a powershell script from rundeck(linux), If I run the script locally[Deletes some files from multiple terminal servers](Windows server) it is working as expected however if I call it from rundeck server(winrm configured) it seems that the script cant access the remote folders I'm trying to access.
I tried running the script using the same user but still shows different result.
Script bellow:
$userAD = "someuser"
$servers = Get-Content C:\TSList.csv
$Folder = "c$\Users\$userAD\"
$TSFolderShare = "\\sharepath"
Write-Output "#####Start of script#####"
Write-output `n
Write-output "Checking if $userAD user profile exist in Terminal servers..."
sleep -seconds 1
foreach ($server in $servers) {
Test-Path "\\$server\$Folder" -PathType Any
Get-ChildItem "\\$server\$Folder"
if (Test-Path "\\$server\$Folder" -PathType Any) {
Write-output "Resetting user profile in $server.."
Get-ChildItem "\\$server\$Folder" -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
sleep -seconds 1
Write-output "Done."
if( (Get-ChildItem "\\$server\$Folder" | Measure-Object).Count -eq 0)
{
Write-output "Done."
}
}
else
{
Write-output "Resetting user profile in $server.."
sleep -seconds 1
Write-output "User profile does not exist in $server."
#Write-output "\\$server\$Folder does not exist in $server!" -ForegroundColor Red
}
}
EDIT: It seems my problem is when running my script from another script with RunAS.
Below I'm trying to access a folder from another server using ps script, but since I want to integrate this to Rundeck I need to call my ps script from my linux server using python. I did a test running the ps script directly and calling the test path script using another script with RunUs using the same user I used to run the script manually
Scenario 1
Running PS script via separate PS script with RunAS(my_account)
$username = "my_account"
$password = "my_password"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
Invoke-Command -FilePath "C:\testpath.ps1" -Credential $cred -Computer localhost
(C:\testpath.ps1) Content below:
Test-Path "\\server\c$\Users\myaccount\"
result:
Access is denied
+ CategoryInfo : PermissionDenied: (\server\c$\Users\myaccount:String) [Test-Path], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.TestPathCommand
+ PSComputerName : localhost
False
Scenario 2
Running C:\testpath.ps1 directly as my_account
Test-Path "\\server\c$\Users\myaccount\"
result:
True
I used session configuration in powershell to solve the issue. This way allows you to tie a credential to a PowerShell session configuration and reuse this configuration for all future connections.
https://4sysops.com/archives/solve-the-powershell-multi-hop-problem-without-using-credssp/
Thanks a lot!
You're facing a double-hop issue with Rundeck and Powershell, here the explanation. That's asked before, take a look a this, and here a good workaround. Also this to solve it.

Running command on freeSSHD server with WinSCP fails with "Your shell is probably incompatible with the application (BASH is recommended)"

I am using below script to Verify checksum of a remote file against a local file. The server I installed on my machine is freeSSHd.
When I tried to execute the below script using PowerShell ISE I get an error message saying:
Your shell is probably incompatible with the application (BASH is recommended)
I've granted shell access in the FreeSSHd Server User properties:
Script:
param (
# Use Generate URL function to obtain a value for -sessionUrl parameter.
$sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx#example.com/",
[Parameter(Mandatory = $True)]
$localPath,
[Parameter(Mandatory = $True)]
$remotePath,
[Switch]
$pause = $False
)
try
{
Write-Host $localPath -foregroundcolor Gray
# Calculate local file checksum
$localChecksum = ((CertUtil -hashfile $localPath SHA1)[1] -replace " ","")
# Write-Host "Local Checksum:"
Write-Host $localChecksum
# Load WinSCP .NET assembly
#Add-Type -Path (Join-Path $PSScriptRoot "WinSCPnet.dll")
[Reflection.Assembly]::LoadFrom("\\c:\Program Files (x86)\WinSCP\WinSCPnet.dll") | Out-Null
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.ParseUrl($sessionUrl)
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
Write-Host $remotePath -foregroundcolor Gray
# Calculate remote file checksum
$sha1Command = "bash sha1sum -b $remotePath | awk '{print `$1}'"
$result = $session.ExecuteCommand($sha1Command)
$result.Check()
$remoteChecksum = $result.Output;
#$remoteChecksum =
[System.BitConverter]::ToString($session.CalculateFileChecksum("sha-1", $remotePath))
# Write-Host "Remote Checksum:"
Write-Host $remoteChecksum
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
# Compare cheksums
if ($localChecksum -eq $remoteChecksum)
{
Write-Host
Write-Host "Match" -foregroundcolor "green"
$result = 0
}
else
{
Write-Host
Write-Host "Does NOT match" -foregroundcolor "red"
$result = 1
}
}
catch [Exception]
{
Write-Host $_.Exception.Message
$result = 1
}
# Pause if -pause switch was used
if ($pause)
{
Write-Host "Press any key to exit..."
[System.Console]::ReadKey() | Out-Null
}
exit $result
FreeSSHd server does not support any "bash". Its "shell" is Windows cmd.exe.
Your code cannot work. Windows cmd.exe is not compatible with WinSCP.
Moreover FreeSSHd is pretty buggy, do not use it.
You should use another Windows SSH server.
You can use Windows build of OpenSSH. It would allow you to execute a PowerShell script on the server to calculate the checksum.
If you install Windows Subsystem for Linux, you may even get the sha1sum (but I'm not sure).
You can use Cygwin, if you need to simulate *nix environment on Windows.
You can use Bitvise SSH Server for personal use for free. Its SFTP server supports checksum calculation on its own, so you would be able to use WinSCP Session.CalculateFileChecksum method directly.
There are lot of other options.

How to integrate registry edit script with exe execution with VBScript

I am trying to write script which should change the registry settings (WSUS server name) of remote servers. Once success script should execute exe and VBScript file stored on remote servers which installs patches on the server. below is my progress.
Change WSUS settings of the server. This is done, I am able to change WSUS server in registry on remote servers and get the result in a CSV file.
Once above step is successfull my below script should be able to execute mentioned command on remote servers, which is not happening currently.
Script:
#defined variables to use in script as below.##
$Computers = Get-Content "C:\serverlist.txt"
$Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
$property = "WUServer"
$value = "http://serverFQDN"
$results = foreach ($computer in $Computers) {
if (Test-Connection -ComputerName $computer -Count 1 -Quiet) {
try {
Set-ItemProperty -Path $path -Name $Property -Value $Value -ErrorAction 'Stop'
$status = "WSUS server has been set to http://serverFQDN"
foreach ($computer in $Computers) {
# below step is not getting executed on remote servers. I do not
# get any error but above script do not execute any command on
# remote servers.
foreach ($computer in $computers) {
Invoke-Command -ScriptBlock {
C:\test\Patcher > cscript.exe -nologo test_v1.03.vbs /anlyze:false /reboot:false | Out-Null
}
}
}
} catch {
$status = "Failed"
}
} else {
$status = "Server is not reachable, please check connection and try again"
}
New-Object -TypeName PSObject -Property #{
'Computer' = $computer
'Status' = $status
}
}
$results | Export-Csv -NoTypeInformation -Path "./out.csv"
This isn't valid syntax:
C:\test\Patcher > cscript.exe -nologo test_v1.03.vbs ...
The statement would (try to) run a command Patcher located in the directory C:\test and redirect its output to a file cscript.exe in the current working directory.
You probably want to change the working directory to C:\test\Patcher and run test_v1.03.vbs from that directory. To do that change the above line to this:
Set-Location 'C:\test\Patcher'
& cscript.exe //NoLogo test_v1.03.vbs /anlyze:false /reboot:false | Out-Null

Resources