简体   繁体   中英

Windows Update API CopyToCache(IStringCollection) - Specified cast is not valid

For reducing traffic on our VPN routes, I need to download the windows updates from an external server while reporting to our internal server.

So I'm doing the following:

Create an UpdateSession and Search for Updates, storing them in $SearchResult. Then I download the Updates from an external Server and then I want to pass them into the Windows Update Api via IUpdate2.CopyToCache(IStringCollection)

Everything is just fine, except passing the StringCollection into the Method CopyToCache and it just ends up with an 'Specified cast is not valid.'-Error.

This is my code:

Thank's for help! eldo-ob

$UpdateSession = New-Object -ComObject Microsoft.Update.Session
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
$UpdateCollection = New-Object -Com Microsoft.Update.UpdateColl

$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'")
$AvailibleUpdates = [int16]$SearchResult.Updates.Count

$AvailibleUpdates

$WebClient = New-Object System.Net.WebClient

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

@($SearchResult.Updates.Item(0).BundledUpdates) | Foreach { 
    $_.DownloadContents | Foreach { 
        $FileName = $_.DownloadUrl.Split("/")[-1]
        $downloadFrom = $_.DownloadUrl.Replace("http://contoso-intern.com","https://contoso-extern.com")
        $WebClient.DownloadFile($downloadFrom,("C:\temp\WSUS\{0}" -f $FileName))
        Write-Host "File Downloaded" -ForegroundColor Green
    }
    $StringCollection = New-Object System.Collections.Specialized.StringCollection
    $StringCollection.Add(("C:\temp\WSUS\{0}" -f $FileName))
    $_.CopyToCache($StringCollection)
}

Error Msg:

Specified cast is not valid.
At line:24 char:19
+ $_.CopyToCache($StringCollection)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], InvalidCastException
    + FullyQualifiedErrorId : System.InvalidCastException

Update / Solution:

# create UpdateSession
$UpdateSession = New-Object -ComObject Microsoft.Update.Session
# create UpdateSearcher
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()

# search for updates & count updates
$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'")
$AvailibleUpdates = [int16]$SearchResult.Updates.Count

# create an WebClient instance for downloading Updates from alternative source
$WebClient = New-Object System.Net.WebClient

# fix some tls issues (not for everyone neccessary) 
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# iterate the updates in searchresult
$SearchResult.Updates | ForEach-Object {
    # iterate bundledupdates
    $_.BundledUpdates | ForEach-Object {
        # create COM stringcollection
        $StringCollection = New-Object -ComObject "Microsoft.Update.StringColl.1"
        # iterate downloadcontents
        $_.DownloadContents | ForEach-Object { 
            # get the filename from url
            $FileName = $_.DownloadUrl.Split("/")[-1]
            # create external downloadlink
            $downloadFrom = $_.DownloadUrl.Replace("http://contoso-intern.com","https://contoso-extern.com/wsusreplica")
            # download update with webclient
            $WebClient.DownloadFile($downloadFrom,("C:\temp\WSUS\{0}" -f $FileName))
            # adding downloaded filepath to stringcollection
            $StringCollection.Add(("C:\temp\WSUS\{0}" -f $FileName))
        }
        # copy downloaded file to cache (load into wuapi)
        $_.CopyToCache($StringCollection)
    }
}

# create installer
$Installer = $UpdateSession.CreateUpdateInstaller()
# set the updates
$Installer.Updates = $SearchResult.Updates
# and install
$Installer.Install()

The updates where successfuly installed without using the UpdateDownloader from a self choosen location. So now I'm able to report and search updates through the vpn-tunnel and download the updates from an external source, where we can route the traffic beside the vpn tunnel.

You are using a .NET object. After searching the registry for the interface, then looking up the TypeLib for the interface, it pointed to the wuapi.dll. I then searched for COM objects that use wuapi.dll as their InprocServer32. I found "Microsoft.Update.StringColl.1". It has an Add() method, so it should work the same in the code as your other method (I think). So, replace where you initialize the $StringCollection with this:

$StringCollection = new-object -ComObject "Microsoft.Update.StringColl.1"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM