Posts RSS Comments RSS 117 Posts and 170 Comments till now

Test-Host (WMI Ping -or Port Check)

I often find (specifically when using WMI) the need to ping the machine first before performing any queries. WMI takes FOREVER to timeout. I decided that I should use a script/function to test a host before passing it down the pipe.

There are a couple of problems with this approach that I had to consider.
1) How do I know what to test without corrupting the pipe or using foreach?
- For this I added a “-property” parameter that would allow the user to pick what property to check against, but still output the entire object that was inputted.

2) What about firewalls that block ping?
- Added TestPort function that does a TCP connect and returns $true or $false

3) What if I want a conditional port check.
- Added the ability to Change the Default Port for TCP Connection Test

Here is the script that I came up with and some of things it does.
Parameters
- $property: The Property to Ping or Test (Default is none.)
- $tport: The Port to test against (Default is 135. Used with -port)
- $timeout: The timeout for the connection (Default is 1000 ms, Used with -port)
- [switch]$port: Switch to Test a port instead of Ping
- [switch]$verbose: Provides Verbose Output.
Features
- Will Ping ‘$_’ by default
- Can pass the property that contains the Host to test using -property
- Can use -port to test a port instead of ping. (Uses TCP)
- Maintains the Object that is tested and passes it down the pipe if connection is passed.

A Demo of the script in action

Best Viewed Full Screen
Get the Flash Player to see this player.

Script CODE

  1. Param($property,$tport=135,$timeout=1000,[switch]$port,[switch]$verbose)
  2. Begin{
  3.     function TestPort {
  4.         Param($srv)
  5.         $error.Clear()
  6.         $ErrorActionPreference = "SilentlyContinue"
  7.         $tcpclient = new-Object system.Net.Sockets.TcpClient
  8.         $iar = $tcpclient.BeginConnect($srv,$tport,$null,$null)
  9.         $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
  10.         # Traps    
  11.         trap {if($verbose){Write-Host "General Exception"};return $false}
  12.         trap [System.Net.Sockets.SocketException]
  13.         {
  14.             if($verbose){Write-Host "Exception: $($_.exception.message)"}
  15.             return $false
  16.         }
  17.         if(!$wait)
  18.         {
  19.             $tcpclient.Close()
  20.             if($verbose){Write-Host "Connection Timeout"}
  21.             return $false
  22.         }
  23.         else
  24.         {
  25.             $tcpclient.EndConnect($iar) | out-Null
  26.             $tcpclient.Close()
  27.         }
  28.         if(!$error[0]){return $true}
  29.     }
  30.     function PingServer {
  31.         Param($MyHost)
  32.         $pingresult = Get-WmiObject win32_pingstatus -f "address=’$MyHost’"
  33.         if($pingresult.statuscode -eq 0) {$true} else {$false}
  34.     }
  35. }
  36. Process{
  37.     if($_)
  38.     {
  39.         if($port)
  40.         {
  41.             if($property)
  42.             {
  43.                 if(TestPort $_.$property){$_}  
  44.             }
  45.             else
  46.             {
  47.                 if(TestPort $_){$_}
  48.             }
  49.         }
  50.         else
  51.         {
  52.             if($property)
  53.             {
  54.                 if(PingServer $_.$property){$_}  
  55.             }
  56.             else
  57.             {
  58.                 if(PingServer $_){$_}
  59.             }
  60.         }
  61.     }
  62. }

