Installing Windows Updates via PSWindowsUpdate - powershell

I am trying to remotely make a domain-computer install its windows updates. This sounds like it should be quite easy, but I've been working on this for over 7 hours now and can't get it to work. I know you can do this via a GPO, but that doesn't give me enough control over the interval. I want our servers to install them and reboot monthly - a GPO can only be used to install and reboot weekly. Since our production works 24/7 I absolutely don't want the servers to reboot outside of the few hours downtime per month I am allowed for maintenance!
I have found several tutorials like this that use the Module PSWindowsUpdate, but these tutorials use an older version of that Module. They use a Function called Invoke-WUInstall which doesn't exist in the newest version. I have tried downgrading the module, but the packagesource doesn't provide versions older than 2.0.0.0
Also the project page doesn't provide a documentation - no examples - neither does it have a discussion or bugtracker. There is a discussion on the page of the original author, but he stopped working on it 2 years ago when it was still the old version.
I tried using Invoke-Command instead of Invoke-WUInstall, but Windows doesn't seem to allow remote update installation like that. PSWindowsUpdate apparently circumvents this problem by running the command as a scheduled task on the target machine, so looking at the output of Get-Command -Module PSWindowsUpdate, I thought I might need to use Invoke-WUJob instead and wrote this code:
Import-Module -Name PSWindowsUpdate
Enable-PSRemoting -Force
ForEach ($hostname in $args) {
Write-Output "Processing $hostname"
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $hostname -Concatenate -Force
# Install PSWindowsUpdate on target machine
Invoke-Command -computername $hostname -ScriptBlock {
PackageManagement\Get-PackageProvider -Name NuGet -Force
inmo PSWindowsUpdate -Force
}
# Install the Updates
Invoke-WUJob -ComputerName $hostname -Script {
ipmo PSWindowsUpdate;
Install-WindowsUpdate -install -AcceptAll -IgnoreReboot
} -Confirm:$false -RunNow
}
I run this as a user who has administrative rights on the target machine and the output looks fine, but it didn't do anything.
Does anyone have experience with that module? how do you do this properly in versions >= 2?

Well, i already did something like this and also faced this same problem.
That was my solution:
Create a powershell file to execute your commands. Place all your commands to install the updates there.
Copy this file to the remote server.
You can do something like this:
copy myfile.ps1 \\myserver\c$\temp\myfile.ps1;
Run a remote script to create a registry inside the RunOnce, and the set value with a command to run your script:
Set-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce" -Name '!InstallUpdates' -Value "c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -File c:\temp\myfile.ps1"
Run another command remotelly to restart your server.
The server will reboot and then will execute your script locally.

Related

Powershell script to push installation via intune

I am trying to create an intunewin file to update dell command update on all computers (via MS endpoint manager).
Dell CU will not install itself, if the older version of the app is present on the pc. Or rather it will install, but it won't run.
Solution - To create a powershell script, that first uninstalls the older versions of dell CU, and only then installs the newest one.
The code:
Remove-Item -Path "C:\Program Files\Dell\CommandUpdate" -Recurse -Force -EA SilentlyContinue -Verbose
Remove-Item -Path "C:\Program Files (x86)\Dell\CommandUpdate" -Recurse -Force -EA SilentlyContinue -Verbose
./Dell-Command-Update-Windows-Universal-Application_601KT_WIN_4.5.0_A00_01.EXE
This works just fine, when run like this on my computer. Actually I run the cmd script:
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File .\script.ps1
Where script.ps1 is the first script above.
So I have 3 files in the folder - the ps1 script, the cmd command, and the EXE file itself. From these 3 I create the intunewin file.
When pushed via intune, the app does not install itself. I can see 'downloading' notification, but never receive installation notification, neither successful nor failed one.
Can this be related to intune settings itself? The detection method and install command are most likely correct and were working before, when I was just using the exe file for intunewin creation.
I have to change this, because Dell CU won't install itself if the older version is there - as mentioned in the first sentence.
I assume this might be related to the powershell code. Maybe intune does not understand
./Dell-Command-Update-Windows-Universal-Application_601KT_WIN_4.5.0_A00_01.EXE
anymore, when it is given intunewin file instead?
If that's the case, how can I modify my script to 'make sense in intune'?
Thank you in advance for all the advices

Running hyperV inside a windows docker container

