Pages

Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

3/22/2020

Monitor Cisco ASA with snmp using powershell

With the entire company working remotely, the bosses want to see an hourly report of ASA connections since our capacity is limited.
  • To find the SNMP OIDs of interest I used a freeware MIB walker and lots of googling in he past 2 days about this and everything else.
  • I already had SNMPGET for the cisco backup script I've been using for years.
  • This was a good opportunity to learn more about using RRDTOOLS.  I downloaded RRD from www.rrdtool.org to use for saving the connection history and graphing it.
  • I also wanted to capture internet circuit bandwidth and utilization.  I have been using the free Solarwinds Realtime Bandwidth Monitor for this to show all the peaks that get averaged out in Orion and others.  I was able to find a powershell script that grabbed a screen shot and adjusted it to only capture the half of the server screen where the internet circuit monitors are open on,
    • It turns out that this requires that I be RDPd to this machine all the time.  So this isn't a long term kind of thing.
  • Using windows task scheduler a batch file runs that executes the powershell to take a screenshot and save it in the working folder.  Then my powershell launches. 
  • Roughly the powershell does the following:
    • create $report and then add the text of HTML BODY and TABLE headers
    • run SNMPGET to pull the svc and webvpn current connection counts from two ASA's we refer to as PRI and SEC.  svc is anyconnect client connections and webvpn is "clientless" which in my case is workspot user sessions.
    • calculate the total sessions on PRI & SEC and grand total.
    • add table rows and table data fields to $report
    • use rrdtool update to save the total to rrd database.
    • use rrdtool graph to create graph and save to working directory
    • add HTML image tags to insert the RRD graph and the screenshot image to $report
    • save $report as HTML file in working directory 
    • use send-mailmessage to e-mail $report to the recipients.  
      • NOTE:  for the images to be included in the message it is necessary to also attach them.
      • ALSO:  to specify more than one attachment or recipient, they need to be entered in quotes separated by commas.  Like:
        • "joe@cool.net", "woodstock@cool.net"
  • Code for screenprint script is below.  Followed by code for main script.

######################

# send-screen.ps1

#
#start-process "PATH TO AN APPLICATION.EXE"
#Start-Sleep -Milliseconds 1000
$File = "\util\asa\internetbw.bmp"
Add-Type -AssemblyName System.Windows.Forms
Add-type -AssemblyName System.Drawing
$Screen = [System.Windows.Forms.SystemInformation]::VirtualScreen
$Width = ($Screen.Width/2+256)
$Height = ($Screen.Height-64)
$Left = ($Screen.Left+800)
$Top = $Screen.Top
$bitmap = New-Object System.Drawing.Bitmap $Width, $Height
$graphic = [System.Drawing.Graphics]::FromImage($bitmap)
$graphic.CopyFromScreen($Left, $Top, 0, 0, $bitmap.Size)
$bitmap.Save($File) 
Write-Output $File
#$SendTo = "joe@cool.net"
#$SMTPServer = "smtp" 
#$EmailFrom = “noreply@cool.net”
#$EmailSubject = “SCREENSHOT”
#$Image = $File
#$Message = new-object Net.Mail.MailMessage
#Add-PSSnapin Microsoft.Exchange.Management.Powershell.Admin -erroraction silentlyContinue
#$attachment = new-object Net.Mail.Attachment($Image)
#$attachment.ContentId = "att"
#$smtp = new-object Net.Mail.SmtpClient($smtpServer)
#$body = ''
#$Message.From = $EmailFrom
#$Message.To.Add($SendTo)
#$Message.Subject = $EmailSubject
#$Message.Body = $body
#$Message.IsBodyHTML = $true
#$Message.Attachments.Add($attachment)
#$smtp.Send($Message)
#$attachment.Dispose()
#
#     END
#######################


##########################################
#
# CONRPT.PS1
#
# ASA Connection Report
#

$community = 'readonly'
$SEC = '10.66.1.16'
$PRI = '10.66.1.6'
$svc = '.1.3.6.1.4.1.9.9.392.1.3.35.0'
$webvpn = '.1.3.6.1.4.1.9.9.392.1.3.38.0'
$outfile = "asa-connect.html"
$logfile = "log.txt"
$rptname = "VPN Connections & Internet Bandwidth Usage"
$recipient = "matt.kunkel@troutman.com","lloyd.petrey@troutman.com"
$today = get-date

############################################################################################
# Report Heading