If you want this as a function use this code

  1. function Test-Host{
  2. Param($property,$tport=135,$timeout=1000,[switch]$port,[switch]$verbose)
  3. Begin{
  4.     function TestPort {
  5.         Param($srv)
  6.         $error.Clear()
  7.         $ErrorActionPreference = "SilentlyContinue"
  8.         $tcpclient = new-Object system.Net.Sockets.TcpClient
  9.         $iar = $tcpclient.BeginConnect($srv,$tport,$null,$null)
  10.         $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
  11.         # Traps    
  12.         trap {if($verbose){Write-Host "General Exception"};return $false}
  13.         trap [System.Net.Sockets.SocketException]
  14.         {
  15.             if($verbose){Write-Host "Exception: $($_.exception.message)"}
  16.             return $false
  17.         }
  18.         if(!$wait)
  19.         {
  20.             $tcpclient.Close()
  21.             if($verbose){Write-Host "Connection Timeout"}
  22.             return $false
  23.         }
  24.         else
  25.         {
  26.             $tcpclient.EndConnect($iar) | out-Null
  27.             $tcpclient.Close()
  28.         }
  29.         if(!$error[0]){return $true}
  30.     }
  31.     function PingServer {
  32.         Param($MyHost)
  33.         $pingresult = Get-WmiObject win32_pingstatus -f "address=’$MyHost’"
  34.         if($pingresult.statuscode -eq 0) {$true} else {$false}
  35.     }
  36. }
  37. Process{
  38.     if($_)
  39.     {
  40.         if($port)
  41.         {
  42.             if($property)
  43.             {
  44.                 if(TestPort $_.$property){$_}  
  45.             }
  46.             else
  47.             {
  48.                 if(TestPort $_){$_}
  49.             }
  50.         }
  51.         else
  52.         {
  53.             if($property)
  54.             {
  55.                 if(PingServer $_.$property){$_}  
  56.             }
  57.             else
  58.             {
  59.                 if(PingServer $_){$_}
  60.             }
  61.         }
  62.     }
  63. }}

Get-CitrixPrinterInfo.ps1 (Citrix Top 10)

This script just collects the Printer Information from all the Servers in the Farm. It will output them to a file or you can pipe them and filter them.

Name: Get-CitrixPrinterInfo.ps1
Purpose: Gets Print Driver Info from all the Servers in the Farm and outputs to file or console

  1. # Get-CitrixPrinterInfo.ps1
  2. # Brandon Shell [MVP]
  3. # www.bsonposh.com
  4. # Gets Print Driver Info from all the Servers in the Farm
  5. Param($Server,$file,[Switch]$help)
  6. function HelpMe{
  7.     Write-Host
  8.     Write-Host " Get-CitrixPrinterInfo.ps1:" -fore Green
  9.     Write-Host "   Gets Print Driver Info from all the Servers in the Farm"
  10.     Write-Host
  11.     Write-Host " Parameters:" -fore Green
  12.     Write-Host "   -Server                : Optional. Server to Get Print Info From "
  13.     Write-Host "   -File                  : Optional. File Name to Export Info to"
  14.     Write-Host "   -Help                  : Optional. Displays This"
  15.     Write-Host
  16.     Write-Host " Examples:" -fore Green
  17.     Write-Host "   Gets Print Info and Exports to File" -fore White
  18.     Write-Host "     .\Get-CitrixPrinterInfo.ps1 -file MyExportFile.txt" -fore Yellow
  19.     Write-Host
  20.     Write-Host "   Gets Print Drivers from a Specific Server and outputs DriverName and SourceServer"  -fore White
  21.     Write-Host "     .\Get-CitrixPrinterInfo.ps1 <serverName> | ft DriverName,SourceServer" -fore Yellow
  22.     Write-Host
  23. }
  24.  
  25. # Check for Help Flag
  26. if($help){HelpMe;Write-Host;Return}
  27.  
  28. # Check for File
  29. if($file)
  30. {
  31.     if($server) # If -Server was passed we run check just against it and output to screen
  32.     {
  33.         $mfsrv = new-Object -com "MetaframeCOM.MetaframeServer"
  34.         $mfsrv.Initialize(6,$Server.ToUpper())
  35.         $mfsrv | foreach{"`n$($_.ServerName) `n$(’-'*20)";$_.PrinterDrivers| Format-Table} | out-File $file -enc ASCII
  36.     }
  37.     else # We run the check against the whole farm and output results to file
  38.     {
  39.         $mfarm = new-Object -com "MetaframeCOM.MetaframeFarm"
  40.         $mfarm.Initialize(1)
  41.         $mfarm.Servers | foreach{"`n$($_.ServerName) `n$(’-'*20)";$_.PrinterDrivers| Format-Table} | out-File $file -enc ASCII
  42.     }
  43. }
  44. else
  45. {
  46.     if($server) # If -Server was passed we run check just against it and output to screen
  47.     {
  48.         $mfsrv = new-Object -com "MetaframeCOM.MetaframeServer"
  49.         $mfsrv.Initialize(6,$Server.ToUpper())
  50.         $mfsrv | foreach{"`n$($_.ServerName) `n$(’-'*20)";$_.PrinterDrivers| Format-Table}
  51.     }
  52.     else # We run the check against the whole farm and output results to screen
  53.     {
  54.         $mfarm = new-Object -com "MetaframeCOM.MetaframeFarm"
  55.         $mfarm.Initialize(1)
  56.         $mfarm.Servers | foreach{"`n$($_.ServerName) `n$(’-'*20)";$_.PrinterDrivers| Format-Table}
  57.     }
  58.  }

How to Manage Multiple Citrix Farms

Chris left a comment on Powershelling Citrix (The Good, Bad, and The Code)

Here is a function that returns a farm object for Server that is passed.

  1. function Get-CitrixFarm {
  2.    Param([string]$server)
  3.    $type = [system.Type]::GetTypeFromProgID("MetaframeCOM.MetaFrameFarm",$server)
  4.    $farm = [system.Activator]::CreateInstance($type)
  5.    $farm.Initialize(1)
  6.    return $farm
  7. }
  8.  

Here is an example to find a Server that a User is on.

  1. function Find-CitrixUser {
  2.     Param([string]$user,[string]$server,[string]$domain,[switch]$verbose)
  3.     $type = [system.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeUser",$server)
  4.     $mfuser = [system.Activator]::CreateInstance($type)
  5.     $mfuser.Initialize(1,$domain,1,$user)
  6.     Write-Host
  7.     Write-Host "User: $($mfuser.UserName) found on the Following:"
  8.     foreach ($s in $mfuser.Sessions)
  9.     {
  10.         if($verbose)
  11.         {
  12.             Write-Host
  13.             Write-Host "$($s.ServerName)"
  14.             Write-Host "-=-=-=-=-=-"
  15.             Write-Host "AppName          : $($s.AppName)" -foregroundcolor yellow
  16.             Write-Host "SessionName      : $($s.SessionName)" -foregroundcolor yellow
  17.             Write-Host "SessionID        : $($s.SessionID)" -foregroundcolor yellow
  18.             Write-Host "ClientAddress    : $($s.ClientAddress)" -foregroundcolor yellow
  19.             Write-Host "ClientEncryption : $($s.ClientEncryption)" -foregroundcolor yellow
  20.             Write-Host
  21.             Write-Host "Processes"
  22.             Write-Host "========="
  23.             foreach ($proc in $s.Processes)
  24.             {
  25.                 Write-Host $proc.ProcessName -foregroundcolor Green
  26.             }
  27.             Write-host
  28.         }
  29.         else
  30.         {
  31.             write-Host "   -> $($s.ServerName)"
  32.         }
  33.     }
  34. }

Birth of a Script/Function

I know my post have been few and far between, but I have been super swamped at work and will be for a few more months at least.

That said I am writing some scripts and functions for work and as I was writing one today I though maybe I should share how I go about writing a function slash script. I like step-by-step lists so I decided at that format.

1> A purpose
- All Scripts must start with a purpose. Be it install something or check something. It needs to do something.

2> I figure the best process to do what I want
- Can what I want done be remoted?
- Do I use WMI?
- Do I use .NET?
- Do I use external Commands?
- Who is going to be doing it? What rights do they need?
- Does it have potential to break stuff (BIGGY!!!)

3> Write a function or functions that do what I want done on one Server, Device, or file
Example

  1. function Checkhf{
  2.    Param($srv,$ptch)
  3.    $hf = get-WmiObject Win32_QuickfixEngineering -ComputerName $srv | where-Object{$_.HotfixID -match $ptch}
  4.    if($hf)
  5.    {
  6.       return $true
  7.    }
  8.    else
  9.    {
  10.       return $false
  11.    }
  12. }

4> Cut and Paste function into my templates (At the bottom of post)
- Add any missing parameters
- Add any extra parsing
- Add error control if needed

5> Now it looks like this

  1. function Check-Hotfix {
  2.     Param([string]$server,[string]$hotfix)
  3.     Begin{
  4.         function PingServer {
  5.             param([string]$srv)
  6.             $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
  7.             if($pingresult.statuscode -eq 0) {$true} else {$false}
  8.         }
  9.         function Checkhf{
  10.             Param($srv,$ptch)
  11.             $hf = get-WmiObject Win32_QuickfixEngineering -ComputerName $srv | where-Object{$_.HotfixID -match $ptch}
  12.             if($hf)
  13.             {
  14.                 return $true
  15.             }
  16.             else
  17.             {
  18.                 return $false
  19.             }
  20.         }
  21.         Write-Host
  22.         $process = @()
  23.     }
  24.     Process{
  25.         if($_)
  26.         {
  27.             if($_.ServerName)
  28.             {
  29.                 $process += $_.ServerName
  30.             }
  31.             else
  32.             {
  33.                 $process += $_
  34.             }
  35.         }
  36.     }
  37.     End{
  38.         if($Server){$Process += $Server}
  39.         if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
  40.         foreach($s in $process)
  41.         {
  42.             if(PingServer $s)
  43.             {
  44.                 $myobj = "" | select-Object Server,Result
  45.                 $myobj.Server = $s
  46.                 $myobj.Result = Checkhf -srv $s -ptch $hotfix
  47.                 Write-Output $myObj
  48.             }
  49.         }
  50.     }
  51. }

6> Final Test

Here are my Templates
- By default they take a Pipe, Server, or File and will process all three

Template for Script

  1. Param([string]$server,[string]$file)
  2. Begin{
  3.     function PingServer {
  4.         param($srv)
  5.         $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
  6.         if($pingresult.statuscode -eq 0) {$true} else {$false}
  7.     }
  8.     function InsertFunctionHere{
  9.     }
  10.     Write-Host
  11.     $process = @()
  12. }
  13. Process{
  14.     if($_)
  15.     {
  16.         if($_.ServerName)
  17.         {
  18.             $process += $_.ServerName
  19.         }
  20.         else
  21.         {
  22.             $process += $_
  23.         }
  24.     }
  25. }
  26. End{
  27.     # Check if $server is populated and add to Process Array
  28.     if($Server){$Process += $Server}
  29.     # Check if $file is populated and add to Process Array
  30.     if($file)
  31.     {
  32.         foreach($entry in (get-content $file))
  33.         {
  34.             $Process += $entry
  35.         }
  36.     }
  37.     # If Process Array is empty… Add self
  38.     if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
  39.     foreach($s in $process)
  40.     {
  41.         if(pingserver $s)
  42.         {
  43.             InsertFunctionHere $s
  44.         }
  45.         Write-Host
  46.     }
  47. }

Template for Function

  1. function Verb-Noun {
  2.     Param([string]$server,[string]$file)
  3.     Begin{
  4.         function PingServer {
  5.             param($srv)
  6.             $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
  7.             if($pingresult.statuscode -eq 0) {$true} else {$false}
  8.         }
  9.         function InsertFunctionHere{
  10.         }
  11.         Write-Host
  12.         $process = @()
  13.     }
  14.     Process{
  15.         if($_)
  16.         {
  17.             if($_.ServerName)
  18.             {
  19.                 $process += $_.ServerName
  20.             }
  21.             else
  22.             {
  23.                 $process += $_
  24.             }
  25.         }
  26.     }
  27.     End{
  28.         # Check if $server is populated and add to Process Array
  29.         if($Server){$Process += $Server}
  30.         # Check if $file is populated and add to Process Array
  31.         if($file)
  32.         {
  33.             foreach($entry in (get-content $file))
  34.             {
  35.                 $Process += $entry
  36.             }
  37.         }
  38.         # If Process Array is empty… Add self
  39.         if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
  40.         foreach($s in $process)
  41.         {
  42.             if(pingserver $s)
  43.             {
  44.                 InsertFunctionHere $s
  45.             }
  46.             Write-Host
  47.         }
  48.     }
  49. }