I have a process which runs primarily with powershell and relies heavily on the hyperV pwsh module to build (at script runtime) and launch a hyper-v instance. This is to programmatically build a windows machine with specific features, updates, and applications, then capture an image of that machine for deployment to physical devices later.
We want to containerize this process so it can be run more dynamically than on a physical box like it is today.
Critical in this, is we need to be able to build and turn on a hyper-v instance inside the container. Currently experimenting on win 1803 with the dockerFile below.
# note it doesn't necessarily need to be this image, I just picked it because it was easy
FROM microsoft/powershell:nanoserver-1803 AS powershell
COPY ./mainContainer/ c:/app/
and then need pwsh like the lines below to work (primary issue is the lack of the hyperV pwsh module):
New-VHD -SizeBytes 100GB -Path $vhdPath
New-VM -Name $VmName -Generation 2 -Path "$TempDirectory\$VmName" -VHDPath $vhdPath -Switch $switchName
Set-VMMemory -VMName $VmName -StartupBytes 4096MB -DynamicMemoryEnabled $false
Add-VMScsiController -VMName $VmName
Add-VMDvdDrive -VMName $VmName -ControllerNumber 1 -ControllerLocation 0 -Path $WindowsIsoPath
Set-VMFirmware -VMName $VmName -FirstBootDevice $dvdDrive
Start-VM -VMName $VmName
$vm = Get-Vm $VMName
# then there's little loop waiting for the machine to turn off before continuing
I have tried Install-WindowsFeature and similar, but always get an error that:
"The term 'Install-WindowsFeature' is not recognized as the name of a cmdlet, function, script file, or operable program."
I have tried import-module servermanager, but that also gives "...not loaded because no valid module file was..."
It seems perhaps the main (current) hurdle may be to get a new module imported in pwsh (within the container) so I can enable the windows feature?
any advice?
update: I found part of the problem was it appears the nanoserver doesn't allow things like dism, so I've updated the dockerFile to:
FROM microsoft/powershell:windowsservercore-1803 AS powershell
COPY ./mainContainer/ c:/app/
RUN DISM /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V
but now I get an error:
The source files could not be found.
Use the "Source" option to specify the location of the files that are required to restore the feature. For more information on specifying a source location, see http://go.microsoft.com/fwlink/?LinkId=243077.
seems I need a different base image, not sure if there is one that can enable hyper-V

How to bypass security warning when running EXE from network location?

I am trying to write a complex unattended install script that installs from a network directory. I'm running PS in administrator mode with bypass security.
When I run:
Start-Process "\\192.168.5.7\MSChart.exe" -ArgumentList "/q" -Wait
I get:
How can I bypass this without adding the network location as a trusted server? Ideally simply using PowerShell. I've tried Unblock-File, no luck.
The network share is not trusted by your computer, hence it warns you. You would have to add the share to the trusted zone in the systems internet settings, and allow "launching programs and unsafe files".
You cannot bypass it, but
add the required configuration to the registry
or copy the files locally and run it from there
using PowerShell
You can bypass the warning by adding -NoNewWindow as in Start-Process "\\192.168.5.7\MSChart.exe" -ArgumentList "/q" -Wait -NoNewWindow.
You should however leverage DNS for your path (e.g. \\share.domain.com\file.exe) and ensure the URI (share.domain.com) is in your system 'Trusted Sites' or 'Intranet Sites' list or you may still be blocked. Copying the file to the local system first may also fix the problem.
Reference: https://social.technet.microsoft.com/Forums/en-US/92eab96d-fe1a-4119-a5bc-f171d517466a/getting-open-file-security-warning-using-startprocess?forum=winserverpowershell
Maybe you want to Unblock-File and accept all of the risks that come with that and then try to execute it?
I don't recommend anyone EVER run a script like this:
function Unblock-Dir()
{
gci -Directory | % {
push-location $_ ;
gci | % {
Write-Host "Unblocking $_";
Unblock-File $_
}
Unblock-Dir ;
Pop-Location
}
Unblock-File -path .\*
}
It's just too dangerous.

PSexec vs Built-in Windows

So, I'm writing tools in PowerShell to execute files on remote computers. I was initially using PSexec but switched them to .net framework using win32_process. When I ran an install file on the remote machine using win32_process, it failed. And after trying gwmi win32_process on the remote machine, that failed. So accessing the wmi objects is probably the problem. Anyway! I ended up using PSexec and it succeeded, and i verified that it did. But, that got me thinking about how PSexec connects to the remote machine, and I was wondering if anyone on here knew either how I could look at PSexec source code or if someone flat out knew how it connects and executes.
I couldn't find anything on it online, just a bunch of articles about what it can do. Maybe I just suck at researching though.
I have done this using the Invoke-WmiMethod cmdlet against remote machines. You need to include any switches in your executable path but the below code sample should get you there assuming you have appropriate permissions on the local / remote hosts.
See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1 for more details on the cmdlet.
#local path on the remote machine that will be run including any switches needed
$exePath = "c:\mypath\myfile.exe -s -norestart"
# Use FQDN or IP if netbios name is not reachable
$server = "myserver"
try {
Invoke-WmiMethod -ComputerName $server -Class win32_process -Name create -ArgumentList $exePath -ErrorAction Stop | Out-Null
}
catch {
Write-Host "Failed to execute program on $server. Error Details: $_.Exception.Message" -ForegroundColor Red
}
I can't speak to how PSExec works for you to compare but this method has worked for me in the past executing applications on remote hosts using only native PowerShell.

