Install windows update - powershell

I have following powershell script which should update my windows OS everytime I run it. Therefore I use the given windows API in order to search, download and install the updates. But somehow only searching for them actually works.
This is my script:
$global:scriptpath = $MyInvocation.MyCommand.Path
$global:dir = Split-Path $scriptpath
$global:logfile = "$dir\updatelog.txt"
write-host " Searching for updates..."
$session = New-Object -ComObject Microsoft.Update.Session
$searcher = $session.CreateUpdateSearcher()
$result = $searcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
if ($result.Updates.Count -eq 0) {
Write-Host "No updates to install"
} else {
$result.Updates | Select Title
}
$downloads = New-Object -ComObject Microsoft.Update.UpdateColl
foreach ($update in $result){
try {
$update.AcceptEula()
$Null = $downloads.Add($update)
} catch {}
}
$count = $result.Updates.Count
write-host ""
write-host "There are $($count) updates available."
write-host ""
read-host "Press Enter to download\install updates"
$downloader = $session.CreateUpdateDownLoader()
$downloader.Updates = $downloads
$downloader.Download()
$installs = New-Object -ComObject Microsoft.Update.UpdateColl
foreach ($update in $result.Updates){
if ($update.IsDownloaded){
$installs.Add($update)
}
}
$installer = $session.CreateUpdateInstaller()
$installer.Updates = $installs
$installresult = $installer.Install()
$installresult
But I get following error:
Exception calling "Download" with "0" argument(s): "Exception from HRESULT: 0x80240024"
+ $downloader.Download()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
Somehow this line: $downloader.Updates = $downloads is not executed, but I don't know why. I also already tried running the script as an admin, didn't work either.

That error code is the WU_E_NO_UPDATE, described here. Basically it says that the Updates collection is not set or empty.

Related

Failing to install audio driver script using microsoft update as source on dell