$report=@'
<STYLE>
BODY{font-family: Verdana, Arial, Helvetica, sans-serif;font-size:12;font-color: #000000}
TABLE{border-width: 2px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;} 
TH{border-width: 2px;padding: 4px;border-style: solid;border-color: black;background-color: #dddddd;font-size:16;font-weight:bold}
TD{border-width: 2px;padding: 4px;border-style: solid;border-color: black;background-color: #efefef; font-size:12;font-weight:normal} 
TD.error{border-width: 2px;padding: 4px;border-style: solid;border-color: black;background-color: #ffffff;font face="monospace";font-size:10;font-color: #cccccc}
</STYLE> 
<HTML>
<HEAD> 
<TITLE></TITLE> 
</HEAD> 
<BODY>
'@

$report+="<H2>VPN Connections</H2><H4>"
$report+=$today
$report+="</H4><table><th>Connection </th><th>PRI </th><th>SEC </th></tr>"

############################################################################################




$cmd = "c:\snmp\bin\snmpget -M c:\snmp\mib -O nQ -v 2c -r 2 -t 1000 -c $community $SEC $svc"
$result = invoke-expression $cmd
$output = $result -split "= "
$anyconnectsec = $output[1]
$result=''
$output=''

$cmd = "c:\snmp\bin\snmpget -M c:\snmp\mib -O nQ -v 2c -r 2 -t 1000 -c $community $PRI $svc"
$result = invoke-expression $cmd
$output = $result -split "= "
$anyconnectpri = $output[1]
$result=''
$output=''

$cmd = "c:\snmp\bin\snmpget -M c:\snmp\mib -O nQ -v 2c -r 2 -t 1000 -c $community $PRI $webvpn"
$result = invoke-expression $cmd
$output = $result -split "= "
$workspotpri = $output[1]
$result=''
$output=''

$cmd = "c:\snmp\bin\snmpget -M c:\snmp\mib -O nQ -v 2c -r 2 -t 1000 -c $community $SEC $webvpn"
$result = invoke-expression $cmd
$output = $result -split "= "
$workspotsec = $output[1]
$result=''
$output=''

$totalPRI = [int]$anyconnectpri + [int]$workspotpri
$totalSEC = [int]$anyconnectsec + [int]$workspotsec

$report+="<tr><td>anyconnect</td><td>$anyconnectpri</td><td>$anyconnectsec</td></tr>"
$report+="<tr><td>workspot</td><td>$workspotpri</td><td>$workspotsec</td></tr>"
$report+="<tr><td>total</td><td>$totalPRI</td><td>$totalSEC</td></tr>"

$total = $totalPRI + $totalSEC

$log = "`t`t`t PRI `t SEC `n"
$log+= "anyconnect `t $anyconnectpri `t $anyconnectsec `n"
$log+= "workspot `t $workspotpri `t $workspotsec `n"
$log+= "total `t`t $totalPRI `t $totalSEC `n"
$log+= "$total `n"

$log | out-file $logfile

$now = get-date -date $today -uformat %s
$timestamp = [int]$now

& \rrd\bin\rrdtool update allcon.rrd N:$total 

& & \rrd\bin\rrdtool graph all-week.png --units-exponent 0 --start now-7d --end now DEF:ds1a=allcon.rrd:all:AVERAGE VDEF:ds1max=ds1a`,MAXIMUM LINE3:ds1a#FF0000:"Total Connections = $total" GPRINT:ds1max:"Max for Week=%5.0lf     "

$image=@'
</TABLE><img src="all-week.png"></img>
</img>
'@
$report+=$image
$report+="</BODY></HTML>" 

$report | out-file $outfile 

############################################################################################
#e-mail the report

$messageSubject = $rptname
$smtpServer = "smtp.cool.net"
$smtpFrom = "noreply@cool.net"
$smtpTo = $recipient
$message = $report 
#send-mailmessage -to $smtpTo -cc "joe@cool.net" -from $smtpFrom -subject $messageSubject -body $message -smtpserver $smtpServer -BodyAsHtml
send-mailmessage -to $smtpTo -cc "cool.net" -from $smtpFrom -subject $messageSubject -body $message -smtpserver $smtpServer -BodyAsHtml -attachments "\util\asa\all-week.png","\util\asa\internetbw.bmp"
###


1/02/2019

Capture on Windows Server without any Wireshark or other install




Netsh trace start capture=yes tracefile=c:\temp\trace.etl 
Netsh trace stop
 .\etl-to-pcap.ps1 -Path c:\temp\trace.etl -Destination c:\temp\trace.pcap



etl-to-pcap.ps1
[CmdletBinding()]

param(
[Parameter(Position=0)]
[ValidateScript({
    if( -Not ($_ | Test-Path) ){
        throw "File or folder $_ does not exist"
    }

    if($_.Extension -ne ".etl"){
        throw "Source file must be .etl file"
    }
    return $true
})]
[System.IO.FileInfo]$Path,

[Parameter(Position=1)]
[ValidateScript({
    if( -Not ($path.DirectoryName | Test-Path) ){
        throw "File or folder does not exist"
    }

    if($_.Extension -ne ".pcap") {
        throw "Estination file must be .pcap file"
    }
    return $true
})]
[System.IO.FileInfo]$Destination,

[Parameter(Position=2)]
[Uint32]$MaxPacketSizeBytes = 65536)


$csharp_code = @'
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace chentiangemalc
{
    public static class NetworkRoutines
    {
    public static long ConvertEtlToPcap(string source, string destination, UInt32 maxPacketSize)
        {
            int result = 0;
            using (BinaryWriter writer = new BinaryWriter(File.Open(destination, FileMode.Create)))
            {

                UInt32 magic_number = 0xa1b2c3d4;
                UInt16 version_major = 2;
                UInt16 version_minor = 4;
                Int32 thiszone = 0;
                UInt32 sigfigs = 0;
                UInt32 snaplen = maxPacketSize;
                UInt32 network = 1; // LINKTYPE_ETHERNET

                writer.Write(magic_number);
                writer.Write(version_major);
                writer.Write(version_minor);
                writer.Write(thiszone);
                writer.Write(sigfigs);
                writer.Write(snaplen);
                writer.Write(network);

                long c = 0;
                long t = 0;
                using (var reader = new EventLogReader(source, PathType.FilePath))
                {
                    EventRecord record;
                    while ((record = reader.ReadEvent()) != null)
                    {
                        c++;
                        t++;
                        if (c == 10000)
                        {
                            Console.WriteLine(String.Format("Processed {0} events with {1} packets processed",t,result));
                            c = 0;
                        }
                        using (record)
                        {
                            if (record.ProviderName == "Microsoft-Windows-NDIS-PacketCapture")
                            {
                                result++;
                                DateTime timeCreated = (DateTime)record.TimeCreated;
                                UInt32 ts_sec = (UInt32)((timeCreated.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
                                UInt32 ts_usec = (UInt32)(((timeCreated.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds) - ((UInt32)((timeCreated.Subtract(new DateTime(1970, 1, 1))).TotalSeconds * 1000))) * 1000;
                                UInt32 incl_len = (UInt32)record.Properties[2].Value;
                                if (incl_len > maxPacketSize)
                                {
                                   Console.WriteLine(String.Format("Packet size of {0} exceeded max packet size {1}, packet ignored",incl_len,maxPacketSize));
                                }
                                UInt32 orig_len = incl_len;

                                writer.Write(ts_sec);
                                writer.Write(ts_usec);
                                writer.Write(incl_len);
                                writer.Write(orig_len);
                                writer.Write((byte[])record.Properties[3].Value);

                            }
                        }
                    }
                }
            }
            return result;
        }
    }
}
'@

Add-Type -Type $csharp_code

$result = [chentiangemalc.NetworkRoutines]::ConvertEtlToPcap($Path.FullName,$Destination.FullName,$MaxPacketSizeBytes)

Write-Host "$result packets converted."





9/28/2016

Duplicate IP address registrations in DNS

Duplicate IP address registrations in DNS


https://blogs.technet.microsoft.com/askpfe/2011/06/03/how-dns-scavenging-and-the-dhcp-lease-duration-relate/


Very useful discussion of this issue and methods to address it.


Also a script to identify duplicate IP addresses in DNS:




#
#Import the Active Directory Module
import-module activedirectory

#Define an empty array to store computers with duplicate IP address registrations in DNS
$duplicate_comp = @()

#Get all computers in the current Active Directory domain along with the IPv4 address
#The IPv4 address is not a property on the computer account so a DNS lookup is performed
#The list of computers is sorted based on IPv4 address and assigned to the variable $comp
$comp = get-adcomputer -filter * -properties ipv4address | sort-object -property ipv4address

#For each computer object returned, assign just a sorted list of all 
#of the IPv4 addresses for each computer to $sorted_ipv4
$sorted_ipv4 = $comp | foreach {$_.ipv4address} | sort-object

#For each computer object returned, assign just a sorted, unique list 
#of all of the IPv4 addresses for each computer to $unique_ipv4
$unique_ipv4 = $comp | foreach {$_.ipv4address} | sort-object | get-unique

#compare $unique_ipv4 to $sorted_ipv4 and assign just the additional 
#IPv4 addresses in $sorted_ipv4 to $duplicate_ipv4
$duplicate_ipv4 = Compare-object -referenceobject $unique_ipv4 -differenceobject $sorted_ipv4 | foreach {$_.inputobject}

#For each instance in $duplicate_ipv4 and for each instance 
#in $comp, compare $duplicate_ipv4 to $comp If they are equal, assign
#the computer object to array $duplicate_comp
foreach ($duplicate_inst in $duplicate_ipv4)
{
    foreach ($comp_inst in $comp)
    {
        if (!($duplicate_inst.compareto($comp_inst.ipv4address)))
        {
            $duplicate_comp = $duplicate_comp + $comp_inst
        }
    }
}

#Pipe all of the duplicate computers to a formatted table
$duplicate_comp | ft name,ipv4address -a

9/29/2015

List all SPNs in Active Directory

From TechNet



cls
$search = New-Object  DirectoryServices.DirectorySearcher([ADSI]“”)
$search.filter = “(servicePrincipalName=*)”
$results = $search.Findall()

 

#list results
foreach($result in $results)
{
        $userEntry  = $result.GetDirectoryEntry()
        Write-host "Object Name = " $userEntry.name -backgroundcolor "yellow" -foregroundcolor "black"
        Write-host "DN      =      "  $userEntry.distinguishedName
        Write-host "Object Cat. = "  $userEntry.objectCategory
        Write-host "servicePrincipalNames"
        $i=1
        foreach($SPN in $userEntry.servicePrincipalName)
        {
            Write-host  "SPN(" $i ")   =      " $SPN       $i+=1
        }
        Write-host ""

} 

1/14/2015

Powershell: File Dialog

Here is an example of presenting the user with a file dialog. 
This script also does some conversion and opens the CSV in Excel when it's done.
############################################################################################
#
# SSID Report Conversion
# Process SSID report from NCS.  Calculate connection time in seconds and KB transferred
#

Function Get-FileName($initialDirectory)
{   
 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
 $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
 $OpenFileDialog.ShowHelp = $true
 $OpenFileDialog.initialDirectory = $initialDirectory
 $OpenFileDialog.filter = "All files (*.*)| *.*"
 $OpenFileDialog.ShowDialog() | Out-Null
 $OpenFileDialog.filename
} #end function Get-FileName

# 

[string]$infile = Get-FileName -initialDirectory "Downloads"
if (-not $infile) { exit }

$outfile = $infile -replace ".csv", "-ADJUSTED.csv"

$file = get-content $infile
$today = Get-Date
$today = $today.touniversaltime()

write-output "Converted:  $today" | out-file -encoding ASCII -filepath $outfile
foreach ($line in $file) {
 $field = $line.split(",")
 if ($field.count -eq 13) {# report body
  if ($field[0] -eq "Client Username") { #header line (first field heading matches)
   $heading = $line + ",Seconds Connected,KBytes Transferred"
   write-output $heading | out-file -encoding ASCII -filepath $outfile -append
   continue
  } #end header line

  #fix average Kb
  $avgKbits = $field[6]
  if ($avgKbits -eq "<0.1") { $avgKbits = 0 }
 
  #Connection time in seconds
  $conn = $field[5]
  [array]$seperator = " hrs " , " min " , " sec"
  $option = [System.StringSplitOptions]::RemoveEmptyEntries
  $hours = 0
  $minutes = 0
  $seconds = 0
  $connection = 0
  $temp = $conn.split($seperator, $option)
  if ($temp.count -eq 3) {
   $hours = [int]$temp[0]
   $minutes = [int]$temp[1]
   $seconds = [int]$temp[2]
   }
  elseif ($temp.count -eq 2) {
   $minutes = [int]$temp[0]
   $seconds = [int]$temp[1]
   }
  elseif ($temp.count -eq 1) {
   $seconds = [int]$temp[0]
   }
  $connection = ( $hours * 60 * 60 )  + ( $minutes * 60 ) + $seconds

  #Bytes transferred
  $KBytes = $connection * $avgKbits * 8
  $line = $line + "," + $connection + "," + $KBytes
  write-output $line | out-file -encoding ASCII -filepath $outfile -append
 }#end if 16 fields

 else {# report heading line (does not have 13 fields)
  write-output $line | out-file -encoding ASCII -filepath $outfile -append
 }#end else 

}#end foreach line

start excel $outfile

1/12/2015

powershell query remote sharepoint

Example of query to a sharepoint list on a remote machine.
############################################################################################
# Create $list of server names - in Service Catalog where status equals selection
#

[array]$list = $null
$uri = "http://portal/apps/systemscatalog/_vti_bin/lists.asmx?WSDL"
$listName = "Server Catalog" 

# Create xml query - get the whole list
$xmlDoc = new-object System.Xml.XmlDocument
$query = $xmlDoc.CreateElement("Query")
$vfxml = "" +
 "" +
 "" +
 "" +
 ""
$viewFields = $xmlDoc.CreateElement("ViewFields")
$queryOptions = $xmlDoc.CreateElement("QueryOptions")
$query.set_InnerXml("FieldRef Name='Full Name'") 
$rowLimit = "3000"
$serverlist = $null 
$service = $null  
try{
    $service = New-WebServiceProxy -Uri $uri  -Namespace SpWs  -UseDefaultCredential
}
catch{ 
    Write-Error $_ -ErrorAction:'SilentlyContinue' 
}
if($service -ne $null){
    try{        
        $serverlist = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, $null)
    }
    catch{ 
        Write-Error $_  -ErrorAction:'SilentlyContinue'
    }
}
$output = $serverlist.data.row


if ( -not $output) {
 clear-host
 "ERROR:  No output from sharepoint"
 "ERROR:  No output from sharepoint" | out-file $logfile -append
 exit
 }

[string]$status = $null
foreach ($item in $output) {
 [string]$status = $item.ows_DeploymentStatus
 $Server = $item.ows_Title
 $dmz = $item.ows_IsDMZServer
 if ($dmz -eq $null) { $dmz = 0 }
 if($status -eq $selection) { 
   if ($filterDMZ -and (-not $dmz)) {
  if ($Server) { $list = $list + $Server} #skip a null value
   }#end if
   else {
       if ($Server) { $list = $list + $Server} #skip a null value
       }
 }#end if
 [string]$status = $null 
} #end foreach

#

$list = $list | sort-object

if ( -not $list) { 
    "ERROR:  No server list to check"
    "ERROR:  No server list to check" | out-file $logfile -append
    exit
    }

12/18/2014

Powershell Report HP Virtual Connect VLANs

Create a report from HP virtual connect for all VLAN's defined in each server profile.

$cmd = 'C:\Program Files\HP\Virtual Connect Enterprise Manager\Virtual Connect Enterprise Manager CLI\vcemcli.exe'
 $arg1 = '-export'
 $arg2= 'profiles'
 $arg3 = '-exportfile'
 $arg4 = 'profiles.csv'
 &$CMD $arg1 $arg2 $arg3 $arg4
 $raw = ".\profiles.csv" | import-csv -header ''
 $list = $raw | format-list -property "Profile Name", "*Network Name" | out-string 
 $list = $list.split("`n")
 foreach ($item in $list) { 
  $item = $item.replace("`n","")
  $descr = $item.split(":")[0]
  $value = $item.split(":")[1]
  if ( $descr -like "Profile Name*") { 
   write-output "-----------------------------"
   write-output $value
   }
  else { 
   if ( $value -notlike "*N/A*") {
    write-output "    $value"
    }
   }
  }

9/19/2014

Powershell: Get list of files in folder

Create a list of all files in a folder. Maybe in preparation for processing each file.

$workdir = "c:\parse"
$inputdir = $workdir + "\input"

# Get file listing
if (-not (test-path $inputdir)) {
 "Folder:  $inputdir"
 "Does not exist!"
 exit
 }

$files = get-childitem $inputdir -name
if (-not ($files)) {
 "Folder:  $inputdir"
 "Contains no files!"
 exit
 }

Powershell - Date String for File Name

I often need to create a temp file or output file and want to make it unique. Using the date and time can be a good way to do that. For example:

$now = get-date -format yyyyMMddHHmmss
$outfile = $now + ".csv"

8/21/2014

Powershell: Get SharePoint List

Need to get a sharepoint list but don't have access to the server -- I just have a logon that is able to browse to the list. In this example the list is named "Server Catalog." I retrieved the entire list and then selected entries with a specific value in a field named "DeploymentStatus"
$credential = get-credential
$uri = "http://tskm/apps/systemscatalog/_vti_bin/lists.asmx?WSDL"
$listName = "Server Catalog"             
            
# Create xml query to retrieve list.             
$xmlDoc = new-object System.Xml.XmlDocument            
$query = $xmlDoc.CreateElement("Query")            
$viewFields = $xmlDoc.CreateElement("ViewFields")            
$queryOptions = $xmlDoc.CreateElement("QueryOptions")            
$query.set_InnerXml("FieldRef Name='Full Name'")             
$rowLimit = "1000"            
            
$list = $null             
$service = $null              
            
try{            
    $service = New-WebServiceProxy -Uri $uri  -Namespace SpWs  -credential $credential  # -UseDefaultCredential
}            
catch{             
    Write-Error $_ -ErrorAction:'SilentlyContinue'             
}

if($service -ne $null){            
    try{                    
        $list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, $null)
    }            
    catch{             
        Write-Error $_ -ErrorAction:'SilentlyContinue'            
    }            
}

$output = $list.data.row

foreach ($item in $output) {
 if ($item.ows_DeploymentStatus = "Production") {
  [string]$server=$item.ows_Title
  [string]$status=$item.ows_DeploymentStatus
  "$server - $status"
  }
 }

1/30/2014

Run a command on every server in domain. (Powershell v2 compatible)



#############################################################################################################
#
#   run-remote.ps1
#
#   run a command on each server in the domain
#   log results to file and e-mail report of failures
#

$rcmd = "ping cmsweb"
$success = "Reply from"
$logfile = ".\run-remote.log"
$outfile = ".\cmsweb-test.html"
$rptname = "cmsweb reachability"
$recipient = "user@domain.com"

############################################################################################
# Create $list of server names for all Windows servers in Active Directory
#
$strCategory = "computer" 
$strOS = "Windows*Server*"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher 
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("OperatingSystem=$strOS")
$colProplist = "dnshostname"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults) 
 { 
  $objComputer = $objResult.Properties;  
  $Server = $objComputer.dnshostname
  $Server = $Server -replace "\s{2,}", ""
  $Server = $Server -replace "\.usa\.domain\.com", ""
  if ($Server) { $list = $list + $Server } #skip a null value
  } 
$list = $list | sort-object
###

clear-host
$today = get-date
$today | out-file $logfile

"Run:  $rcmd"
$username = read-host "Logon"
$pw = read-host -AsSecureString "Password"
$pass = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
   [Runtime.InteropServices.Marshal]::SecureStringToBSTR($pw))
############################################################################################
# Report Heading

$report=@'
<STYLE>
BODY{font-family: Verdana, Arial, Helvetica, sans-serif;font-size:12;font-color: #000000}
TABLE{border-width: 2px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;} 
TH{border-width: 2px;padding: 1px;border-style: solid;border-color: black;background-color: #dddddd;font-size:16;font-weight:bold}
TD{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #efefef; font-size:12;font-weight:normal} 
TD.error{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #ffffff;font face="monospace";font-size:10;font-color: #cccccc}
</STYLE> 
<HTML> 
<HEAD> 
<TITLE></TITLE> 
</HEAD> 
<BODY> 
<H2>Server Time Issues</H2> 
<H4>
'@
$report+=$today
$report+="Command:  $rcmd"
$report+="</H4><table><th>Server</th><th>IP Number</th><th>Result</th></tr>"

############################################################################################
# Run for every server in list 


foreach ($computer in $list) {
 If (Test-Connection -computername $computer -Quiet -count 1){ #respond to ping?
  #get IP address
  $conn = test-connection -computername $computer -count 1
  $ip = $conn.IPV4Address.IPAddressToString
  "Executing remotely from $computer - $ip"
  $cmd = "c:\util\psexec.exe /acceptEula \\$computer -u $username -p $pass -w c:\ $rcmd"
  $result = invoke-expression $cmd
  if ($result -like "$success*") { #success 
   "$computer - $ip" + ": <$rcmd> -> Success" | out-file $logfile -append
#   $report+=('<tr><td>' + $computer + '</td>') 
#   $report+=('<td >$ip</td>')  
#   $report+=('<td >Success</td>')  
#   $report+=('</tr>')
   } 
  else { #fail 
   "$computer - $ip" + ": <$rcmd> -> Fail" | out-file $logfile -append
   $report+=('<tr><td>' + $computer + '</td>') 
   $report+=('<td >$ip</td>')  
   $report+=('<td >Fail</td>')  
   $report+=('</tr>')
   }
  }#end if connection
 }#end foreach computer
clear-host
notepad $logfile

$report+="</TABLE></BODY></HTML>" 

$report | out-file $outfile 

############################################################################################
#e-mail the report

$messageSubject = $rptname
$smtpServer = "smtp.domain.com"
$smtpFrom = "noreply@domain.com"
$smtpTo = $recipient
$message = $report
send-mailmessage -to $smtpTo -cc "admin@domain.com" -from $smtpFrom -subject $messageSubject -body $message -smtpserver $smtpServer -BodyAsHtml 
###

1/15/2014

Check Time on VMWare Hosts

Check Time on VMware Hosts Similar to my previous script reporting on Windows Server time.

##########################################################################################
# esx-time.ps1
#
# Gather local time and time zone for all servers in AD.
# Report servers with time different from machine on which script is run
# E-Mail report to designated recipient.
#
# Requires vmware power cli
# "set-powercliconfiguration -InvalidCertificateAction Ignore" to ignore cert errors
#
#
##########################################################################################

Add-PSSnapin VMware.VimAutomation.Core  -ErrorAction SilentlyContinue

#VCS
$vcs="privcs01" # PRIVDIVC1, PRIDEVVC1, PRIVCSVDI01, SECVCS01

# E-Mail Recipient 
$recipient="administrator@DOMAIN.com"

# Greatest acceptable time difference
$maxdiff=59

$outfile = "c:\dev\esx-time.html"
$user = "usa\svc_vmware"
$pw = Read-Host "Password for $user" -AsSecureString
$rootpw = Read-Host "Password for root" -AsSecureString
#convert $pw to plain text
    $pass = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
        [Runtime.InteropServices.Marshal]::SecureStringToBSTR($pw))
#convert $rootpw to plain text
    $rootpass = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
        [Runtime.InteropServices.Marshal]::SecureStringToBSTR($rootpw))

############################################################################################
# Get List of Host Names from VCS server
#
write-host "Getting Server List from VCS"
connect-viserver -Server $vcs -User $user -Password $pass -ErrorAction SilentlyContinue > $null
$hosts = get-vmhost
disconnect-viserver -confirm:$false -ErrorAction SilentlyContinue > $null
$list = @()
foreach ($Server in $hosts) { 
  $Server = $Server -replace "\s{2,}", ""
  $Server = $Server -replace "\.usa\.DOMAIN\.com", ""
  if ($Server) { $list = $list + $Server } #skip a null value
  } 
$list = $list | sort-object
write-host "COMPLETE"
###


#clear-host
$today = get-date

############################################################################################
# Report Heading

$report=@'
<STYLE>
BODY{font-family: Verdana, Arial, Helvetica, sans-serif;font-size:12;font-color: #000000}
TABLE{border-width: 2px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;} 
TH{border-width: 2px;padding: 1px;border-style: solid;border-color: black;background-color: #dddddd;font-size:16;font-weight:bold}
TD{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #efefef; font-size:12;font-weight:normal} 
TD.error{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #ffffff;font face="monospace";font-size:10;font-color: #cccccc}
</STYLE> 
<HTML> 
<HEAD> 
<TITLE></TITLE> 
</HEAD> 
<BODY> 
<H2>VMWare Host Time Issues</H2> 
<H4>
'@
$report+=$today
$report+="</H4><table><th>Server</th><th>Date</th><th>Time</th><th>Off(s)</th></tr>"

############################################################################################
# Query every server in list 

write-host "Checking each server:"

foreach ($item in $list) {
  $flag=" "
  $dt=""
  $srvtime=""
  $hour = ""
  $min = ""
  $sec = ""
  $month = ""
  $day = ""
  $year = ""
  $comp = ""
  $d = ""
  $t = ""
   $computer = $item 
  $comp = "{0,-16}" -f $computer
  $comp = $comp.padright(16," ")

write-host ">$computer<"

 If (Test-Connection -computername $computer -Quiet -count 1){ #respond to ping?
write-host "    PING - SUCCESS"
write-host "    Time Query"
  $output=""
  $block = @'
  $machine = $args[0]
  $pass = $args[1]
  Add-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue
  connect-viserver -server $machine -user "root" -password $pass -WarningAction SilentlyContinue -ErrorAction SilentlyContinue > $null
#  $time = (get-view serviceinstance).CurrentTime()
#  $time
  ((get-view serviceinstance).CurrentTime())
'@
  $sb = [scriptblock]::create($block)
  $args=@()
  $args = ($computer, $rootpass)
  start-job -name $computer -scriptblock $sb -argumentlist $args > $null
  Wait-Job -name $computer -Timeout 60 > $null 
  $output = Receive-Job $computer
#$output
  #disconnect-viserver -server $computer -confirm:$false #-ErrorAction SilentlyContinue > $null
  if ($output) {  
  $dt = $output
write-host "DT=$dt"
  }
  else {   
  write-host "$computer`tERROR:  No time Query Output"
   $report+='<tr><td class="error">' + $comp + '</td>' 
    $report+='<td colspan="4" class="error">' + "ERROR - No response to date/time query" + '</td>'  
   $report+='</tr>' 
  continue
  } # end if output
 }#end if ping
 else { # No PING response
  write-host "$computer`tERROR:  No PING Response"
   $report+='<tr><td class="error">' + $comp + '</td>' 
          $report+='<td colspan="4" class="error">' + "CONNECTION ERROR:  No response to PING" + '</td>'  
   $report+='</tr>' 
  continue
  }
 [string] $month = [System.Convert]::ToString($dt.Month)
 $month = $month.padleft(2,"0")
 [string] $day = [System.Convert]::ToString($dt.Day)
 $day = $day.padleft(2,"0")
 [string] $year = [System.Convert]::ToString($dt.Year)
 $year = $year.padleft(4,"0")
 $d = $month + "/" + $day + "/" + $year
write-host "    Date=$d"
 [string] $hour = [System.Convert]::ToString($dt.Hour)
 $hour = $hour.padleft(2,"0")
 [string] $min = [System.Convert]::ToString($dt.Minute)
 $min = $min.padleft(2,"0")
 [string] $sec = [System.Convert]::ToString($dt.Second)
 $sec = $sec.padleft(2,"0")
 $t = $hour + ":" + $min + ":" + $sec
write-host "    Time=$t"
 if ($dt) { #$dt not null
  $srvtime=($dt.Minute)*60+($dt.Second)
  $refmin = ""
  $refsec = ""
  $now = get-date
  $cmptime = ($now.Minute)*60+($now.Second)
  [string] $min = [System.Convert]::ToString($now.Minute)
  $refmin = $min.padleft(2,"0")
  [string] $sec = [System.Convert]::ToString($now.Second)
  $refsec = $sec.padleft(2,"0")
  $reftime=$refmin+":"+$refsec
  #Compare server time to script machine time.
  $diff=$cmptime-$srvtime
write-host "    Time Diff=$diff"
  if (($diff -gt $maxdiff) -or ($diff -lt (-1*$maxdiff))) { $flag="*" }
   write-host "$flag$comp`t$d`t$t`t$flag$diff$flag`t" $timezone.Description 
   if ($flag -eq "*") { #time difference is too great
    $report+=('<tr><td>' + $comp + '</td>') 
    $report+=('<td >' + $d + '</td>')  
    $report+=('<td >' + $t + '</td>')  
    $report+=('<td >' + $diff + '</td>')  
    $report+=('</tr>') 
    }
  }# end if null 
}#end foreach computer
###
$report+="</TABLE></BODY></HTML>" 

$report | out-file $outfile 

############################################################################################
#e-mail the report

$messageSubject = "VMWare Host Time Report"
$smtpServer = "smtp.DOMAIN.com"
$smtpFrom = "noreply@DOMAIN.com"
$smtpTo = $recipient
$message = $report
send-mailmessage -to $smtpTo -from $smtpFrom -subject $messageSubject -body $message -smtpserver $smtpServer -BodyAsHtml 
###


remove-job * -force

1/03/2014

Powershell Format Operator

Powershell Format Operator "-f"




OperatorExampleResultsDescription


{0}Display a particular element"{0} {1}" -f "a", "b"a b
{0:x}Display a number in Hexadecimal"0x{0:x}" -f 1813420x2c45e
{0:X}Display a number in Hexadecimal uppercase"0x{0:X}" -f 1813420x2C45E
{0:dn}Display a decimal number left justified, padded with zeros"{0:d8}" -f 300000003
{0:p}Display a number as a percentage"{0:p}" -f .12312.30 %
{0:c}Display a number as currency"{0:c}" -f  12.34$12.34
{0,n}Display with field width n, left aligned"|{0,5}|" -f "hi"|   hi|
{0,-n}Display with field width n, right aligned"|{0,-5}| -f "hi"|hi   |
{0:hh}
{0:mm}
Display the hours and minutes from a date time value"{0:hh}:{0:mm}" -f (Get-Date)01:34
{0:C}Display using the currency symbol for the current culture"|{0,10:C}|" -f 12.3|  $12.40|

1/02/2014

Powershell:  WMI Timeouts locking up scripts

There are a few folks with suggestions out there.  One is to use a job to run the query.  Unfortunately this leaves those jobs stuck out there so if a lot of my servers have WMI screwed up I suppose doing this could crash my management machine.
This example is to get the current time and time zone from every server machine in my AD domain. 

##########################################################################################
# CHECK-TIME.PS1
#
# Gather local time and time zone for all servers in AD.  Convert times to GMT & compare
# Report servers with time different from machine on which script is run
# E-Mail report to designated recipient.
#
##########################################################################################


# E-Mail Recipient 
$recipient="user@domain.com"

# Greatest acceptable time difference
$maxdiff=59

$outfile = "c:\dev\check-time.html"
If (Test-Path $outfile){
	Remove-Item $outfile
}

$logfile = "c:\dev\check-time.log"
If (Test-Path $logfile){
	Remove-Item $logfile
}

$mytimezone = get-wmiobject Win32_Computersystem -property CurrentTimeZone, daylightineffect
$myoffset = $mytimezone.CurrentTimeZone #GMT offset in minutes
$mydst = $mytimezone.daylightineffect
   if ($mydst) {
   	$myoffset+=60
   	}

##########################################################################################
# FUNCTION:  Check for TCP response on $port

function Test-Port {  
    Param(  
      [string] $srv,  
      $port=135,  
      $timeout=1500,  
      [switch]$verbose  
    )  
    # TCP connect $port
    $ErrorActionPreference = "SilentlyContinue"
    $tcpclient = new-Object system.Net.Sockets.TcpClient 
    $iar = $tcpclient.BeginConnect($srv,$port,$null,$null) 
    $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false) 
    # Check to see if the connection is done 
    if(!$wait) 
    { 
    # Close connection, report timeout 
    $tcpclient.Close()  
        if($verbose){write-host "Connection Timeout" }  
        Return $false  
    }  
    else  
    {  
        # Close connection, report any error
         $error.Clear()  
         $tcpclient.EndConnect($iar) | out-Null  
         if(!$?){if($verbose){write-host $error[0]};$failed = $true}  
         $tcpclient.Close()  
     }  
     # Return $true if connection established  
      if($failed){  
          return $false  
      } else {  
          return $true  
      }  
    } # http://technet.microsoft.com/en-us/library/ff730959.aspx


#
# End of functions
##########################################################################################


############################################################################################
# Create $list of server names for all Windows servers in Active Directory
#
$strCategory = "computer" 
$strOS = "Windows*Server*"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher 
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("OperatingSystem=$strOS")
$colProplist = "dnshostname"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults) 
 { 
  $objComputer = $objResult.Properties;  
  $Server = $objComputer.dnshostname
  $Server = $Server -replace "\s{2,}", ""
  $Server = $Server -replace "\.usa\.domain\.com", ""
  if ($Server) { $list = $list + $Server } #skip a null value
  } 
$list = $list | sort-object
###

clear-host
$today = get-date

############################################################################################
# Report Heading

$report=@'
<STYLE>
BODY{font-family: Verdana, Arial, Helvetica, sans-serif;font-size:12;font-color: #000000}
TABLE{border-width: 2px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;} 
TH{border-width: 2px;padding: 1px;border-style: solid;border-color: black;background-color: #dddddd;font-size:16;font-weight:bold}
TD{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #efefef; font-size:12;font-weight:normal} 
TD.error{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #ffffff;font face="monospace";font-size:10;font-color: #cccccc}
</STYLE> 
<HTML> 
<HEAD> 
<TITLE></TITLE> 
</HEAD> 
<BODY> 
<H2>Server Time Issues</H2> 
<H4>
'@
$report+=$today
$report+="</H4><table><th>Server</th><th>Date</th><th>Time</th><th>Off(s)</th><th>Time Zone</th></tr>"

############################################################################################
# Query every server in list 

foreach ($result in $list) {
	 $flag=" "
	 $timezone=""
	 $dt=""
	 $srvtime=""
	 $hour = ""
	 $min = ""
	 $sec = ""
	 $comp = ""
	 $d = ""
	 $t = ""
 	 $computer = $result 
	 $comp = "{0,-16}" -f $computer
	 $comp = $comp.padright(16," ")
#write-host ("$Computer"+":") 
#("$Computer"+":")|out-file $logfile -append
	If (Test-Connection -computername $computer -Quiet -count 1){ #respond to ping?
	    $a = Test-Port $computer 
	    $dst=""
	    $timezone=""
	    $output=""
	    $offset=""
	    if ($a) { # resonds on RPC?
		#timezone
			$block = "get-wmiobject Win32_Computersystem -computer $computer -property CurrentTimeZone, daylightineffect"
			$sb = [scriptblock]::create($block)
			start-job -name $computer $sb > $null
			Wait-Job -name $computer -Timeout 10 > $null
			$output = Receive-Job $computer
			$block = "Get-WmiObject -class Win32_TimeZone -ComputerName $computer"
			$sb = [scriptblock]::create($block)
			start-job -name $computer $sb > $null
			Wait-Job -name $computer -Timeout 10 > $null
			$timezonedesc = Receive-Job $computer
			$tz = $timezonedesc.description
			if ($output -ne $null) {  
			    $timezone = $output
			    $offset = $timezone.CurrentTimeZone #GMT offset in minutes
			    $dst = $timezone.daylightineffect
			    if ($dst) {
			    	$offset+=60
			    	}
				 }
			else {   
			write-host "$computer`tERROR:  No WMI Query Output"
			"$computer`tERROR:  No WMI Query Output" | out-file $logfile -append
			 $report+='<tr><td class="error">' + $comp + '</td>' 
		         $report+='<td colspan="4" class="error">' + "WMI ERROR - No response to timezone query" + '</td>'  
			 $report+='</tr>' 
			continue
			}#end if output
		#date/time
			$block = "Get-WmiObject -class win32_localtime -ComputerName $computer"
			$sb = [scriptblock]::create($block)
			start-job -name $computer $sb > $null
			Wait-Job -name $computer -Timeout 10 > $null 
			$output = Receive-Job $computer
			if ($output -ne $null) {  
			$dt = $output
			}
			else {   
			write-host "$computer`tERROR:  No WMI Query Output"
			"$computer`tERROR:  No WMI Query Output" | out-file $logfile -append
			 $report+='<tr><td class="error">' + $comp + '</td>' 
		         $report+='<td colspan="4" class="error">' + "WMI ERROR - No response to date/time query" + '</td>'  
			 $report+='</tr>' 
			continue
			} # end if output
	    }#end if port
	    else {# No response on port
		write-host "$computer`tERROR:  No RPC Response"
		"$computer`tERROR:  No RPC Response" | out-file $logfile -append
		 $report+='<tr><td class="error">' + $comp + '</td>' 
	         $report+='<td colspan="4" class="error">' + "RPC ERROR - No response on port " + $port + '</td>'  
		 $report+='</tr>' 
		continue
		}    
	}#end if ping
	else { # No PING response
		write-host "$computer`tERROR:  No PING Response"
		"$computer`tERROR:  No PING Response" | out-file $logfile -append
		 $report+='<tr><td class="error">' + $comp + '</td>' 
	         $report+='<td colspan="4" class="error">' + "CONNECTION ERROR:  No response to PING" + '</td>'  
		 $report+='</tr>' 
		continue
		}
	[string] $month = [System.Convert]::ToString($dt.Month)
	[string] $day = [System.Convert]::ToString($dt.Day)
	[string] $year = [System.Convert]::ToString($dt.Year)
	[string] $hour = [System.Convert]::ToString($dt.Hour)
	$hour = $hour.padleft(2,"0")
	[string] $min = [System.Convert]::ToString($dt.Minute)
	$min = $min.padleft(2,"0")
	[string] $sec = [System.Convert]::ToString($dt.Second)
	$sec = $sec.padleft(2,"0")
	$d = $month + "/" + $day + "/" + $year
	$t = $hour + ":" + $min + ":" + $sec
	if ($dt) { #$dt not null
		#convert to object
		$dObj = get-date "$d $t"
		#adjust to GMT
		$srvtime=$dObj.addminutes(-$offset)
#write-host "    $computer time=$srvtime"	
#"    $computer time=$srvtime" | out-file $logfile -append
		$now = get-date
		$cmptime = $now.addminutes(-$myoffset)
		[string] $min = [System.Convert]::ToString($now.Minute)
		$diff = $cmptime-$srvtime
		$diff = $diff.totalseconds
		$diff = [decimal]::round($diff)
		if (($diff -gt $maxdiff) -or ($diff -lt (-1*$maxdiff))) { $flag="*" }
			write-host "$flag$comp`t$d`t$t`t$flag$diff$flag`t$tz"
			"$flag$comp`t$d`t$t`t$flag$diff$flag`t$tz" | out-file $logfile -append
			$zone = $timezonedesc.Description.tostring()
			if (-not($timezonedesc )) { #no zone returned
				$flag="*"
				$zone = "ERROR:  Invalid Time Zone Response"
				write-host "*$zone*"
				"*$zone*" | out-file $logfile -append
				}
			if ($flag -eq "*") { #time difference is too great
				$report+=('<tr><td>' + $comp + '</td>') 
				$report+=('<td >' + $d + '</td>')  
				$report+=('<td >' + $t + '</td>')  
				$report+=('<td >' + $diff + '</td>')  
				$report+=('<td >' + $zone + '</td>')  
				$report+=('</tr>') 
				}
	 }# end if null 
}#end foreach computer
###
$report+="</TABLE></BODY></HTML>" 

$report | out-file $outfile 

############################################################################################
#e-mail the report

$messageSubject = "Server Time Report"
$smtpServer = "smtp.domain.com"
$smtpFrom = "noreply@domain.com"
$smtpTo = $recipient
$message = $report
send-mailmessage -to $smtpTo -cc "admin@domain.com" -from $smtpFrom -subject $messageSubject -body $message -smtpserver $smtpServer -BodyAsHtml 
###
remove-job * -force

Dealing with WMI Timeouts — Steven Murawski

Dealing with WMI Timeouts — Steven Murawski: Dealing with WMI Timeouts

Get-WmiCustom (aka: Get-WMIObject with timeout!) - musc@> $daniele.work.ToString() - Site Home - MSDN Blogs

Get-WmiCustom (aka: Get-WMIObject with timeout!) - musc@> $daniele.work.ToString() - Site Home - MSDN Blogs: Unfortunately, the Get-WmiObject cmdlet does not let you specify a timeout. Therefore I cooked my own function which has a compatible behaviour to that of Get-WmiObject, but with an added “-timeout” parameter which can be set.

Function Get-WmiCustom([string]$computername,[string]$namespace,[string]$class,[int]$timeout=15) 
{ 
$ConnectionOptions = new-object System.Management.ConnectionOptions 
$EnumerationOptions = new-object System.Management.EnumerationOptions 

$timeoutseconds = new-timespan -seconds $timeout 
$EnumerationOptions.set_timeout($timeoutseconds) 

$assembledpath = "\\" + $computername + "\" + $namespace 
#write-host $assembledpath -foregroundcolor yellow 

$Scope = new-object System.Management.ManagementScope $assembledpath, $ConnectionOptions 
$Scope.Connect() 

$querystring = "SELECT * FROM " + $class 
#write-host $querystring 

$query = new-object System.Management.ObjectQuery $querystring 
$searcher = new-object System.Management.ManagementObjectSearcher 
$searcher.set_options($EnumerationOptions) 
$searcher.Query = $querystring 
$searcher.Scope = $Scope 

trap { $_ } $result = $searcher.get() 

return $result 
}

12/16/2013

Searching Active Directory user objects for a values in an attribute

Searching Active Directory user objects for value in an attribute:
The following will look for user objects with any value in "audio" attribute
$strFilter = "(&(objectCategory=User)(audio=*))"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher

$objSearcher.SearchRoot = $objDomain

$objSearcher.PageSize = 4000

$objSearcher.Filter = $strFilter

$objSearcher.SearchScope = "Subtree"

$colProplist = "name"

foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults)

    {$objItem = $objResult.Properties; $objItem.name}