Can't find the Connect-ServiceFabricCluster cmdlet when using Powershell

I'm trying to follow this article about deploying a service fabric app through powershell, but I have an issue with running the Connect-ServiceFabricCluster cmdlet. I get the following:
Connect-ServiceFabricCluster : The term 'Connect-ServiceFabricCluster' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name,
or if a path was included, verify that the path is correct and try again.
At line:1 char:2
+ Connect-ServiceFabricCluster
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Connect-ServiceFabricCluster:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Following other articles on the internet, I've tried importing the following things:
Import-Module "$ENV:ProgramW6432\Microsoft SDKs\Service Fabric\Tools\PSModule\ServiceFabricSDK\ServiceFabricSDK.psm1"
Import-Module "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ServiceFabric"
I also saw somewhere to try and set execution policy before importing modules, so I tried this:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force -Scope CurrentUser
In the Modules section of the Powershell ISE I see the ServiceFabricSDK module, but I don't see this cmdlet.
How do I get access to these cmdlets?
Thank you for any help.
Current versions:
Running $PSVersionTable.PSVersion, I get
Major Minor Build Revision
----- ----- ----- --------
4 0 -1 -1
Service Fabric SDK is version 2.5.216
You should make sure you are running the Windows Powershell as opposed to just Powershell. This made a difference for me.
Are you running x86 version of Powershell ISE? I got this error as well but when I switched to the other ISE the cmdlet was available again.
First, I would set your policy to bypass. This can't be done from the script itself, because, well, that's what needs to run with this policy. You could look into setting your powershell ise profile to do this for you.
Set-ExecutionPolicy Bypass
To your question. Not all modules can use the Import-Module feature. For instance, modules from the technet.microsoft.com site must sometimes be manually installed and unzipped. I'm including a script I use below to do this automatically.
#https://www.petri.com/manage-windows-updates-with-powershell-module\
$url = "https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc/file/41459/47/PSWindowsUpdate.zip"
$module = "PSWindowsUpdate"
$zipped = "$($PSScriptRoot)\$($module).zip"
$unzipped = "C:\Windows\System32\WindowsPowerShell\v1.0\Modules"
#$unzipped = "$PSScriptRoot\$($module)"
if (Get-Module -Name $($module)) {
Write-Host "Module exists $($module)"
} else {
Write-Host "Getting Module $($module)"
if(!(Test-Path $zipped)){
(New-Object System.Net.WebClient).DownloadFile($url, $zipped)
if($?){Write-Output "Downloaded zip $($zipped)"}
}else{
Write-Output "Zip found $($zipped)"
}
if(!(test-path "$($unzipped)\$($module)")){
Add-Type -assembly “system.io.compression.filesystem”
[io.compression.zipfile]::ExtractToDirectory($zipped, $unzipped)
if($?){Write-Output "Unzipped to $($unzipped)"}
}
Unblock-File -Path "$($unzipped)\$($module)" -Confirm
if($?){Write-Output "Unblocked file $($unzipped)"}
Import-Module $unzipped\*\$($module).psd1 -Verbose
if($?){Write-Output "Imported module $($unzipped)"}
}
I was too hasty in my first answer. (which is weird, cuz it took awhile to type...) anyhow. It looks like the install process actually unpacks the psm1 for you.
Be sure you are running as admin, use this to check.
([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
[Security.Principal.WindowsBuiltInRole] “Administrator”)
Make sure the file name you made in step 3 matches the path in step 6.
When you run the import module command, follow that up with $?. This will tell you if it imported correctly. You can also use these commands to see if it worked.
get-command -name "Cluster"; get-module
I have just experienced the same problem on my Win10 box,
when cmdlets were not recognized as valid and downloading/installing relevant modules that contained those cmdlets didn't work.
The only solution that worked for me was as follows:
Go to the Control Panel -> "Programs and Features"
Uninstall Service Fabric SDK
click "Turn Windows features on or off" link and uninstall PowerShell
Next, reboot the Windows
Go back to the Control Panel -> "Programs and Features" -> "Turn Windows features on or off"
And install PowerShell
After which download/install Service Fabric SDK
Once again, restart your PC, start the Service Fabric Cluster Manager (if it doesn't auto-start), then right-click its icon on the task-bar and try creating 1-node or 5-node cluster again. In my case, it took less than a minute.