Archive

Archive for May, 2009

Powershell port ping function

As a variation of my previously posted Portscan with powershell i wrote the following function

Function Port-Ping {
    param([Array]$hostlist,[Array]$ports,[Int]$timeout = "50")
    $ErrorActionPreference = "SilentlyContinue"
    $ping = new-object System.Net.NetworkInformation.Ping
    foreach ($ip in $hostlist) {
        $rslt = $ping.send($ip,$timeout)
        if (! $?){
            Write-Host "Host: $ip - not found" -ForegroundColor Red
        }
        else {
            if ($rslt.status.tostring() –eq “Success”) {
                write-host "Host: $ip - Ports: " -foregroundColor Green -NoNewline
                foreach ($port in $ports){
                    $socket = new-object System.Net.Sockets.TcpClient($ip, $port)
                    if ($socket –eq $null) {
                        write-host "$port," -ForegroundColor Red -NoNewline
                    }
                    else {
                        write-host "$port,"-foregroundcolor Green -NoNewline
                        $socket = $null
                    }
                }
            Write-Host
            }
            else {
                write-host "Host: $ip - down" -ForegroundColor Red
            }
        }
    }
    Write-Host ""
    $ping = $null
}

This function is great when you need a fast overview of servers and the ports they have open. In my case I needed to check 3 ports on 100+ servers. The output of this function is color-coded  as the previous script (hence not suitable for piping)

The functions usage is like this:

PS> .\PortPing.ps1 <server> <port> <timeout>

Alternatively an array of servers can be created and used with the function:

Say you need to find whether all AD computer objects in a particular OU are alive and responding to port 3389 (Remote Desktop)

(I’m using Quest Download ActiveRoles Management Shell for Active Directory in this example)

PS> Get-QADComputer -service <Domain> -SearchRoot ‘<Domain/OU/OU>’ | %{.\PortPing.ps1 $_.Name 3389 100}

Inspired by Jeffery Hicks, I added the function to a dot source file, which is loaded with my PowerShell profile, which would then have this usage:

PS> Get-QADComputer -service <Domain> -SearchRoot ‘<Domain/OU/OU>’ | %{Port-Ping $_.Name 3389 100}

As a server administrator, this function gives me the rapid overview that I need to check multiple servers and their ports.

 

Regards

The Admin Guy

Run MBSA against all machines in WSUS

As a WSUS administrator, I often find the various views and reports frustrating.

Say you have a number of machines, which you want to see the status of from a OS security perspective, but you are not interested in the various other MS products (office, Exchange etc.) – No joy.

WSUS will show the machines overall status including everything. Handing report based on that, over to others will surely guarantee that all sorts of time will have to spent explaining all sorts of stuff.

Now, I’m sure that some may say that all the information can be gathered from the SQL database in one form or another, in that case, please let me know 🙂

From another perspective, the WSUS also acts like a good database of machines in scope. It provides various key information about the environment, which can surely be used for something..

The result of the above was a powershell script to get all the machines in WSUS and perform an MBSA scan against all of them.

The MBSA scan’s have the nice, self-explanatory reports and as a bonus they are also able to check for other things than patch status.

The script:

#We need a date to append to the log files
$date = (Get-Date).toshortdatestring()

