function vce2020-1472{
# Source:
# Original script has been modified to fix a couple of bugs with connection error detection
# Create output directory on executiong user's desktop
$date = get-date -Format MMddyyyy
$rootPath = $env:USERPROFILE + '\Desktop\CISA'
$fullPath = $rootPath + '\' + $date
$UpdateList = $fullPath + '\complianceReport.csv'
if (Test-Path $rootPath){
if (!(test-path $fullPath)){
mkdir $fullPath
}
}else{
mkdir $fullPath
}
function checkPort{
Param(
[string]$server,
[int]$port=135,
[bool]$verbose=$true
)
function importPortQry{
if (!(Get-Command portqry.exe -ErrorAction SilentlyContinue)){
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))}
choco install portqry -y
if (Get-Command portqry.exe -ErrorAction SilentlyContinue){return $true}else{return $false}
}else{
return $true
}
}
function Check-NetConnection($server, $port) {
$session = New-Object System.Net.Sockets.TcpClient;
$result=$false
try {
$session.Connect($server, $port);
$result=$true;
} catch {
$result=$false;
} finally {
$session.Close();
}
return $result;
}
function testPortArray {
# Casting parameters is better than passing arguments as that allows for switches that can be arranged in any order
param ([string]$targetServer,[array]$arrPorts,$verbose=$false)
$source = $env:computername
$destination=$targetServer.toUpper()
$portsCount=$arrPorts.count
$portsSuccess=0
foreach ($port in $arrPorts){
$testResult = Check-NetConnection -server $targetServer -port $port;
If ($testResult){
if($verbose){Write-Output "$port`: reachable"}
$portsSuccess++
}
Else{
if($verbose){Write-Output "$port`: unreachable"}
}
}
if($portsCount -eq $portsSuccess){
return $true
}else{
return $false
}
}
if($verbose){write-host "Checking for existence of PortQry.exe..."}
do {
$portQryExists=Get-Command "PortQry.exe" -ErrorAction SilentlyContinue
if(!$portQryExists){
importPortQry;
sleep 1;
}
}while(!$portQryExists)
$portReachable=Check-NetConnection -server $server -port $port
if ($portReachable){
if($verbose){write-host "$env:computername is able to reach $server on the primary port of $port."}
$strInvokeCommand = "PortQry.exe -e $port -n $server";
$arrQuryResult = Invoke-Expression $strInvokeCommand;
$arrPorts = @(); #Initiates and clears the collection of ports array
ForEach ($strResult in $arrQuryResult)
{
If ($strResult.Contains("ip_tcp"))
{
$arrSplt = $strResult.Split("[");
$strPort = $arrSplt[1];
$strPort = $strPort.Replace("]","");
$arrPorts += $strPort;
}
}
# Remove duplicate port records from within the array
$arrPorts = $arrPorts | select -uniq
if ($arrPorts){
if($verbose){write-host "These are the detected dynamic ephemeral ports being used:`r`n$arrPorts" }
$result=testPortArray -targetServer $server -arrPorts $arrPorts # Pass the ports array into the workflow as a parameter
return $result
}else{
if($verbose){write-host "Ephemeral ports were NOT detected.`r`n"}
return $portReachable
}
}else{
if($verbose){write-host "$env:computername is NOT able to reach $server on port: $port`r`n"}
return $false
}
}
## Get all DCs in forest
$allDCs = ($((Get-ADForest).Domains | %{ Get-ADDomainController -Filter * -Server $_ })).hostname
$validHotFixes=@(
'KB4571729',
'KB4571719',
'KB4571736',
'KB4571702',
'KB4571703',
'KB4571723',
'KB4571694',
'KB4565349',
'KB4565351',
'KB4566782',
'KB4577051',
'KB4577038',
'KB4577066',
'KB4577015',
'KB4577069',
'KB4574727',
'KB4577062',
'KB4571744',
'KB4571756',
'KB4571748',
'KB4570333'
)
Write-Host -ForegroundColor White ("There are $($allDcs.count) DCs")
## Foreach DC, get Component Based Servicing provided updates and MSI installed updates. Then dump to a common CSV
foreach ($dc in $allDCs) {
$winRmIsAvailable=Test-NetConnection $dc -commonTCPPort WinRm -informationlevel Quiet
$rpcIsAvailable=checkPort $dc -port 135 -verbose $false
if($rpcIsAvailable){
$OS = $(Get-WmiObject -ComputerName $DC -Class Win32_OperatingSystem).caption
Write-Host -ForegroundColor White ("Getting updates for $DC")
Write-Host -ForegroundColor White ("Checking CBS Updates...")
try{
$quickFixes=Get-WmiObject Win32_quickfixengineering -ComputerName $dc | Select-Object *
}catch{
write-warning $_
}
if($quickFixes){
$quickFixes|%{
$hotfix=$_.HotFixID
if($hotfix -in $validHotFixes){
$hotfixFound=$true
$CBSObj = New-Object -TypeName psobject
$CBSObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC
$CBSObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $OS
$CBSObj | Add-Member -MemberType NoteProperty -Name "Update" -Value $hotfix
$CBSObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $hotfixFound
$CBSObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
#break;
}
}
}
}elseif($winRmIsAvailable){
Write-Host -ForegroundColor White ("Getting updates for $dc`r`nChecking MSI Updates...")
$session=new-pssession -ComputerName $dc
if($session){
$x=Invoke-Command -session $session -ScriptBlock {
$updatesession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$env:computername))
$UpdateSearcher = $updatesession.CreateUpdateSearcher()
$searchresult = $updatesearcher.Search("IsInstalled=1").Updates|select Title
#$updatesSession = New-Object -ComObject Microsoft.Update.Session ;
#$updateSearch = $updatesSession.CreateUpdateSearcher();
#$hotfixes=$updateSearch.Search("IsInstalled=1").Updates | Select Title;
<#
Exception calling "Search" with "1" argument(s): "Exception from HRESULT: 0x8024401C"
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
+ PSComputerName : TESTSERVER
#>
$os=(Get-WmiObject -Class Win32_OperatingSystem).caption;
return @($os,$searchresult)
}
remove-pssession $session
$hotfixCount=0
$x[1] | ForEach-Object {
$Title = $_.Title
$kb=switch -Wildcard ($Title){
"*4571729*" {"KB4571729"}
"*4571719*" {"KB4571719"}
"*4571736*" {"KB4571736"}
"*4571702*" {"KB4571702"}
"*4571703*" {"KB4571703"}
"*4571723*" {"KB4571723"}
"*4571694*" {"KB4571694"}
"*4565349*" {"KB4565349"}
"*4565351*" {"KB4565351"}
"*4566782*" {"KB4566782"}
"*4577051*" {"KB4577051"}
"*4577038*" {"KB4577038"}
"*4577066*" {"KB4577066"}
"*4577015*" {"KB4577015"}
"*4577069*" {"KB4577069"}
"*4574727*" {"B4574727"}
"*4577062*" {"KB4577062"}
"*4571744*" {"KB4571744"}
"*4571756*" {"KB4571756"}
"*4571748*" {"KB4571748"}
"*4570333*" {"KB4570333"}
}
if($kb){
$hotfixCount++
$CBSObj = New-Object -TypeName psobject
$CBSObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC
$CBSObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $x[0]
$CBSObj | Add-Member -MemberType NoteProperty -Name "Update" -Value $kb
$CBSObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $True
$CBSObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
#break
}
}
if($hotfixCount -eq 0){
$MSIObj = New-Object -TypeName psobject
$MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
$MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $x[0]
$MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'Missing'
$MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $false
$MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
}
}else{
write-warning "Unable to connect to $dc via WinRM"
$MSIObj = New-Object -TypeName psobject
$MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
$MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value 'unknown'
$MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'unknown'
$MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value 'unknown'
$MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
}
}else{
write-warning "Unable to connect to $dc via RPC nor WinRM"
$MSIObj = New-Object -TypeName psobject
$MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
$MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value 'unknown'
$MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'unknown'
$MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value 'unknown'
$MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
}
}
Write-Host -ForegroundColor White ("INFORMATION: DONE!")
}
vce2020-1472
Categories: