I'm writing a script that will take a list of server names and return the list of pending Windows updates. I'd like the script to accept input from Get-ADComputer, Get-Content (of a text file with server names), or from the command line.
Right now, I can pass in multiple names from the command line (.\scriptName.ps1 -DNSHostName server1,server2) and get the correct output. With Get-ADComputer, the script works when I'm only passing in one server (Get-ADComputer -filter * | where {$_.name -eq "memwinexch*"} | .\scriptName.ps1). If I try to get multiple servers, I only get updates for one, and I can't tell which, because the $computer variable is blank. Finally, if I use Get-Content, the script only returns updates for the last computer in the list.
How do I sort this out? Thanks.
<#
.Synopsis
Get's the list of pending Windows Updates from the local or remote computers.
.DESCRIPTION
This script takes a list of Windows computers from the pipeline or as a parameter and gets the list of pending updates.
.NOTES
Author: Mike Hashemi
V1 date: 19 Aug 13
.PARAMETER DNSHostName
Required parameter. Accepts pipeline input, or a comma-sperated list of computer names.
.PARAMETER OutputType
Default value is "File". Valid options are "File" and "Screen". This parameter determines where the script will send its output.
.PARAMETER OutputFilePath
Default value is the logged-on user's desktop. This parameter determines where the script will save the output file, if OutputType is "File".
.EXAMPLE
.\get-WindowsUpdates-Pending-Parameterized.ps1 -DNSHostName server1,server2
This example get's the list of pending updates for server1 and server2, then saves the list to a text file on the user's desktop. The output file is called "pendingUpdates_$computer.txt".
.EXAMPLE
Get-ADComputer -Filter DNSHostName | Where {$_.Name -eq "server1"} | .\get-WindowsUpdates-Pending-Parameterized.ps1 -OutputType Screen
This example get's the list of pending updates for server1, then outputs the list to the shell.
.EXAMPLE
Get-Content C:\servers.txt | .\get-WindowsUpdates-Pending-Parameterized.ps1 -OutputFilePath c:\
This example get's a list of computers from the servers.txt file (one server name per line), then get's the list of pending updates for those server. Finally, the script saves the list to a text file on the c:\ drive. The output file is called "pendingUpdates_$computer.txt".
#>
#Requires -version 2.0
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string[]]$DNSHostName,
[ValidateSet("Screen","File")]
[string]$OutputType = 'File',
[string]$OutputFilePath = [Environment]::GetFolderPath("Desktop")
)
#Test if the output file path exists. If not, try to create it.
If (($OutputType -eq "File") -and (-not (Test-Path $OutputFilePath))) {
Try {
New-Item $OutputFilePath -Type Directory -ErrorAction Stop | Out-Null
}
Catch [System.UnauthorizedAccessException] {
Write-Host ("You do not have permission to create a file in {0}. The specific error message is: {1}" -f $OutputFilePath,$_.Exception.Message) -ForegroundColor Red
Return
}
Catch {
Write-Host ("An unexpected error has occurred. The specific error message is: {0}" -f $_.Exception.Message) -ForegroundColor Red
Return
}
}
#Get updates for each computer
Foreach ($computer in $DNSHostName) {
Write-Host ("Gathering updates for {0}" -f $computer)
Try {
$updateSession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$computer))
}
Catch [UnauthorizedAccessException] {
Write-Host ("You do not have permission to access {0}. Please try with another account." -f $computer) -ForegroundColor Red
Continue
}
Catch {
If ($_.Exception -match "800706ba") {
Write-Host ("Cannot connect to the server: {0}, please check the name and try again." -f $computer) -ForegroundColor Red
Continue
}
Else {
Write-Host ("Unexpected error connecting to {0}. The specific error message is {1}." -f $computer, $error.Exception) -ForegroundColor Red
Continue
}
}
#Getting the list of updates
$updateSearcher = $updateSession.CreateUpdateSearcher()
$searchResult = $updateSearcher.Search("IsAssigned=1 and IsHidden=0 and IsInstalled=0")
#Setup variables for different types of updates
$critical = $searchResult.updates | Where {$_.MsrcSeverity -eq "Critical"}
$important = $searchResult.updates | Where {$_.MsrcSeverity -eq "Important"}
$other = $searchResult.updates | Where {$_.MsrcSeverity -eq $null}
If ($searchresult.Updates.Count -eq "0") {
If ($OutputType -eq "File") {
("There are no pending updates for {0}" -f $computer) | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
Continue
}
Else {
Write-Host ("There are no pending updates for {0}" -f $computer) -ForegroundColor Yellow
Continue
}
}
#Write results to the output file
If ($OutputType -eq "File") {
("Updates for {0}:" -f $computer) | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
("Critical = {0}" -f $critical.count) | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
Foreach ($update in $critical) {
$update.title | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
}"" | Out-File -FilePath "$OutputFilePath\pendingUpdates_$Computer.txt" -Append
("Important = {0}" -f $important.count) | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
Foreach ($update in $important) {
$update.title | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
}"" | Out-File -FilePath "$OutputFilePath\pendingUpdates_$Computer.txt" -Append
("Other = {0}" -f $other.count) | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
Foreach ($update in $other) {
$update.title | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
}"--------------------------------" | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append"" | Out-File -FilePath "$OutputFilePath\pendingUpdates_$computer.txt" -Append
}
Else {
#Write results to the shell
Write-Host ("Updates for {0}:" -f $computer)
Write-Host ("Critical = {0}" -f $critical.count)
Foreach ($update in $critical) {
Write-Host $update.title
}
Write-Host ("Important = {0}" -f $important.count)
Foreach ($update in $important) {
Write-Host $update.title
}
Write-Host ("Other = {0}" -f $other.count)
Foreach ($update in $other) {
Write-Host $update.title
}
Write-Host "--------------------------------"
Write-Host ""
}
}
#Open the output file for each computer
If ($OutputType -eq "File") {
Foreach ($computer in $DNSHostName) {
Notepad "$OutputFilePath\pendingUpdates_$computer.txt"
}
}