#Connect to WSUS, if needed load assembly
$wsusrv = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
If (! $?){
    [Reflection.Assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
    $wsusrv = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
    }
    
#Get all machines in WSUS
$wsusrv.getcomputertargets() | select FullDomainName,IPAddress,RequestedTargetGroupName `
    | tee -Variable wsustargets | Export-Csv -NoTypeInformation "$pwd\WSUSTargets-$date.csv"

#Part to remove certain machines which we cannot scan 
#(like machines with different permissions than the bulk)
foreach ($target in $wsustargets){
    if ($target.RequestedTargetGroupName -eq "SomeFolder"){
        }
    ElseIf ($target.RequestedTargetGroupName -like "*SomeOtherFolder*"){
        }
    Else {
        #create array of machines to be scanned
        [Array]$MBSAList += $target.IPAddress
        $MBSAList | Out-File "$pwd\MBSATargets-$date.csv"
        }
}

#execute MBSA against the array created. This array must have been loaded to a file
$mbsacli = "C:\Program Files\Microsoft Baseline Security Analyzer 2\mbsacli.exe"
$cmdline = "/listfile " + '"' + "$pwd\MBSATargets-$date.csv" + '"' + `
    " /n OS+SQL+IIS+Password /nvc /wa /o " + '"%d% - %c% - %IP% (%t%)"' + `
    " /qe /qr /rd D:\MBSA_scan_auto"
$cmdline
$process = [System.Diagnostics.Process]::Start($mbsacli,$cmdline)
$process.WaitForExit()

Now, very off character for me, I have added some comments in the script, but it is fairly straight forward.

A list of machines is gathered from the WSUS server and stuffed in a file. The MBSAcli.exe utility is then executed using that file. It is of course possible to execute the MBSAcli.exe using the powershell array:

$mbsacli = "C:\Program Files\Microsoft Baseline Security Analyzer 2\mbsacli.exe"
foreach ($target in $MBSAList){
    $cmdline = "/target $target /n OS+SQL+IIS+Password /nvc /wa /o " + `
        '"%d% - %c% - %IP% (%t%)"' + " /qe /qr /rd D:\MBSA_scan_auto"
    $process = [System.Diagnostics.Process]::Start($mbsacli,$cmdline)
    $process.WaitForExit()
}

But the load of MBSA before each scan will lengthen the scan and will consume more resources (it’s not friendly as it is :-))

But of course there will be machines which cannot be scanned for whatever reason. Above I excluded the once I was sure would fail (due to other permissions) , but some machines may be offline, some with special permissions may hide somewhere etc.

So in order to get an overview of which machines that do not have a report, I did the following script:

param($mbsareportstore = "SomeFolder")

#Connect to WSUS, if needed load assembly
$wsusrv = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
If (! $?){
    [Reflection.Assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
    $wsusrv = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
}

#Get all machines in WSUS
$wsusrv.getcomputertargets() | select FullDomainName,IPAddress |tee -Variable wsustargets `
    | Export-Csv -NoTypeInformation "$pwd\NewWSUSTargets-$date.csv"

#Get all reports in the scanfile store
(Get-ChildItem $mbsareportstore | select name | tee -Variable reports)

#Create the status csv file
"Machine,Status,Reportname" | out-file "$PWD\FindReportStatus.txt"

#Do something...
foreach ($target in $wsustargets){
        
        #because the targets are reurned from WSUS in FQDN format, but reports are stored 
        #with hostname the domain name is cut of.
        $b = ($target.FullDomainName.ToString()).Split(".")
        $c = $b[0]
        
        #Using Select-string to look for the hostname ($c) in each of the filenames
        $reports | % {select-String -pattern $c -inputobject $_ | tee -variable slct}
        
        #If the hostname is not found in any filename, this is logged in the status file 
        #and added to a new targetfile for MBSA to use
        #Write-Host lines can be removed if script is not executed interactively
        if ($slct -eq $null){
            Write-Host "Report Not found for " $target.FullDomainName -foregroundcolor red
            "$c,ReportNotFound,N/A" | out-file -append "$PWD\FindReportStatus.txt"
            $target.FullDomainName | Out-File -Append "$PWD\MBSAScanMissing.txt"
        }
        Else {
            Write-Host "Report found for " $target.FullDomainName -foregroundcolor green
            "$c,ReportFound,$slct" | out-file -append "$PWD\FindReportStatus.txt"
            $slct = $Null
        }
}

This script simply gets the list from WSUS and checks whether a report of each machine exists in the report store.

The 2 scripts could be fused into one, but for my purposes, where I need to run script 1 on a regular basis and script 2 on demand, this is the best way.

Categories: Powershell Scripts Tags: , ,
%d bloggers like this: