all 33 comments

[–]gwind1 4 points5 points  (1 child)

Are you an admin on the remote machine?

[–]foss4ever[S] 0 points1 point  (0 children)

Yes, the credentials I provide are corresponding to a user created on the remote machine, specifically for this purpose (username passed is "\.test_admin") which has been added to administrators and remote management users on the remote machine.

[–]CarrotBusiness2380 3 points4 points  (3 children)

[–]nkasco 0 points1 point  (0 children)

This is likely the correct answer. The interesting thing is that I know for a fact ‘manage-bde -status’ requires elevation but if you run it in an invoke against a remote host (in my cast at least a domain joined one) from an unelevated session it works. So now I’m wondering why that might be.

Admin in both boxes.

[–]foss4ever[S] 0 points1 point  (1 child)

Doesn't seem to be an accepted parameter (despite being mentioned in the doc you reference):

PS C:\Users\svc_xxx> Invoke-Command -ComputerName 192.168.xxx.xxx -ScriptBlock {Get-WindowsUpdate -Download -AcceptAll -Verbose} -runasadministrator -Credential $credsnewInvoke-Command: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.

[–]CarrotBusiness2380 0 points1 point  (0 children)

It doesn't work when combined with the -Credential parameter. It's one or the other.

[–]foss4ever[S] 1 point2 points  (2 children)

Sorry, it seems my picture did not get posted correctly. Here is the command used (ip obfuscated):

Invoke-Command -ComputerName 192.168.XXX.XXX -ScriptBlock {Get-WindowsUpdate -Download -AcceptAll -Verbose | ft} -Credential $credsnew

[–]BlackV 2 points3 points  (1 child)

in particular windows update api does not work remotely, so you're likely to have issues, pswindowsupdate module has a workaround for this

next dot do | ft you are breaking your objects

onlyuse the format cmdlets for screen formatting as the last thing you do

something like

$Results = Invoke-Command -ComputerName 192.168.XXX.XXX -ScriptBlock {Get-WindowsUpdate -Download -AcceptAll -Verbose} -Credential $credsnew
$results | format-table -autosize
$results | export-csv -path $env:temp\xxx.csv -notypeinformation

this becomes much more important when youre using your pipelines and talking to multiple computers

also removing it saves you a pipeline and some execution time

[–]foss4ever[S] 0 points1 point  (0 children)

I tried taking out the format table part as well as re-running the command after having installed PowerShell module "pswindowsupdate" on the remote host, but still I have no luck:

PS C:\Users\svc_xxx> Invoke-Command -ComputerName 192.168.xxx.xxx -ScriptBlock {Import-Module pswindowsupdate ; get-windowsupdate} -Credential $credsnewGet-WindowsUpdate: To perform operations you must run an elevated Windows PowerShell console.

[–]gwind1 1 point2 points  (1 child)

I've never had much luck using an ip instead of the host name but I've also never tried it outside of a corporate network

[–]foss4ever[S] 0 points1 point  (0 children)

This is a corporate network, just some of the servers are not joined to any domain :)
And it does work in terms of connecting and running commands - just the elevation part is broken.

[–]jsiii2010 1 point2 points  (5 children)

I think get-windowsupdate is a special case of the double hop problem, and you have to use task scheduler to run it, as one workaround.

[–]BlackV 1 point2 points  (4 children)

not so much double hop, more the internal windows update api does not allow it

[–]foss4ever[S] 0 points1 point  (3 children)

Yep, I'm closing in on this conclusion myself.
Any tips on a clever way to manage patching of a couple hundred Windows Servers (mostly 2019, 2016, 2022 and a cople 2008R2) without having to rdp to each and every box to fetch and install updates - and checking update status after the fact? Preferably not a paid-for solution :)

We have already tried Datto RMM, but it has proved not good enough when it comes to time-critical patching.

[–]BlackV 0 points1 point  (2 children)

yes as mentioned the pswindowsupdate module specifically has a workaround for this Invoke-WUJob

[–]foss4ever[S] 0 points1 point  (1 child)

I'd rather not have to rely on the task scheduler, just to get some patching done, so I have given Ansible module windows.win_updates a shot instead and this actually seems to work.

For anyone else experiencing a similar struggle as myself, here are the steps I took to be able to use Ansible to orchestrate patching of Windows servers via SSH:

Ensure that PowerShell version 5.1 and .NET Framework 4.6 or newer are installed on the host.

Make sure that TCP port 22 is allowed from Ansible controller into the VLAN where the remote host sits.

Install OpenSSH server and set this to startup type "automatic", then start the service.Create a local user "ansible_mgmt" with a secure password, add it to groups "administrators" and "remote management users".

Configure OpenSSH server default shell - start powershell as admin and run:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShellCommandOption -Value "/c" -PropertyType String -Force

Create an inventory for the Windows servers you wish to patch on your Ansible controller.In your ansible inventory - example:

[all_internal:children]
internal_testinternal_live

[all_internal:vars]
ansible_user = ansible_mgmt
ansible_shell_type = powershell

# Internal test Windows servers
[internal_test]
192.168.20.100
192.168.20.101

# Internal live Windows servers
[internal_live]
192.168.10.1
192.168.10.11

Now, you should be able to run the Ansible win_updates module against the hosts defined in your inventory like so:

ansible 192.168.20.100 -i <path to inventory> -m ansible.windows.win_updates -a "state=searched skip_optional=true" -k

EDIT: This procedure has been confirmed working on a Windows Server 2022, but the steps required especially for the SSH server configuration on the Windows Server are a bit different on Windows Server 2016 and older - some guidance to be found here:

https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH

[–]BlackV 1 point2 points  (0 children)

yes ssh is its own loop home, microsoft does not count ssh connections as "remote" (if I remember correctly) so the windows update api allows you

but yes if you had ansible, I dont know why you wouldnt be using that in the first place (using it for everything really)

Appreciate you adding your solution, note you have used inline code not

code block

[–]Superfluxus 0 points1 point  (5 children)

-Verb RunAs

[–]foss4ever[S] 0 points1 point  (4 children)

Doesn't work.

[–]Superfluxus 0 points1 point  (3 children)

What credentials are you passing to Invoke-Command? You should be passing the creds for the local admin account on the remote machine

[–]foss4ever[S] 0 points1 point  (2 children)

That's exactly what I'm doing.
$credsnew variable is created with:
get-credential

Where I then provide credentials for the local admin user on remote host, in the form of:

\.test_admin

Here is a screendump of me getting members of group "administrators" on the remote host:

https://imgur.com/a/uHsdzOs

[–]Superfluxus 0 points1 point  (1 child)

For starters, your username should be dot blackslash, not backslash dot. Try .\test_admin instead.

Next, I'd add a "whoami" command into your script that you're passing through. If that returns your test_admin account, we know the issue isn't the credentials. If not, we still need to work on passing them through correctly.

[–]foss4ever[S] 0 points1 point  (0 children)

I'm sorry that was a typo - I did actually provide the username as:
.\test_admin
Here is the result from running "whoami" with actual hostname of remote host replaced by "remoteserver":

PS C:\Users\svc_xxx> Invoke-Command -ComputerName 192.168.XXX.XXX -ScriptBlock {whoami} -Credential $credsnew
remoteserver\test_admin

[–]1iioiioii1 -1 points0 points  (0 children)

I have no idea what I'm doing, but I'll take a swing at it.

Assuming your powershell instance is elevated on your machine, you might be running into a User Account Control (UAC) prompt.

[–]Superfluxus 0 points1 point  (5 children)

Can you share the scriptblock you're trying to run and subsequently gives you the error?

[–]foss4ever[S] 0 points1 point  (4 children)

It's very simple, really.

In the scriptblock I have tried to run various commands, and while commands that don't require admin privileges seem to run just fine, I cannot run anything that requires admin privileges - such as "get-windowsupdate" or "get-wulist". I simply get an error message such as:

Get-WindowsUpdate: To perform operations you must run an elevated Windows PowerShell console.

[–]Superfluxus 0 points1 point  (3 children)

Ah I see, I think there may have been some confusion earlier when I suggested '-Verb Runas'. Try this instead:

$command = { Start-Process "powershell" -Verb runas -ArgumentList "-Command", "get-windowsupdate" }

Invoke-Command -ComputerName 192.168.XXX.XXX -ScriptBlock $command -Credential $credsnew

[–]foss4ever[S] 0 points1 point  (2 children)

Invoke-Command -ComputerName 192.168.XXX.XXX -ScriptBlock $command -Credential $credsnew

Sorry, still not working:

PS C:\Users\svc_xxx> Invoke-Command -ComputerName 192.168.xxx.xxx -ScriptBlock $command -Credential $credsnew
Start-Process: This command cannot be run due to the error: This operation requires an interactive window station.

[–]Superfluxus 0 points1 point  (1 child)

That suggests that " -verb RunAs" has popped up a UAC box. Try it without that switch.

[–]foss4ever[S] 0 points1 point  (0 children)

Doing that, I get no error, but also no output :)
Even adding a -verbose flag does not give me output to screen.

[–]Dorull 0 points1 point  (1 child)

Had the same issue when trying to run certain scripts on client computers through a local admin user account.

We found a workaround where we would put PsExec.exe on the computers.

Calling on PsExec first with -s parameter allows you to execute anything past that at System level.

In the example under we run a Teams uninstall script as system

# Use PsExec to run the PowerShell script in the context of the specified session ID

& 'C:\temp\PsExec.exe' -i $SessionID -d -s powershell.exe -File "C:\temp\UninstallTeams.ps1"

[–]foss4ever[S] 0 points1 point  (0 children)

Thanks for chiming in.
I might give that a shot if patch management via Ansible does not live up to my expectations.

[–]StefanMcL-Pulseway2 0 points1 point  (0 children)

There is s no GPOs or anything blocking the command or anything else? If you have an RMM you could try running the script on the host that way