I am trying to run below code to install realtek audio driver on dell laptop but getting below error. Is it possible to use this script for all model laptop to install missing audio driver or update it? Any help would be greatly appreciated
ERROR:
RegistrationState ServiceID IsPendingRegistrationWithAU Service
----------------- --------- --------------------------- -------
3 7971f918-a847-4430-9279-4a52d1efe18d False System.__ComObject
Exception from HRESULT: 0x80240024
+ $Downloader.Download()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
Installing Drivers...
Exception from HRESULT: 0x80240024
+ $InstallationResult = $Installer.Install()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
**CODE:**
$UpdateSvc = New-Object -ComObject Microsoft.Update.ServiceManager
$UpdateSvc.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"")
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$Searcher.ServiceID = '7971f918-a847-4430-9279-4a52d1efe18d'
$Searcher.SearchScope = 1 # MachineOnly
$Searcher.ServerSelection = 3 # Third Party
$Criteria = "IsInstalled=0 and Type='Driver'"
Write-Host('Searching Driver-Updates...') -Fore Green
$SearchResult = $Searcher.Search($Criteria)
$Updates = $SearchResult.Updates | Where-Object { $_.DriverManufacturer -like 'Realtek' }
#Show available Drivers...
$Updates | select Title, DriverModel, DriverVerDate, Driverclass, DriverManufacturer | fl
#Download the Drivers from Microsoft
$UpdatesToDownload = New-Object -Com Microsoft.Update.UpdateColl
$updates | % { $UpdatesToDownload.Add($_) | out-null }
Write-Host('Downloading Drivers...') -Fore Green
$UpdateSession = New-Object -Com Microsoft.Update.Session
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdatesToDownload
$Downloader.Download()
#Check if the Drivers are all downloaded and trigger the Installation
$UpdatesToInstall = New-Object -Com Microsoft.Update.UpdateColl
$updates | % { if($_.IsDownloaded) { $UpdatesToInstall.Add($_) | out-null } }
Write-Host('Installing Drivers...') -Fore Green
$Installer = $UpdateSession.CreateUpdateInstaller()
$Installer.Updates = $UpdatesToInstall
$InstallationResult = $Installer.Install()
if($InstallationResult.RebootRequired) {
Write-Host('Reboot required! please reboot now..') -Fore Red
} else { Write-Host('Done..') -Fore Green } ```
There are a couple of things I would change in your code.
For one thing, I think you are (unnecessarily) creating a new Microsoft.Update.UpdateColl object twice. Then you are not checking if there actually are updates to install, at which point the code should exit.
The test for the driver manufacturer in your code is -like 'Realtek', but without wildcard characters (*) surrounding it, this is the same as -eq 'Realtek' and because of that you might miss a couple.
# check if the Windows Update service is running
if ((Get-Service -Name wuauserv).Status -ne "Running") {
Set-Service -Name wuauserv -StartupType Automatic
Start-Service -Name wuauserv
}
# check if there are updates available
$UpdateSession = New-Object -Com Microsoft.Update.Session
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
Write-Host 'Searching Driver-Updates...' -ForegroundColor Green
$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Driver' and IsHidden=0")
# collect the updates
$UpdateCollection = New-Object -Com Microsoft.Update.UpdateColl
$Updates = for ($i = 0; $i -lt $SearchResult.Updates.Count; $i++) {
$Update = $SearchResult.Updates.Item($i)
# we are only interested in RealTek Audio driver updates
# if you need to add more manufacturers, change the first part in the 'if' to for instance
# $Update.DriverManufacturer -match 'Realtek|Conexant|Intel'
if ($Update.DriverManufacturer -like '*Realtek*' -and
($Update.Title -like '*audio*' -or $Update.Description -like '*audio*')) {
if (-not $Update.EulaAccepted) { $Update.AcceptEula() | Out-Null }
[void]$UpdateCollection.Add($Update)
# output a PsCustomObject for display purposes only
$Update | Select-Object Title, DriverModel, DriverVerDate, Driverclass, DriverManufacturer
}
}
# no updates found; exit the script
if ($null -eq $Updates -or $Updates.Count -eq 0) {
Write-Host 'No Driver-Updates available...' -ForegroundColor Cyan
}
else {
# Show available driver updates...
$Updates | Format-List
# download the updates
Write-Host 'Downloading driver updates...' -ForegroundColor Green
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdateCollection
$Downloader.Priority = 3 # high
[void]$Downloader.Download()
# install the updates
Write-Host 'Installing Drivers...' -ForegroundColor Green
$Installer = $UpdateSession.CreateUpdateInstaller()
# accept all Critical and Security bulletins.
$Installer.ForceQuiet = $true
$Installer.Updates = $UpdateCollection
$InstallationResult = $Installer.Install()
$ResultCode = $InstallationResult.ResultCode
# test if the computer needs rebooting
if ($InstallationResult.RebootRequired) {
Write-Host 'Reboot required! please reboot now..' -ForegroundColor Red
}
else {
Write-Host 'Done..' -ForegroundColor Green
}
}
# Clean-up COM objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateSession)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateSearcher)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateCollection)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($SearchResult)
if ($Downloader) { $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Downloader)}
if ($Installer) { $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Installer)}
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()

IE History Permissions for other users

I have a script which I think is most of the way to being able to grab IE history for all of the users on a machine. My problem is it doesn't work for users other than myself because I get a permissions error when attempting open the folder. Does anyone have any ideas how I can fix the permissions problem?
I'm running this script on a Windows 2012r2 machine and I am an administrator on the box.
Thanks!
function Get-History
{
param
(
[string]$userName
)
$shell = New-Object -ComObject Shell.Application
if($username)
{
$users = $username
}
else
{
$users = Get-ChildItem C:\Users
}
if((([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")))
{
Foreach($user in $users)
{
$user = Split-Path $user -leaf
try
{
$ErrorActionPreference = 'Stop'
$hist = $shell.NameSpace("C:\Users\$user\AppData\Local\Microsoft\Windows\History")
}
catch
{
continue
}
$folder = $hist.Self
#$folder.Path
if($hist){
$hist.Items() | foreach {
#""; ""; $_.Name
if ($_.IsFolder) {
$siteFolder = $_.GetFolder
$siteFolder.Items() | foreach {
$site = $_
#""; $site.Name
if ($site.IsFolder) {
$pageFolder = $site.GetFolder
$pageFolder.Items() | foreach {
$url = $pageFolder.GetDetailsOf($_,0)
$date = $pageFolder.GetDetailsOf($_,2)
#"$user`: $date visited $url"
#Write-Output ("$user,$date,`"$url`"" | ConvertFrom-Csv)
New-Object -TypeName PSObject -Property #{
user=$user;
date = $date;
url = $url
}
}
}
}
}
}
}
}
}
else
{
Write-Host "Not Admin"
}
}
If I run just the small snippet:
$shell = New-Object -ComObject Shell.Application
$hist = $shell.NameSpace("C:\Users\MyOwnUsername\AppData\Local\Microsoft\Windows\History")
Then I successfully assign the $hist variable as a System.__ComObject
But if I run:
$shell = New-Object -ComObject Shell.Application
$hist = $shell.NameSpace("C:\Users\SomeOtherUser\AppData\Local\Microsoft\Windows\History")
I get:
Exception calling "NameSpace" with "1" argument(s): "Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))"
At line:3 char:1
+ $hist = $shell.NameSpace("C:\Users\SomeOtherUser\AppData\Local\Microsoft\Windows\History ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
Full Disclosure: it's a slight modification of the script at this blog post
I never solved the permissions problem. I changed strategy to use BrowsingHistoryViewer by Nirsoft.
$execPath = "C:\BrowsingHistoryView.exe"
$computers = 'computer1','computer2','computer3','computer4'
$outPath = "c:\"
$computers |
ForEach-Object{ `
Start-Process $execPath `
-argumentList "/HistorySource 3",
"/HistorySourceFolder ""\\$_\c$\Users""",
"/scomma ""$outpath\history_$_.txt"""
}

Updating SharePoint User Profile Property with a Taxonomy Term

I'm experiencing a problem trying to update a SharePoint User Profile property that is linked to a taxonomy TermSet. The following code results in an exception.
$spsite = Get-SPSite $mysiteurl
$context = Get-SPServiceContext $mysiteurl
$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
if ($upm.UserExists($adAccount))
{
$user = $upm.GetUserProfile($adAccount)
$locationsCollection = $user[$propName]
$taxMgr = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($spsite)
$taxStore = $taxMgr.TermStores[0]
$officeLocationsGroup = $taxStore.Groups["Office Locations"]
$officeLocationsTermSet = $officeLocationsGroup.TermSets["Office Locations"]
$terms = $officeLocationsTermSet.GetTerms($newValue, $false)
$foundTerm = $false
$newTerm = $null
foreach ($term in $terms) {
Write-Host " Found: $($term.Name)" -BackgroundColor Yellow -ForegroundColor Black
$foundTerm = $true
$newTerm = $term
}
if (-not $foundTerm) {
$newTerm = $officeLocationsTermSet.CreateTerm($theTermValue, 1033)
$foundTerm = $true
Write-Host " Created: $($newTerm.Name)" -BackgroundColor DarkGreen -ForegroundColor Black
$taxStore.CommitAll()
}
Write-Host "Adding the term..."
$locationsCollection.AddTaxonomyTerm($newTerm)
Write-Host "Term added."
$user.Commit()
Write-Host "Profile Committed."
}
The call to AddTaxonomyTerm triggers this exception:
Exception calling "AddTaxonomyTerm" with "1" argument(s): "Index was out of ran
ge. Must be non-negative and less than the size of the collection.
Parameter name: index"
At E:\mark\updateUserProfile.ps1:41 char:41
+ $locationsCollection.AddTaxonomyTerm <<<< ($newTerm)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Any thoughts on why this would occur would be of great help. Thanks.
It seems that you can't use the AddTaxonomyTerm method on empty fields. You need to "initialize" the taxonomy field first. Use the .Value method first, then the AddTaxonomyTerm method.
$locationsCollection.Value = $newTerm.Name;
$locationsCollection.AddTaxonomyTerm($newTerm)

PowerShell Exception calling "Start" with "0" argument(s) from within another function

I am writing my first Powershell script and coming from C# am confused, my code is below:
function Run(
[string] $command,
[string] $args,
[Ref] [string] $stdout,
[Ref] [string] $stderr
)
{
$p1 = New-Object System.Diagnostics.Process
$p1.StartInfo = New-Object System.Diagnostics.ProcessStartInfo;
$p1.StartInfo.FileName = $command
$p1.StartInfo.Arguments = $arguments
$p1.StartInfo.CreateNoWindow = $true
$p1.StartInfo.RedirectStandardError = $true
$p1.StartInfo.RedirectStandardOutput = $true
$p1.StartInfo.UseShellExecute = $false
$p1.Start()
$p1.WaitForExit()
}
$p = New-Object System.Diagnostics.Process
$p.StartInfo = New-Object System.Diagnostics.ProcessStartInfo;
$p.StartInfo.FileName = "ping"
$p.StartInfo.Arguments = "142.553.22242.2"
$p.StartInfo.CreateNoWindow = $true
$p.StartInfo.RedirectStandardError = $true
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.UseShellExecute = $false
$p.Start()
$p.WaitForExit()
$code = $p.ExitCode
$stderr = $p.StandardError.ReadToEnd()
$stdout = $p.StandardOutput.ReadToEnd()
Run("ping","208.67.222.222","","")
The $p.Start() works, but for some reason the parameters passed in to the Run function are ignored and $p1 fails. What am I doing wrong please?
Exception calling "Start" with "0" argument(s): "The system cannot find the file specified"
At C:\Users\Administrator\Desktop\logtofile.ps1:27 char:5
+ $p1.Start()
+ ~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : Win32Exception
Exception calling "WaitForExit" with "0" argument(s): "No process is associated with this object."
At C:\Users\Administrator\Desktop\logtofile.ps1:28 char:5
+ $p1.WaitForExit()
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException
You have to call run as follows:
Run "ping","208.67.222.222","",""
putting in between the parentheses passes it to the function as a single array argument.
I wasn't trying to start a process from inside a function, but I was getting the same error. It took me a few minutes to realize that it was one of my favorite time-wasters: a UAC trap. I hadn't started PowerShell using "Run as administrator". You have to have admin privileges and run the code as such to start/stop/modify processes that you don't own and this error message is totally unhelpful in this regard.
function Demo {
param (
$fileName,$Arguments
)
$p = New-Object System.Diagnostics.Process
$p.StartInfo = New-Object System.Diagnostics.ProcessStartInfo
$p.StartInfo.FileName = $fileName
$p.StartInfo.RedirectStandardError = $true
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.UseShellExecute = $false
$p.StartInfo.Arguments = $Arguments
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
Write-Host "exit code: " + $p.ExitCode
}
Demo "getmac" " /v"
I got this error with the start() function on a service because a colleague set the service to "disabled" in the Windows Services window. Setting it back to "Manual" fixed it.

Need help figuring out why Powershell is throwing error 16

I posted this script the other day in an effort to discover a good way to change file extensions when "saving as." I had the problem licked, but as of this morning, the script will not run without errors. Here's the error message I'm getting:
Processing : C:\users\xxx\Desktop\ht\Automatic_Post-Call_Survey.htm
Exception calling "SaveAs" with "16" argument(s): "This is not a valid file name.
Try one or more of the following:
* Check the path to make sure it was typed correctly.
* Select a file from the list of files and folders."
At C:\users\xxx\Desktop\hd.ps1:11 char:20
+ $opendoc.saveas <<<< ([ref]"$docpath\$doc.FullName.doc", [ref]$saveFormat);
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
if "16" is the error code, that represents an inability to delete the directory...but it doesn't appear as if I'm asking for that at all--unless there's some default parameter in place somewhere. I'm pretty much baffled.anyone have any other ideas I can try out?
$docpath = "c:\users\xxx\desktop\do"
$htmPath = "c:\users\xxx\desktop\ht"
$srcfiles = Get-ChildItem $htmPath -filter "*.htm*"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument");
$word = new-object -comobject word.application
$word.Visible = $False
$filename = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
function saveas-document {
$opendoc = $word.documents.open($doc.FullName);
$opendoc.saveas([ref]"$docpath\$filename", [ref]$saveFormat);
$opendoc.close();
}
ForEach ($doc in $srcfiles) {
Write-Host "Processing :" $doc.FullName
saveas-document
$doc = $null
}
$word.quit();
this should do what do you need, but is not the best design :)
$docpath = "c:\users\xxx\desktop\do"
$htmPath = "c:\users\xxx\desktop\ht"
$srcfiles = Get-ChildItem $htmPath -filter "*.htm*"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument");
$global:word = new-object -comobject word.application
$word.Visible = $False
#$filename = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
function saveas-document ($docs) {
$opendoc = $word.documents.open($docs);
$savepath = $docs -replace [regex]::escape($htmPath),"$docpath"
$savepath = $savepath -replace '\.html*', '.doc'
$opendoc.saveas([ref]"$savepath", [ref]$saveFormat);
$opendoc.close();
}
ForEach ($doc in $srcfiles) {
Write-Host "Processing :" $doc.FullName
saveas-document -doc $doc.FullName
$doc = $null
}
$word.quit();